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