1 /* $OpenBSD: mdstore.c,v 1.11 2019/07/07 14:45:15 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <assert.h> 20 #include <err.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <time.h> 25 26 #include "ds.h" 27 #include "mdesc.h" 28 #include "mdstore.h" 29 #include "util.h" 30 #include "ldomctl.h" 31 32 void mdstore_start(struct ldc_conn *, uint64_t); 33 void mdstore_start_v2(struct ldc_conn *, uint64_t); 34 void mdstore_start_v3(struct ldc_conn *, uint64_t); 35 void mdstore_rx_data(struct ldc_conn *, uint64_t, void *, size_t); 36 37 struct ds_service mdstore_service = { 38 "mdstore", 1, 0, mdstore_start, mdstore_rx_data 39 }; 40 41 struct ds_service mdstore_service_v2 = { 42 "mdstore", 2, 0, mdstore_start_v2, mdstore_rx_data 43 }; 44 45 struct ds_service mdstore_service_v3 = { 46 "mdstore", 3, 0, mdstore_start_v3, mdstore_rx_data 47 }; 48 49 #define MDSET_BEGIN_REQUEST 0x0001 50 #define MDSET_END_REQUEST 0x0002 51 #define MD_TRANSFER_REQUEST 0x0003 52 #define MDSET_LIST_REQUEST 0x0004 53 #define MDSET_SELECT_REQUEST 0x0005 54 #define MDSET_DELETE_REQUEST 0x0006 55 #define MDSET_RETREIVE_REQUEST 0x0007 56 57 struct mdstore_msg { 58 uint32_t msg_type; 59 uint32_t payload_len; 60 uint64_t svc_handle; 61 uint64_t reqnum; 62 uint16_t command; 63 uint8_t reserved[6]; 64 } __packed; 65 66 struct mdstore_begin_end_req { 67 uint32_t msg_type; 68 uint32_t payload_len; 69 uint64_t svc_handle; 70 uint64_t reqnum; 71 uint16_t command; 72 uint16_t nmds; 73 uint32_t namelen; 74 char name[1]; 75 } __packed; 76 77 struct mdstore_begin_req_v2 { 78 uint32_t msg_type; 79 uint32_t payload_len; 80 uint64_t svc_handle; 81 uint64_t reqnum; 82 uint16_t command; 83 uint16_t nmds; 84 uint32_t config_size; 85 uint64_t timestamp; 86 uint32_t namelen; 87 char name[1]; 88 } __packed; 89 90 struct mdstore_begin_req_v3 { 91 uint32_t msg_type; 92 uint32_t payload_len; 93 uint64_t svc_handle; 94 uint64_t reqnum; 95 uint16_t command; 96 uint16_t nmds; 97 uint32_t config_size; 98 uint64_t timestamp; 99 uint8_t degraded; 100 uint8_t active_config; 101 uint8_t reserved[2]; 102 uint32_t namelen; 103 char name[1]; 104 } __packed; 105 106 #define CONFIG_NORMAL 0x00 107 #define CONFIG_DEGRADED 0x01 108 109 #define CONFIG_EXISTING 0x00 110 #define CONFIG_ACTIVE 0x01 111 112 struct mdstore_transfer_req { 113 uint32_t msg_type; 114 uint32_t payload_len; 115 uint64_t svc_handle; 116 uint64_t reqnum; 117 uint16_t command; 118 uint16_t type; 119 uint32_t size; 120 uint64_t offset; 121 char md[]; 122 } __packed; 123 124 #define MDSTORE_PRI_TYPE 0x01 125 #define MDSTORE_HV_MD_TYPE 0x02 126 #define MDSTORE_CTL_DOM_MD_TYPE 0x04 127 #define MDSTORE_SVC_DOM_MD_TYPE 0x08 128 129 struct mdstore_sel_del_req { 130 uint32_t msg_type; 131 uint32_t payload_len; 132 uint64_t svc_handle; 133 uint64_t reqnum; 134 uint16_t command; 135 uint8_t reserved[2]; 136 uint32_t namelen; 137 char name[1]; 138 } __packed; 139 140 #define MDSET_LIST_REPLY 0x0104 141 142 struct mdstore_list_resp { 143 uint32_t msg_type; 144 uint32_t payload_len; 145 uint64_t svc_handle; 146 uint64_t reqnum; 147 uint32_t result; 148 uint16_t booted_set; 149 uint16_t boot_set; 150 char sets[1]; 151 } __packed; 152 153 #define MDST_SUCCESS 0x0 154 #define MDST_FAILURE 0x1 155 #define MDST_INVALID_MSG 0x2 156 #define MDST_MAX_MDS_ERR 0x3 157 #define MDST_BAD_NAME_ERR 0x4 158 #define MDST_SET_EXISTS_ERR 0x5 159 #define MDST_ALLOC_SET_ERR 0x6 160 #define MDST_ALLOC_MD_ERR 0x7 161 #define MDST_MD_COUNT_ERR 0x8 162 #define MDST_MD_SIZE_ERR 0x9 163 #define MDST_MD_TYPE_ERR 0xa 164 #define MDST_NOT_EXIST_ERR 0xb 165 166 struct mdstore_set_head mdstore_sets = TAILQ_HEAD_INITIALIZER(mdstore_sets); 167 uint64_t mdstore_reqnum; 168 uint64_t mdstore_command; 169 uint16_t mdstore_major; 170 171 void 172 mdstore_register(struct ds_conn *dc) 173 { 174 ds_conn_register_service(dc, &mdstore_service); 175 ds_conn_register_service(dc, &mdstore_service_v2); 176 ds_conn_register_service(dc, &mdstore_service_v3); 177 } 178 179 void 180 mdstore_start(struct ldc_conn *lc, uint64_t svc_handle) 181 { 182 struct mdstore_msg mm; 183 184 bzero(&mm, sizeof(mm)); 185 mm.msg_type = DS_DATA; 186 mm.payload_len = sizeof(mm) - 8; 187 mm.svc_handle = svc_handle; 188 mm.reqnum = mdstore_reqnum++; 189 mm.command = mdstore_command = MDSET_LIST_REQUEST; 190 ds_send_msg(lc, &mm, sizeof(mm)); 191 } 192 193 void 194 mdstore_start_v2(struct ldc_conn *lc, uint64_t svc_handle) 195 { 196 mdstore_major = 2; 197 mdstore_start(lc, svc_handle); 198 } 199 200 void 201 mdstore_start_v3(struct ldc_conn *lc, uint64_t svc_handle) 202 { 203 mdstore_major = 3; 204 mdstore_start(lc, svc_handle); 205 } 206 207 void 208 mdstore_rx_data(struct ldc_conn *lc, uint64_t svc_handle, void *data, 209 size_t len) 210 { 211 struct mdstore_list_resp *mr = data; 212 struct mdstore_set *set; 213 int idx; 214 215 if (mr->result != MDST_SUCCESS) { 216 switch (mr->result) { 217 case MDST_SET_EXISTS_ERR: 218 errx(1, "Configuration already exists"); 219 break; 220 case MDST_NOT_EXIST_ERR: 221 errx(1, "No such configuration"); 222 break; 223 default: 224 errx(1, "Unexpected result 0x%x\n", mr->result); 225 break; 226 } 227 } 228 229 switch (mdstore_command) { 230 case MDSET_LIST_REQUEST: 231 for (idx = 0, len = 0; len < mr->payload_len - 24; idx++) { 232 set = xmalloc(sizeof(*set)); 233 set->name = xstrdup(&mr->sets[len]); 234 set->booted_set = (idx == mr->booted_set); 235 set->boot_set = (idx == mr->boot_set); 236 TAILQ_INSERT_TAIL(&mdstore_sets, set, link); 237 len += strlen(&mr->sets[len]) + 1; 238 if (mdstore_major >= 2) 239 len += sizeof(uint64_t); /* skip timestamp */ 240 if (mdstore_major >= 3) 241 len += sizeof(uint8_t); /* skip has_degraded */ 242 } 243 break; 244 } 245 246 mdstore_command = 0; 247 } 248 249 void 250 mdstore_begin_v1(struct ds_conn *dc, uint64_t svc_handle, const char *name, 251 int nmds) 252 { 253 struct mdstore_begin_end_req *mr; 254 size_t len = sizeof(*mr) + strlen(name); 255 256 mr = xzalloc(len); 257 mr->msg_type = DS_DATA; 258 mr->payload_len = len - 8; 259 mr->svc_handle = svc_handle; 260 mr->reqnum = mdstore_reqnum++; 261 mr->command = mdstore_command = MDSET_BEGIN_REQUEST; 262 mr->nmds = nmds; 263 mr->namelen = strlen(name); 264 memcpy(mr->name, name, strlen(name)); 265 266 ds_send_msg(&dc->lc, mr, len); 267 free(mr); 268 269 while (mdstore_command == MDSET_BEGIN_REQUEST) 270 ds_conn_handle(dc); 271 } 272 273 void 274 mdstore_begin_v2(struct ds_conn *dc, uint64_t svc_handle, const char *name, 275 int nmds, uint32_t config_size) 276 { 277 struct mdstore_begin_req_v2 *mr; 278 size_t len = sizeof(*mr) + strlen(name); 279 280 mr = xzalloc(len); 281 mr->msg_type = DS_DATA; 282 mr->payload_len = len - 8; 283 mr->svc_handle = svc_handle; 284 mr->reqnum = mdstore_reqnum++; 285 mr->command = mdstore_command = MDSET_BEGIN_REQUEST; 286 mr->config_size = config_size; 287 mr->timestamp = time(NULL); 288 mr->nmds = nmds; 289 mr->namelen = strlen(name); 290 memcpy(mr->name, name, strlen(name)); 291 292 ds_send_msg(&dc->lc, mr, len); 293 free(mr); 294 295 while (mdstore_command == MDSET_BEGIN_REQUEST) 296 ds_conn_handle(dc); 297 } 298 299 void 300 mdstore_begin_v3(struct ds_conn *dc, uint64_t svc_handle, const char *name, 301 int nmds, uint32_t config_size) 302 { 303 struct mdstore_begin_req_v3 *mr; 304 size_t len = sizeof(*mr) + strlen(name); 305 306 mr = xzalloc(len); 307 mr->msg_type = DS_DATA; 308 mr->payload_len = len - 8; 309 mr->svc_handle = svc_handle; 310 mr->reqnum = mdstore_reqnum++; 311 mr->command = mdstore_command = MDSET_BEGIN_REQUEST; 312 mr->config_size = config_size; 313 mr->timestamp = time(NULL); 314 mr->degraded = CONFIG_NORMAL; 315 mr->active_config = CONFIG_EXISTING; 316 mr->nmds = nmds; 317 mr->namelen = strlen(name); 318 memcpy(mr->name, name, strlen(name)); 319 320 ds_send_msg(&dc->lc, mr, len); 321 free(mr); 322 323 while (mdstore_command == MDSET_BEGIN_REQUEST) 324 ds_conn_handle(dc); 325 } 326 327 void 328 mdstore_begin(struct ds_conn *dc, uint64_t svc_handle, const char *name, 329 int nmds, uint32_t config_size) 330 { 331 if (mdstore_major == 3) 332 mdstore_begin_v3(dc, svc_handle, name, nmds, config_size); 333 else if (mdstore_major == 2) 334 mdstore_begin_v2(dc, svc_handle, name, nmds, config_size); 335 else 336 mdstore_begin_v1(dc, svc_handle, name, nmds); 337 } 338 339 void 340 mdstore_transfer(struct ds_conn *dc, uint64_t svc_handle, const char *path, 341 uint16_t type, uint64_t offset) 342 { 343 struct mdstore_transfer_req *mr; 344 uint32_t size; 345 size_t len; 346 FILE *fp; 347 348 fp = fopen(path, "r"); 349 if (fp == NULL) 350 err(1, "fopen"); 351 352 fseek(fp, 0, SEEK_END); 353 size = ftell(fp); 354 fseek(fp, 0, SEEK_SET); 355 356 len = sizeof(*mr) + size; 357 mr = xzalloc(len); 358 359 mr->msg_type = DS_DATA; 360 mr->payload_len = len - 8; 361 mr->svc_handle = svc_handle; 362 mr->reqnum = mdstore_reqnum++; 363 mr->command = mdstore_command = MD_TRANSFER_REQUEST; 364 mr->type = type; 365 mr->size = size; 366 mr->offset = offset; 367 if (fread(&mr->md, size, 1, fp) != 1) 368 err(1, "fread"); 369 ds_send_msg(&dc->lc, mr, len); 370 free(mr); 371 372 fclose(fp); 373 374 while (mdstore_command == MD_TRANSFER_REQUEST) 375 ds_conn_handle(dc); 376 } 377 378 void 379 mdstore_end(struct ds_conn *dc, uint64_t svc_handle, const char *name, 380 int nmds) 381 { 382 struct mdstore_begin_end_req *mr; 383 size_t len = sizeof(*mr) + strlen(name); 384 385 mr = xzalloc(len); 386 mr->msg_type = DS_DATA; 387 mr->payload_len = len - 8; 388 mr->svc_handle = svc_handle; 389 mr->reqnum = mdstore_reqnum++; 390 mr->command = mdstore_command = MDSET_END_REQUEST; 391 mr->nmds = nmds; 392 mr->namelen = strlen(name); 393 memcpy(mr->name, name, strlen(name)); 394 395 ds_send_msg(&dc->lc, mr, len); 396 free(mr); 397 398 while (mdstore_command == MDSET_END_REQUEST) 399 ds_conn_handle(dc); 400 } 401 402 void 403 mdstore_select(struct ds_conn *dc, const char *name) 404 { 405 struct ds_conn_svc *dcs; 406 struct mdstore_sel_del_req *mr; 407 size_t len = sizeof(*mr) + strlen(name); 408 409 TAILQ_FOREACH(dcs, &dc->services, link) 410 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 && 411 dcs->svc_handle != 0) 412 break; 413 assert(dcs != NULL); 414 415 mr = xzalloc(len); 416 mr->msg_type = DS_DATA; 417 mr->payload_len = len - 8; 418 mr->svc_handle = dcs->svc_handle; 419 mr->reqnum = mdstore_reqnum++; 420 mr->command = mdstore_command = MDSET_SELECT_REQUEST; 421 mr->namelen = strlen(name); 422 memcpy(mr->name, name, strlen(name)); 423 424 ds_send_msg(&dc->lc, mr, len); 425 free(mr); 426 427 while (mdstore_command == MDSET_SELECT_REQUEST) 428 ds_conn_handle(dc); 429 } 430 431 void 432 mdstore_delete(struct ds_conn *dc, const char *name) 433 { 434 struct ds_conn_svc *dcs; 435 struct mdstore_sel_del_req *mr; 436 size_t len = sizeof(*mr) + strlen(name); 437 438 TAILQ_FOREACH(dcs, &dc->services, link) 439 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 && 440 dcs->svc_handle != 0) 441 break; 442 assert(dcs != NULL); 443 444 mr = xzalloc(len); 445 mr->msg_type = DS_DATA; 446 mr->payload_len = len - 8; 447 mr->svc_handle = dcs->svc_handle; 448 mr->reqnum = mdstore_reqnum++; 449 mr->command = mdstore_command = MDSET_DELETE_REQUEST; 450 mr->namelen = strlen(name); 451 memcpy(mr->name, name, strlen(name)); 452 453 ds_send_msg(&dc->lc, mr, len); 454 free(mr); 455 456 while (mdstore_command == MDSET_DELETE_REQUEST) 457 ds_conn_handle(dc); 458 } 459 460 void frag_init(void); 461 void add_frag_mblock(struct md_node *); 462 void add_frag(uint64_t); 463 void delete_frag(uint64_t); 464 uint64_t alloc_frag(void); 465 466 void 467 mdstore_download(struct ds_conn *dc, const char *name) 468 { 469 struct ds_conn_svc *dcs; 470 struct md_node *node; 471 struct md_prop *prop; 472 struct guest *guest; 473 int nmds = 2; 474 char *path; 475 uint32_t total_size = 0; 476 uint16_t type; 477 478 TAILQ_FOREACH(dcs, &dc->services, link) 479 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 && 480 dcs->svc_handle != 0) 481 break; 482 assert(dcs != NULL); 483 484 if (asprintf(&path, "%s/hv.md", name) == -1) 485 err(1, "asprintf"); 486 hvmd = md_read(path); 487 free(path); 488 489 if (hvmd == NULL) 490 err(1, "%s", name); 491 492 node = md_find_node(hvmd, "guests"); 493 TAILQ_INIT(&guest_list); 494 TAILQ_FOREACH(prop, &node->prop_list, link) { 495 if (prop->tag == MD_PROP_ARC && 496 strcmp(prop->name->str, "fwd") == 0) { 497 add_guest(prop->d.arc.node); 498 nmds++; 499 } 500 } 501 502 frag_init(); 503 hv_mdpa = alloc_frag(); 504 505 TAILQ_FOREACH(guest, &guest_list, link) { 506 if (asprintf(&path, "%s/%s.md", name, guest->name) == -1) 507 err(1, "asprintf"); 508 total_size += md_size(path); 509 } 510 if (asprintf(&path, "%s/hv.md", name) == -1) 511 err(1, "asprintf"); 512 total_size += md_size(path); 513 if (asprintf(&path, "%s/pri", name) == -1) 514 err(1, "asprintf"); 515 total_size += md_size(path); 516 517 mdstore_begin(dc, dcs->svc_handle, name, nmds, total_size); 518 TAILQ_FOREACH(guest, &guest_list, link) { 519 if (asprintf(&path, "%s/%s.md", name, guest->name) == -1) 520 err(1, "asprintf"); 521 type = 0; 522 if (strcmp(guest->name, "primary") == 0) 523 type = MDSTORE_CTL_DOM_MD_TYPE; 524 mdstore_transfer(dc, dcs->svc_handle, path, type, guest->mdpa); 525 free(path); 526 } 527 if (asprintf(&path, "%s/hv.md", name) == -1) 528 err(1, "asprintf"); 529 mdstore_transfer(dc, dcs->svc_handle, path, 530 MDSTORE_HV_MD_TYPE, hv_mdpa); 531 free(path); 532 if (asprintf(&path, "%s/pri", name) == -1) 533 err(1, "asprintf"); 534 mdstore_transfer(dc, dcs->svc_handle, path, 535 MDSTORE_PRI_TYPE, 0); 536 free(path); 537 mdstore_end(dc, dcs->svc_handle, name, nmds); 538 } 539 540 struct frag { 541 TAILQ_ENTRY(frag) link; 542 uint64_t base; 543 }; 544 545 TAILQ_HEAD(frag_head, frag) free_frags; 546 547 uint64_t fragsize; 548 549 void 550 frag_init(void) 551 { 552 struct md_node *node; 553 struct md_prop *prop; 554 555 node = md_find_node(hvmd, "frag_space"); 556 md_get_prop_val(hvmd, node, "fragsize", &fragsize); 557 TAILQ_INIT(&free_frags); 558 TAILQ_FOREACH(prop, &node->prop_list, link) { 559 if (prop->tag == MD_PROP_ARC && 560 strcmp(prop->name->str, "fwd") == 0) 561 add_frag_mblock(prop->d.arc.node); 562 } 563 } 564 565 void 566 add_frag_mblock(struct md_node *node) 567 { 568 uint64_t base, size; 569 struct guest *guest; 570 571 md_get_prop_val(hvmd, node, "base", &base); 572 md_get_prop_val(hvmd, node, "size", &size); 573 while (size > fragsize) { 574 add_frag(base); 575 size -= fragsize; 576 base += fragsize; 577 } 578 579 delete_frag(hv_mdpa); 580 TAILQ_FOREACH(guest, &guest_list, link) 581 delete_frag(guest->mdpa); 582 } 583 584 void 585 add_frag(uint64_t base) 586 { 587 struct frag *frag; 588 589 frag = xmalloc(sizeof(*frag)); 590 frag->base = base; 591 TAILQ_INSERT_TAIL(&free_frags, frag, link); 592 } 593 594 void 595 delete_frag(uint64_t base) 596 { 597 struct frag *frag; 598 struct frag *tmp; 599 600 TAILQ_FOREACH_SAFE(frag, &free_frags, link, tmp) { 601 if (frag->base == base) { 602 TAILQ_REMOVE(&free_frags, frag, link); 603 free(frag); 604 } 605 } 606 } 607 608 uint64_t 609 alloc_frag(void) 610 { 611 struct frag *frag; 612 uint64_t base; 613 614 frag = TAILQ_FIRST(&free_frags); 615 if (frag == NULL) 616 return -1; 617 618 TAILQ_REMOVE(&free_frags, frag, link); 619 base = frag->base; 620 free(frag); 621 622 return base; 623 } 624