1 /* $OpenBSD: mdstore.c,v 1.14 2021/02/01 16:27:06 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 "ldom_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
mdstore_register(struct ds_conn * dc)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
mdstore_start(struct ldc_conn * lc,uint64_t svc_handle)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
mdstore_start_v2(struct ldc_conn * lc,uint64_t svc_handle)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
mdstore_start_v3(struct ldc_conn * lc,uint64_t svc_handle)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
mdstore_rx_data(struct ldc_conn * lc,uint64_t svc_handle,void * data,size_t len)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
mdstore_begin_v1(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds)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
mdstore_begin_v2(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)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
mdstore_begin_v3(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)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
mdstore_begin(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)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
mdstore_transfer(struct ds_conn * dc,uint64_t svc_handle,const char * path,uint16_t type,uint64_t offset)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
mdstore_end(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds)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
mdstore_select(struct ds_conn * dc,const char * name)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
mdstore_delete(struct ds_conn * dc,const char * name)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
mdstore_download(struct ds_conn * dc,const char * name)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) mdstore_frags;
546
547 uint64_t mdstore_fragsize;
548
549 void
frag_init(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", &mdstore_fragsize);
557 TAILQ_INIT(&mdstore_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
add_frag_mblock(struct md_node * node)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 > mdstore_fragsize) {
574 add_frag(base);
575 size -= mdstore_fragsize;
576 base += mdstore_fragsize;
577 }
578
579 delete_frag(hv_mdpa);
580 TAILQ_FOREACH(guest, &guest_list, link)
581 delete_frag(guest->mdpa);
582 }
583
584 void
add_frag(uint64_t base)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(&mdstore_frags, frag, link);
592 }
593
594 void
delete_frag(uint64_t base)595 delete_frag(uint64_t base)
596 {
597 struct frag *frag;
598 struct frag *tmp;
599
600 TAILQ_FOREACH_SAFE(frag, &mdstore_frags, link, tmp) {
601 if (frag->base == base) {
602 TAILQ_REMOVE(&mdstore_frags, frag, link);
603 free(frag);
604 }
605 }
606 }
607
608 uint64_t
alloc_frag(void)609 alloc_frag(void)
610 {
611 struct frag *frag;
612 uint64_t base;
613
614 frag = TAILQ_FIRST(&mdstore_frags);
615 if (frag == NULL)
616 return -1;
617
618 TAILQ_REMOVE(&mdstore_frags, frag, link);
619 base = frag->base;
620 free(frag);
621
622 return base;
623 }
624