1 /* $OpenBSD: mdstore.c,v 1.7 2014/09/13 16:06:37 doug 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 25 #include "ds.h" 26 #include "mdesc.h" 27 #include "mdstore.h" 28 #include "util.h" 29 #include "ldomctl.h" 30 31 void mdstore_start(struct ldc_conn *, uint64_t); 32 void mdstore_rx_data(struct ldc_conn *, uint64_t, void *, size_t); 33 34 struct ds_service mdstore_service = { 35 "mdstore", 1, 0, mdstore_start, mdstore_rx_data 36 }; 37 38 #define MDSET_BEGIN_REQUEST 0x0001 39 #define MDSET_END_REQUEST 0x0002 40 #define MD_TRANSFER_REQUEST 0x0003 41 #define MDSET_LIST_REQUEST 0x0004 42 #define MDSET_SELECT_REQUEST 0x0005 43 #define MDSET_DELETE_REQUEST 0x0006 44 #define MDSET_RETREIVE_REQUEST 0x0007 45 46 struct mdstore_msg { 47 uint32_t msg_type; 48 uint32_t payload_len; 49 uint64_t svc_handle; 50 uint64_t reqnum; 51 uint16_t command; 52 } __packed; 53 54 struct mdstore_begin_end_req { 55 uint32_t msg_type; 56 uint32_t payload_len; 57 uint64_t svc_handle; 58 uint64_t reqnum; 59 uint16_t command; 60 uint16_t nmds; 61 uint32_t namelen; 62 char name[1]; 63 } __packed; 64 65 struct mdstore_transfer_req { 66 uint32_t msg_type; 67 uint32_t payload_len; 68 uint64_t svc_handle; 69 uint64_t reqnum; 70 uint16_t command; 71 uint16_t type; 72 uint32_t size; 73 uint64_t offset; 74 char md[]; 75 } __packed; 76 77 #define MDSTORE_PRI_TYPE 0x01 78 #define MDSTORE_HV_MD_TYPE 0x02 79 #define MDSTORE_CTL_DOM_MD_TYPE 0x04 80 #define MDSTORE_SVC_DOM_MD_TYPE 0x08 81 82 struct mdstore_sel_del_req { 83 uint32_t msg_type; 84 uint32_t payload_len; 85 uint64_t svc_handle; 86 uint64_t reqnum; 87 uint16_t command; 88 uint16_t reserved; 89 uint32_t namelen; 90 char name[1]; 91 } __packed; 92 93 #define MDSET_LIST_REPLY 0x0104 94 95 struct mdstore_list_resp { 96 uint32_t msg_type; 97 uint32_t payload_len; 98 uint64_t svc_handle; 99 uint64_t reqnum; 100 uint32_t result; 101 uint16_t booted_set; 102 uint16_t boot_set; 103 char sets[1]; 104 } __packed; 105 106 #define MDST_SUCCESS 0x0 107 #define MDST_FAILURE 0x1 108 #define MDST_INVALID_MSG 0x2 109 #define MDST_MAX_MDS_ERR 0x3 110 #define MDST_BAD_NAME_ERR 0x4 111 #define MDST_SET_EXISTS_ERR 0x5 112 #define MDST_ALLOC_SET_ERR 0x6 113 #define MDST_ALLOC_MD_ERR 0x7 114 #define MDST_MD_COUNT_ERR 0x8 115 #define MDST_MD_SIZE_ERR 0x9 116 #define MDST_MD_TYPE_ERR 0xa 117 #define MDST_NOT_EXIST_ERR 0xb 118 119 struct mdstore_set_head mdstore_sets = TAILQ_HEAD_INITIALIZER(mdstore_sets); 120 uint64_t mdstore_reqnum; 121 uint64_t mdstore_command; 122 123 void 124 mdstore_start(struct ldc_conn *lc, uint64_t svc_handle) 125 { 126 struct mdstore_msg mm; 127 128 bzero(&mm, sizeof(mm)); 129 mm.msg_type = DS_DATA; 130 mm.payload_len = sizeof(mm) - 8; 131 mm.svc_handle = svc_handle; 132 mm.reqnum = mdstore_reqnum++; 133 mm.command = mdstore_command = MDSET_LIST_REQUEST; 134 ds_send_msg(lc, &mm, sizeof(mm)); 135 } 136 137 void 138 mdstore_rx_data(struct ldc_conn *lc, uint64_t svc_handle, void *data, 139 size_t len) 140 { 141 struct mdstore_list_resp *mr = data; 142 struct mdstore_set *set; 143 int idx; 144 145 if (mr->result != MDST_SUCCESS) { 146 switch (mr->result) { 147 case MDST_SET_EXISTS_ERR: 148 errx(1, "Configuration already exists"); 149 break; 150 case MDST_NOT_EXIST_ERR: 151 errx(1, "No such configuration"); 152 break; 153 default: 154 errx(1, "Unexpected result 0x%x\n", mr->result); 155 break; 156 } 157 } 158 159 switch (mdstore_command) { 160 case MDSET_LIST_REQUEST: 161 for (idx = 0, len = 0; len < mr->payload_len - 24; idx++) { 162 set = xmalloc(sizeof(*set)); 163 set->name = xstrdup(&mr->sets[len]); 164 set->booted_set = (idx == mr->booted_set); 165 set->boot_set = (idx == mr->boot_set); 166 TAILQ_INSERT_TAIL(&mdstore_sets, set, link); 167 len += strlen(&mr->sets[len]) + 1; 168 } 169 break; 170 } 171 172 mdstore_command = 0; 173 } 174 175 void 176 mdstore_begin(struct ds_conn *dc, uint64_t svc_handle, const char *name, 177 int nmds) 178 { 179 struct mdstore_begin_end_req *mr; 180 size_t len = sizeof(*mr) + strlen(name); 181 182 mr = xzalloc(len); 183 mr->msg_type = DS_DATA; 184 mr->payload_len = len - 8; 185 mr->svc_handle = svc_handle; 186 mr->reqnum = mdstore_reqnum++; 187 mr->command = mdstore_command = MDSET_BEGIN_REQUEST; 188 mr->nmds = nmds; 189 mr->namelen = strlen(name); 190 memcpy(mr->name, name, strlen(name)); 191 192 ds_send_msg(&dc->lc, mr, len); 193 free(mr); 194 195 while (mdstore_command == MDSET_BEGIN_REQUEST) 196 ds_conn_handle(dc); 197 } 198 199 void 200 mdstore_transfer(struct ds_conn *dc, uint64_t svc_handle, const char *path, 201 uint16_t type, uint64_t offset) 202 { 203 struct mdstore_transfer_req *mr; 204 uint32_t size; 205 size_t len; 206 FILE *fp; 207 208 fp = fopen(path, "r"); 209 if (fp == NULL) 210 err(1, "fopen"); 211 212 fseek(fp, 0, SEEK_END); 213 size = ftell(fp); 214 fseek(fp, 0, SEEK_SET); 215 216 len = sizeof(*mr) + size; 217 mr = xzalloc(len); 218 219 mr->msg_type = DS_DATA; 220 mr->payload_len = len - 8; 221 mr->svc_handle = svc_handle; 222 mr->reqnum = mdstore_reqnum++; 223 mr->command = mdstore_command = MD_TRANSFER_REQUEST; 224 mr->type = type; 225 mr->size = size; 226 mr->offset = offset; 227 if (fread(&mr->md, size, 1, fp) != 1) 228 err(1, "fread"); 229 ds_send_msg(&dc->lc, mr, len); 230 free(mr); 231 232 fclose(fp); 233 234 while (mdstore_command == MD_TRANSFER_REQUEST) 235 ds_conn_handle(dc); 236 } 237 238 void 239 mdstore_end(struct ds_conn *dc, uint64_t svc_handle, const char *name, 240 int nmds) 241 { 242 struct mdstore_begin_end_req *mr; 243 size_t len = sizeof(*mr) + strlen(name); 244 245 mr = xzalloc(len); 246 mr->msg_type = DS_DATA; 247 mr->payload_len = len - 8; 248 mr->svc_handle = svc_handle; 249 mr->reqnum = mdstore_reqnum++; 250 mr->command = mdstore_command = MDSET_END_REQUEST; 251 mr->nmds = nmds; 252 mr->namelen = strlen(name); 253 memcpy(mr->name, name, strlen(name)); 254 255 ds_send_msg(&dc->lc, mr, len); 256 free(mr); 257 258 while (mdstore_command == MDSET_END_REQUEST) 259 ds_conn_handle(dc); 260 } 261 262 void 263 mdstore_select(struct ds_conn *dc, const char *name) 264 { 265 struct ds_conn_svc *dcs; 266 struct mdstore_sel_del_req *mr; 267 size_t len = sizeof(*mr) + strlen(name); 268 269 TAILQ_FOREACH(dcs, &dc->services, link) 270 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0) 271 break; 272 assert(dcs != NULL); 273 274 mr = xzalloc(len); 275 mr->msg_type = DS_DATA; 276 mr->payload_len = len - 8; 277 mr->svc_handle = dcs->svc_handle; 278 mr->reqnum = mdstore_reqnum++; 279 mr->command = mdstore_command = MDSET_SELECT_REQUEST; 280 mr->namelen = strlen(name); 281 memcpy(mr->name, name, strlen(name)); 282 283 ds_send_msg(&dc->lc, mr, len); 284 free(mr); 285 286 while (mdstore_command == MDSET_SELECT_REQUEST) 287 ds_conn_handle(dc); 288 } 289 290 void 291 mdstore_delete(struct ds_conn *dc, const char *name) 292 { 293 struct ds_conn_svc *dcs; 294 struct mdstore_sel_del_req *mr; 295 size_t len = sizeof(*mr) + strlen(name); 296 297 TAILQ_FOREACH(dcs, &dc->services, link) 298 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0) 299 break; 300 assert(dcs != NULL); 301 302 mr = xzalloc(len); 303 mr->msg_type = DS_DATA; 304 mr->payload_len = len - 8; 305 mr->svc_handle = dcs->svc_handle; 306 mr->reqnum = mdstore_reqnum++; 307 mr->command = mdstore_command = MDSET_DELETE_REQUEST; 308 mr->namelen = strlen(name); 309 memcpy(mr->name, name, strlen(name)); 310 311 ds_send_msg(&dc->lc, mr, len); 312 free(mr); 313 314 while (mdstore_command == MDSET_DELETE_REQUEST) 315 ds_conn_handle(dc); 316 } 317 318 void frag_init(void); 319 void add_frag_mblock(struct md_node *); 320 void add_frag(uint64_t); 321 void delete_frag(uint64_t); 322 uint64_t alloc_frag(void); 323 324 void 325 mdstore_download(struct ds_conn *dc, const char *name) 326 { 327 struct ds_conn_svc *dcs; 328 struct md_node *node; 329 struct md_prop *prop; 330 struct guest *guest; 331 int nmds = 2; 332 char *path; 333 uint16_t type; 334 335 TAILQ_FOREACH(dcs, &dc->services, link) 336 if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0) 337 break; 338 assert(dcs != NULL); 339 340 if (asprintf(&path, "%s/hv.md", name) == -1) 341 err(1, "asprintf"); 342 hvmd = md_read(path); 343 free(path); 344 345 if (hvmd == NULL) 346 err(1, "%s", name); 347 348 node = md_find_node(hvmd, "guests"); 349 TAILQ_INIT(&guest_list); 350 TAILQ_FOREACH(prop, &node->prop_list, link) { 351 if (prop->tag == MD_PROP_ARC && 352 strcmp(prop->name->str, "fwd") == 0) { 353 add_guest(prop->d.arc.node); 354 nmds++; 355 } 356 } 357 358 frag_init(); 359 hv_mdpa = alloc_frag(); 360 361 mdstore_begin(dc, dcs->svc_handle, name, nmds); 362 TAILQ_FOREACH(guest, &guest_list, link) { 363 if (asprintf(&path, "%s/%s.md", name, guest->name) == -1) 364 err(1, "asprintf"); 365 type = 0; 366 if (strcmp(guest->name, "primary") == 0) 367 type = MDSTORE_CTL_DOM_MD_TYPE; 368 mdstore_transfer(dc, dcs->svc_handle, path, type, guest->mdpa); 369 free(path); 370 } 371 if (asprintf(&path, "%s/hv.md", name) == -1) 372 err(1, "asprintf"); 373 mdstore_transfer(dc, dcs->svc_handle, path, 374 MDSTORE_HV_MD_TYPE, hv_mdpa); 375 free(path); 376 if (asprintf(&path, "%s/pri", name) == -1) 377 err(1, "asprintf"); 378 mdstore_transfer(dc, dcs->svc_handle, path, 379 MDSTORE_PRI_TYPE, 0); 380 free(path); 381 mdstore_end(dc, dcs->svc_handle, name, nmds); 382 } 383 384 struct frag { 385 TAILQ_ENTRY(frag) link; 386 uint64_t base; 387 }; 388 389 TAILQ_HEAD(frag_head, frag) free_frags; 390 391 uint64_t fragsize; 392 393 void 394 frag_init(void) 395 { 396 struct md_node *node; 397 struct md_prop *prop; 398 399 node = md_find_node(hvmd, "frag_space"); 400 md_get_prop_val(hvmd, node, "fragsize", &fragsize); 401 TAILQ_INIT(&free_frags); 402 TAILQ_FOREACH(prop, &node->prop_list, link) { 403 if (prop->tag == MD_PROP_ARC && 404 strcmp(prop->name->str, "fwd") == 0) 405 add_frag_mblock(prop->d.arc.node); 406 } 407 } 408 409 void 410 add_frag_mblock(struct md_node *node) 411 { 412 uint64_t base, size; 413 struct guest *guest; 414 415 md_get_prop_val(hvmd, node, "base", &base); 416 md_get_prop_val(hvmd, node, "size", &size); 417 while (size > fragsize) { 418 add_frag(base); 419 size -= fragsize; 420 base += fragsize; 421 } 422 423 delete_frag(hv_mdpa); 424 TAILQ_FOREACH(guest, &guest_list, link) 425 delete_frag(guest->mdpa); 426 } 427 428 void 429 add_frag(uint64_t base) 430 { 431 struct frag *frag; 432 433 frag = xmalloc(sizeof(*frag)); 434 frag->base = base; 435 TAILQ_INSERT_TAIL(&free_frags, frag, link); 436 } 437 438 void 439 delete_frag(uint64_t base) 440 { 441 struct frag *frag; 442 struct frag *tmp; 443 444 TAILQ_FOREACH_SAFE(frag, &free_frags, link, tmp) { 445 if (frag->base == base) { 446 TAILQ_REMOVE(&free_frags, frag, link); 447 free(frag); 448 } 449 } 450 } 451 452 uint64_t 453 alloc_frag(void) 454 { 455 struct frag *frag; 456 uint64_t base; 457 458 frag = TAILQ_FIRST(&free_frags); 459 if (frag == NULL) 460 return -1; 461 462 TAILQ_REMOVE(&free_frags, frag, link); 463 base = frag->base; 464 free(frag); 465 466 return base; 467 } 468