xref: /openbsd-src/usr.sbin/ldomctl/mdstore.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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