xref: /openbsd/usr.sbin/ldomctl/mdstore.c (revision bb93e559)
1*bb93e559Skettenis /*	$OpenBSD: mdstore.c,v 1.4 2012/11/05 19:50:54 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>
24cceaa36bSkettenis 
25cceaa36bSkettenis #include "ds.h"
26*bb93e559Skettenis #include "mdesc.h"
27cceaa36bSkettenis #include "mdstore.h"
28cceaa36bSkettenis #include "util.h"
29*bb93e559Skettenis #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) {
146cceaa36bSkettenis 		DPRINTF(("Unexpected result 0x%x\n", mr->result));
147cceaa36bSkettenis 		return;
148cceaa36bSkettenis 	}
149cceaa36bSkettenis 
1506aace0ceSkettenis 	switch (mdstore_command) {
1516aace0ceSkettenis 	case MDSET_LIST_REQUEST:
1526aace0ceSkettenis 		for (idx = 0, len = 0; len < mr->payload_len - 24; idx++) {
153cceaa36bSkettenis 			set = xmalloc(sizeof(*set));
154cceaa36bSkettenis 			set->name = xstrdup(&mr->sets[len]);
155cceaa36bSkettenis 			set->booted_set = (idx == mr->booted_set);
156cceaa36bSkettenis 			set->boot_set = (idx == mr->boot_set);
157cceaa36bSkettenis 			TAILQ_INSERT_TAIL(&mdstore_sets, set, link);
158cceaa36bSkettenis 			len += strlen(&mr->sets[len]) + 1;
159cceaa36bSkettenis 		}
1606aace0ceSkettenis 		break;
1616aace0ceSkettenis 	}
162dc8fdf3dSkettenis 
163dc8fdf3dSkettenis 	mdstore_command = 0;
164dc8fdf3dSkettenis }
165dc8fdf3dSkettenis 
166dc8fdf3dSkettenis void
167*bb93e559Skettenis mdstore_begin(struct ds_conn *dc, uint64_t svc_handle, const char *name,
168*bb93e559Skettenis     int nmds)
169dc8fdf3dSkettenis {
170dc8fdf3dSkettenis 	struct mdstore_begin_end_req *mr;
171dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
172dc8fdf3dSkettenis 
173dc8fdf3dSkettenis 	mr = xzalloc(len);
174dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
175dc8fdf3dSkettenis 	mr->payload_len = len - 8;
176dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
177dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
178dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
179*bb93e559Skettenis 	mr->nmds = nmds;
180dc8fdf3dSkettenis 	mr->namelen = strlen(name);
181dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
182dc8fdf3dSkettenis 
183dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
184dc8fdf3dSkettenis 	free(mr);
185dc8fdf3dSkettenis 
186dc8fdf3dSkettenis 	while (mdstore_command == MDSET_BEGIN_REQUEST)
187dc8fdf3dSkettenis 		ds_conn_handle(dc);
188dc8fdf3dSkettenis }
189dc8fdf3dSkettenis 
190dc8fdf3dSkettenis void
191dc8fdf3dSkettenis mdstore_transfer(struct ds_conn *dc, uint64_t svc_handle, const char *path,
192dc8fdf3dSkettenis     uint16_t type, uint64_t offset)
193dc8fdf3dSkettenis {
194dc8fdf3dSkettenis 	struct mdstore_transfer_req *mr;
195dc8fdf3dSkettenis 	uint32_t size;
196dc8fdf3dSkettenis 	size_t len;
197dc8fdf3dSkettenis 	FILE *fp;
198dc8fdf3dSkettenis 
199dc8fdf3dSkettenis 	fp = fopen(path, "r");
200dc8fdf3dSkettenis 	if (fp == NULL)
201dc8fdf3dSkettenis 		err(1, "fopen");
202dc8fdf3dSkettenis 
203dc8fdf3dSkettenis 	fseek(fp, 0, SEEK_END);
204dc8fdf3dSkettenis 	size = ftell(fp);
205dc8fdf3dSkettenis 	fseek(fp, 0, SEEK_SET);
206dc8fdf3dSkettenis 
207dc8fdf3dSkettenis 	len = sizeof(*mr) + size;
208dc8fdf3dSkettenis 	mr = xzalloc(len);
209dc8fdf3dSkettenis 
210dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
211dc8fdf3dSkettenis 	mr->payload_len = len - 8;
212dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
213dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
214dc8fdf3dSkettenis 	mr->command = mdstore_command = MD_TRANSFER_REQUEST;
215dc8fdf3dSkettenis 	mr->type = type;
216dc8fdf3dSkettenis 	mr->size = size;
217dc8fdf3dSkettenis 	mr->offset = offset;
218dc8fdf3dSkettenis 	if (fread(&mr->md, size, 1, fp) != 1)
219dc8fdf3dSkettenis 		err(1, "fread");
220dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
221dc8fdf3dSkettenis 	free(mr);
222dc8fdf3dSkettenis 
223dc8fdf3dSkettenis 	fclose(fp);
224dc8fdf3dSkettenis 
225dc8fdf3dSkettenis 	while (mdstore_command == MD_TRANSFER_REQUEST)
226dc8fdf3dSkettenis 		ds_conn_handle(dc);
227dc8fdf3dSkettenis }
228dc8fdf3dSkettenis 
229dc8fdf3dSkettenis void
230*bb93e559Skettenis mdstore_end(struct ds_conn *dc, uint64_t svc_handle, const char *name,
231*bb93e559Skettenis     int nmds)
232dc8fdf3dSkettenis {
233dc8fdf3dSkettenis 	struct mdstore_begin_end_req *mr;
234dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
235dc8fdf3dSkettenis 
236dc8fdf3dSkettenis 	mr = xzalloc(len);
237dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
238dc8fdf3dSkettenis 	mr->payload_len = len - 8;
239dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
240dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
241dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_END_REQUEST;
242*bb93e559Skettenis 	mr->nmds = nmds;
243dc8fdf3dSkettenis 	mr->namelen = strlen(name);
244dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
245dc8fdf3dSkettenis 
246dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
247dc8fdf3dSkettenis 	free(mr);
248dc8fdf3dSkettenis 
249dc8fdf3dSkettenis 	while (mdstore_command == MDSET_END_REQUEST)
250dc8fdf3dSkettenis 		ds_conn_handle(dc);
2516aace0ceSkettenis }
2526aace0ceSkettenis 
2536aace0ceSkettenis void
2546aace0ceSkettenis mdstore_select(struct ds_conn *dc, const char *name)
2556aace0ceSkettenis {
2566aace0ceSkettenis 	struct ds_conn_svc *dcs;
2576aace0ceSkettenis 	struct mdstore_sel_del_req *mr;
258dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
2596aace0ceSkettenis 
2606aace0ceSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
2616aace0ceSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0)
2626aace0ceSkettenis 			break;
2636aace0ceSkettenis 	assert(dcs != TAILQ_END(&dc->services));
2646aace0ceSkettenis 
2656aace0ceSkettenis 	mr = xzalloc(len);
2666aace0ceSkettenis 	mr->msg_type = DS_DATA;
2676aace0ceSkettenis 	mr->payload_len = len - 8;
2686aace0ceSkettenis 	mr->svc_handle = dcs->svc_handle;
2696aace0ceSkettenis 	mr->reqnum = mdstore_reqnum++;
2706aace0ceSkettenis 	mr->command = mdstore_command = MDSET_SELECT_REQUEST;
2716aace0ceSkettenis 	mr->namelen = strlen(name);
2726aace0ceSkettenis 	memcpy(mr->name, name, strlen(name));
2736aace0ceSkettenis 
2746aace0ceSkettenis 	ds_send_msg(&dc->lc, mr, len);
2756aace0ceSkettenis 	free(mr);
2766aace0ceSkettenis 
2776aace0ceSkettenis 	while (mdstore_command == MDSET_SELECT_REQUEST)
2786aace0ceSkettenis 		ds_conn_handle(dc);
279cceaa36bSkettenis }
280dc8fdf3dSkettenis 
281dc8fdf3dSkettenis void
282dc8fdf3dSkettenis mdstore_delete(struct ds_conn *dc, const char *name)
283dc8fdf3dSkettenis {
284dc8fdf3dSkettenis 	struct ds_conn_svc *dcs;
285dc8fdf3dSkettenis 	struct mdstore_sel_del_req *mr;
286dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
287dc8fdf3dSkettenis 
288dc8fdf3dSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
289dc8fdf3dSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0)
290dc8fdf3dSkettenis 			break;
291dc8fdf3dSkettenis 	assert(dcs != TAILQ_END(&dc->services));
292dc8fdf3dSkettenis 
293dc8fdf3dSkettenis 	mr = xzalloc(len);
294dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
295dc8fdf3dSkettenis 	mr->payload_len = len - 8;
296dc8fdf3dSkettenis 	mr->svc_handle = dcs->svc_handle;
297dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
298dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_DELETE_REQUEST;
299dc8fdf3dSkettenis 	mr->namelen = strlen(name);
300dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
301dc8fdf3dSkettenis 
302dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
303dc8fdf3dSkettenis 	free(mr);
304dc8fdf3dSkettenis 
305dc8fdf3dSkettenis 	while (mdstore_command == MDSET_DELETE_REQUEST)
306dc8fdf3dSkettenis 		ds_conn_handle(dc);
307dc8fdf3dSkettenis }
308dc8fdf3dSkettenis 
309*bb93e559Skettenis void frag_init(void);
310*bb93e559Skettenis void add_frag_mblock(struct md_node *);
311*bb93e559Skettenis void add_frag(uint64_t);
312*bb93e559Skettenis void delete_frag(uint64_t);
313*bb93e559Skettenis uint64_t alloc_frag(void);
314*bb93e559Skettenis 
315dc8fdf3dSkettenis void
316dc8fdf3dSkettenis mdstore_download(struct ds_conn *dc, const char *name)
317dc8fdf3dSkettenis {
318dc8fdf3dSkettenis 	struct ds_conn_svc *dcs;
319*bb93e559Skettenis 	struct md_node *node;
320*bb93e559Skettenis 	struct md_prop *prop;
321*bb93e559Skettenis 	struct guest *guest;
322*bb93e559Skettenis 	int nmds = 2;
323*bb93e559Skettenis 	char *path;
324*bb93e559Skettenis 	uint16_t type;
325dc8fdf3dSkettenis 
326dc8fdf3dSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
327dc8fdf3dSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0)
328dc8fdf3dSkettenis 			break;
329dc8fdf3dSkettenis 	assert(dcs != TAILQ_END(&dc->services));
330dc8fdf3dSkettenis 
331*bb93e559Skettenis 	if (asprintf(&path, "%s/hv.md", name) == -1)
332*bb93e559Skettenis 		err(1, "asprintf");
333*bb93e559Skettenis 	hvmd = md_read(path);
334*bb93e559Skettenis 	free(path);
335*bb93e559Skettenis 
336*bb93e559Skettenis 	if (hvmd == NULL)
337*bb93e559Skettenis 		err(1, "%s", name);
338*bb93e559Skettenis 
339*bb93e559Skettenis 	node = md_find_node(hvmd, "guests");
340*bb93e559Skettenis 	TAILQ_INIT(&guests);
341*bb93e559Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
342*bb93e559Skettenis 		if (prop->tag == MD_PROP_ARC &&
343*bb93e559Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
344*bb93e559Skettenis 			add_guest(prop->d.arc.node);
345*bb93e559Skettenis 			nmds++;
346*bb93e559Skettenis 		}
347*bb93e559Skettenis 	}
348*bb93e559Skettenis 
349*bb93e559Skettenis 	frag_init();
350*bb93e559Skettenis 	hv_mdpa = alloc_frag();
351*bb93e559Skettenis 
352*bb93e559Skettenis 	mdstore_begin(dc, dcs->svc_handle, name, nmds);
353*bb93e559Skettenis 	TAILQ_FOREACH(guest, &guests, link) {
354*bb93e559Skettenis 		if (asprintf(&path, "%s/%s.md", name, guest->name) == -1)
355*bb93e559Skettenis 			err(1, "asprintf");
356*bb93e559Skettenis 		type = 0;
357*bb93e559Skettenis 		if (strcmp(guest->name, "primary") == 0)
358*bb93e559Skettenis 			type = MDSTORE_CTL_DOM_MD_TYPE;
359*bb93e559Skettenis 		mdstore_transfer(dc, dcs->svc_handle, path, type, guest->mdpa);
360*bb93e559Skettenis 		free(path);
361*bb93e559Skettenis 	}
362*bb93e559Skettenis 	if (asprintf(&path, "%s/hv.md", name) == -1)
363*bb93e559Skettenis 		err(1, "asprintf");
364*bb93e559Skettenis 	mdstore_transfer(dc, dcs->svc_handle, path,
365*bb93e559Skettenis 	    MDSTORE_HV_MD_TYPE, hv_mdpa);
366*bb93e559Skettenis 	free(path);
367*bb93e559Skettenis 	if (asprintf(&path, "%s/pri", name) == -1)
368*bb93e559Skettenis 		err(1, "asprintf");
369*bb93e559Skettenis 	mdstore_transfer(dc, dcs->svc_handle, path,
370dc8fdf3dSkettenis 	    MDSTORE_PRI_TYPE, 0);
371*bb93e559Skettenis 	free(path);
372*bb93e559Skettenis 	mdstore_end(dc, dcs->svc_handle, name, nmds);
373*bb93e559Skettenis }
374*bb93e559Skettenis 
375*bb93e559Skettenis struct frag {
376*bb93e559Skettenis 	TAILQ_ENTRY(frag) link;
377*bb93e559Skettenis 	uint64_t base;
378*bb93e559Skettenis };
379*bb93e559Skettenis 
380*bb93e559Skettenis TAILQ_HEAD(frag_head, frag) free_frags;
381*bb93e559Skettenis 
382*bb93e559Skettenis uint64_t fragsize;
383*bb93e559Skettenis 
384*bb93e559Skettenis void
385*bb93e559Skettenis frag_init(void)
386*bb93e559Skettenis {
387*bb93e559Skettenis 	struct md_node *node;
388*bb93e559Skettenis 	struct md_prop *prop;
389*bb93e559Skettenis 
390*bb93e559Skettenis 	node = md_find_node(hvmd, "frag_space");
391*bb93e559Skettenis 	md_get_prop_val(hvmd, node, "fragsize", &fragsize);
392*bb93e559Skettenis 	TAILQ_INIT(&free_frags);
393*bb93e559Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
394*bb93e559Skettenis 		if (prop->tag == MD_PROP_ARC &&
395*bb93e559Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
396*bb93e559Skettenis 			add_frag_mblock(prop->d.arc.node);
397*bb93e559Skettenis 	}
398*bb93e559Skettenis }
399*bb93e559Skettenis 
400*bb93e559Skettenis void
401*bb93e559Skettenis add_frag_mblock(struct md_node *node)
402*bb93e559Skettenis {
403*bb93e559Skettenis 	uint64_t base, size;
404*bb93e559Skettenis 	struct guest *guest;
405*bb93e559Skettenis 
406*bb93e559Skettenis 	md_get_prop_val(hvmd, node, "base", &base);
407*bb93e559Skettenis 	md_get_prop_val(hvmd, node, "size", &size);
408*bb93e559Skettenis 	while (size > fragsize) {
409*bb93e559Skettenis 		add_frag(base);
410*bb93e559Skettenis 		size -= fragsize;
411*bb93e559Skettenis 		base += fragsize;
412*bb93e559Skettenis 	}
413*bb93e559Skettenis 
414*bb93e559Skettenis 	delete_frag(hv_mdpa);
415*bb93e559Skettenis 	TAILQ_FOREACH(guest, &guests, link)
416*bb93e559Skettenis 		delete_frag(guest->mdpa);
417*bb93e559Skettenis }
418*bb93e559Skettenis 
419*bb93e559Skettenis void
420*bb93e559Skettenis add_frag(uint64_t base)
421*bb93e559Skettenis {
422*bb93e559Skettenis 	struct frag *frag;
423*bb93e559Skettenis 
424*bb93e559Skettenis 	frag = xmalloc(sizeof(*frag));
425*bb93e559Skettenis 	frag->base = base;
426*bb93e559Skettenis 	TAILQ_INSERT_TAIL(&free_frags, frag, link);
427*bb93e559Skettenis }
428*bb93e559Skettenis 
429*bb93e559Skettenis void
430*bb93e559Skettenis delete_frag(uint64_t base)
431*bb93e559Skettenis {
432*bb93e559Skettenis 	struct frag *frag;
433*bb93e559Skettenis 	struct frag *tmp;
434*bb93e559Skettenis 
435*bb93e559Skettenis 	TAILQ_FOREACH_SAFE(frag, &free_frags, link, tmp) {
436*bb93e559Skettenis 		if (frag->base == base) {
437*bb93e559Skettenis 			TAILQ_REMOVE(&free_frags, frag, link);
438*bb93e559Skettenis 			free(frag);
439*bb93e559Skettenis 		}
440*bb93e559Skettenis 	}
441*bb93e559Skettenis }
442*bb93e559Skettenis 
443*bb93e559Skettenis uint64_t
444*bb93e559Skettenis alloc_frag(void)
445*bb93e559Skettenis {
446*bb93e559Skettenis 	struct frag *frag;
447*bb93e559Skettenis 	uint64_t base;
448*bb93e559Skettenis 
449*bb93e559Skettenis 	frag = TAILQ_FIRST(&free_frags);
450*bb93e559Skettenis 	if (frag == NULL)
451*bb93e559Skettenis 		return -1;
452*bb93e559Skettenis 
453*bb93e559Skettenis 	TAILQ_REMOVE(&free_frags, frag, link);
454*bb93e559Skettenis 	base = frag->base;
455*bb93e559Skettenis 	free(frag);
456*bb93e559Skettenis 
457*bb93e559Skettenis 	return base;
458dc8fdf3dSkettenis }
459