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