xref: /openbsd/usr.sbin/ldomctl/mdstore.c (revision 72b890ef)
1*72b890efSkettenis /*	$OpenBSD: mdstore.c,v 1.14 2021/02/01 16:27:06 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"
29d73a4c4fSkn #include "ldom_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);
344b9ab11dSkettenis void	mdstore_start_v3(struct ldc_conn *, uint64_t);
35cceaa36bSkettenis void	mdstore_rx_data(struct ldc_conn *, uint64_t, void *, size_t);
36cceaa36bSkettenis 
37cceaa36bSkettenis struct ds_service mdstore_service = {
38cceaa36bSkettenis 	"mdstore", 1, 0, mdstore_start, mdstore_rx_data
39cceaa36bSkettenis };
40cceaa36bSkettenis 
41a0709405Skettenis struct ds_service mdstore_service_v2 = {
42a0709405Skettenis 	"mdstore", 2, 0, mdstore_start_v2, mdstore_rx_data
43a0709405Skettenis };
44a0709405Skettenis 
454b9ab11dSkettenis struct ds_service mdstore_service_v3 = {
464b9ab11dSkettenis 	"mdstore", 3, 0, mdstore_start_v3, mdstore_rx_data
474b9ab11dSkettenis };
484b9ab11dSkettenis 
49dc8fdf3dSkettenis #define MDSET_BEGIN_REQUEST	0x0001
50dc8fdf3dSkettenis #define MDSET_END_REQUEST	0x0002
51dc8fdf3dSkettenis #define MD_TRANSFER_REQUEST	0x0003
52cceaa36bSkettenis #define MDSET_LIST_REQUEST	0x0004
536aace0ceSkettenis #define MDSET_SELECT_REQUEST	0x0005
546aace0ceSkettenis #define MDSET_DELETE_REQUEST	0x0006
556aace0ceSkettenis #define MDSET_RETREIVE_REQUEST	0x0007
56cceaa36bSkettenis 
57cceaa36bSkettenis struct mdstore_msg {
58cceaa36bSkettenis 	uint32_t	msg_type;
59cceaa36bSkettenis 	uint32_t	payload_len;
60cceaa36bSkettenis 	uint64_t	svc_handle;
61cceaa36bSkettenis 	uint64_t	reqnum;
62cceaa36bSkettenis 	uint16_t	command;
6306b192deSkettenis 	uint8_t		reserved[6];
64cceaa36bSkettenis } __packed;
65cceaa36bSkettenis 
66dc8fdf3dSkettenis struct mdstore_begin_end_req {
67dc8fdf3dSkettenis 	uint32_t	msg_type;
68dc8fdf3dSkettenis 	uint32_t	payload_len;
69dc8fdf3dSkettenis 	uint64_t	svc_handle;
70dc8fdf3dSkettenis 	uint64_t	reqnum;
71dc8fdf3dSkettenis 	uint16_t	command;
72dc8fdf3dSkettenis 	uint16_t	nmds;
73dc8fdf3dSkettenis 	uint32_t	namelen;
74dc8fdf3dSkettenis 	char		name[1];
75dc8fdf3dSkettenis } __packed;
76dc8fdf3dSkettenis 
77a0709405Skettenis struct mdstore_begin_req_v2 {
78a0709405Skettenis 	uint32_t	msg_type;
79a0709405Skettenis 	uint32_t	payload_len;
80a0709405Skettenis 	uint64_t	svc_handle;
81a0709405Skettenis 	uint64_t	reqnum;
82a0709405Skettenis 	uint16_t	command;
83a0709405Skettenis 	uint16_t	nmds;
84a0709405Skettenis 	uint32_t	config_size;
85a0709405Skettenis   	uint64_t	timestamp;
86a0709405Skettenis 	uint32_t	namelen;
87a0709405Skettenis 	char		name[1];
88a0709405Skettenis } __packed;
89a0709405Skettenis 
904b9ab11dSkettenis struct mdstore_begin_req_v3 {
914b9ab11dSkettenis 	uint32_t	msg_type;
924b9ab11dSkettenis 	uint32_t	payload_len;
934b9ab11dSkettenis 	uint64_t	svc_handle;
944b9ab11dSkettenis 	uint64_t	reqnum;
954b9ab11dSkettenis 	uint16_t	command;
964b9ab11dSkettenis 	uint16_t	nmds;
974b9ab11dSkettenis 	uint32_t	config_size;
984b9ab11dSkettenis   	uint64_t	timestamp;
994b9ab11dSkettenis 	uint8_t		degraded;
1004b9ab11dSkettenis 	uint8_t		active_config;
1014b9ab11dSkettenis 	uint8_t		reserved[2];
1024b9ab11dSkettenis 	uint32_t	namelen;
1034b9ab11dSkettenis 	char		name[1];
1044b9ab11dSkettenis } __packed;
1054b9ab11dSkettenis 
1064b9ab11dSkettenis #define CONFIG_NORMAL		0x00
1074b9ab11dSkettenis #define CONFIG_DEGRADED		0x01
1084b9ab11dSkettenis 
1094b9ab11dSkettenis #define CONFIG_EXISTING		0x00
1104b9ab11dSkettenis #define CONFIG_ACTIVE		0x01
1114b9ab11dSkettenis 
112dc8fdf3dSkettenis struct mdstore_transfer_req {
113dc8fdf3dSkettenis 	uint32_t	msg_type;
114dc8fdf3dSkettenis 	uint32_t	payload_len;
115dc8fdf3dSkettenis 	uint64_t	svc_handle;
116dc8fdf3dSkettenis 	uint64_t	reqnum;
117dc8fdf3dSkettenis 	uint16_t	command;
118dc8fdf3dSkettenis 	uint16_t	type;
119dc8fdf3dSkettenis 	uint32_t	size;
120dc8fdf3dSkettenis 	uint64_t	offset;
121dc8fdf3dSkettenis 	char		md[];
122dc8fdf3dSkettenis } __packed;
123dc8fdf3dSkettenis 
124dc8fdf3dSkettenis #define MDSTORE_PRI_TYPE	0x01
125dc8fdf3dSkettenis #define MDSTORE_HV_MD_TYPE	0x02
126dc8fdf3dSkettenis #define MDSTORE_CTL_DOM_MD_TYPE	0x04
127dc8fdf3dSkettenis #define MDSTORE_SVC_DOM_MD_TYPE	0x08
128dc8fdf3dSkettenis 
1296aace0ceSkettenis struct mdstore_sel_del_req {
1306aace0ceSkettenis 	uint32_t	msg_type;
1316aace0ceSkettenis 	uint32_t	payload_len;
1326aace0ceSkettenis 	uint64_t	svc_handle;
1336aace0ceSkettenis 	uint64_t	reqnum;
1346aace0ceSkettenis 	uint16_t	command;
13506b192deSkettenis 	uint8_t		reserved[2];
1366aace0ceSkettenis 	uint32_t	namelen;
1376aace0ceSkettenis 	char		name[1];
1386aace0ceSkettenis } __packed;
1396aace0ceSkettenis 
140cceaa36bSkettenis #define MDSET_LIST_REPLY	0x0104
141cceaa36bSkettenis 
142cceaa36bSkettenis struct mdstore_list_resp {
143cceaa36bSkettenis 	uint32_t	msg_type;
144cceaa36bSkettenis 	uint32_t	payload_len;
145cceaa36bSkettenis 	uint64_t	svc_handle;
146cceaa36bSkettenis 	uint64_t	reqnum;
147cceaa36bSkettenis 	uint32_t	result;
148cceaa36bSkettenis 	uint16_t	booted_set;
149cceaa36bSkettenis 	uint16_t	boot_set;
150cceaa36bSkettenis 	char		sets[1];
151cceaa36bSkettenis } __packed;
152cceaa36bSkettenis 
153cceaa36bSkettenis #define MDST_SUCCESS		0x0
154cceaa36bSkettenis #define MDST_FAILURE		0x1
155cceaa36bSkettenis #define MDST_INVALID_MSG	0x2
156cceaa36bSkettenis #define MDST_MAX_MDS_ERR	0x3
157cceaa36bSkettenis #define MDST_BAD_NAME_ERR	0x4
158cceaa36bSkettenis #define MDST_SET_EXISTS_ERR	0x5
159cceaa36bSkettenis #define MDST_ALLOC_SET_ERR	0x6
160cceaa36bSkettenis #define MDST_ALLOC_MD_ERR	0x7
161cceaa36bSkettenis #define MDST_MD_COUNT_ERR	0x8
162cceaa36bSkettenis #define MDST_MD_SIZE_ERR	0x9
163cceaa36bSkettenis #define MDST_MD_TYPE_ERR	0xa
164cceaa36bSkettenis #define MDST_NOT_EXIST_ERR	0xb
165cceaa36bSkettenis 
166cceaa36bSkettenis struct mdstore_set_head mdstore_sets = TAILQ_HEAD_INITIALIZER(mdstore_sets);
1676aace0ceSkettenis uint64_t mdstore_reqnum;
1686aace0ceSkettenis uint64_t mdstore_command;
169a0709405Skettenis uint16_t mdstore_major;
170a0709405Skettenis 
171a0709405Skettenis void
mdstore_register(struct ds_conn * dc)172a0709405Skettenis mdstore_register(struct ds_conn *dc)
173a0709405Skettenis {
174a0709405Skettenis 	ds_conn_register_service(dc, &mdstore_service);
175a0709405Skettenis 	ds_conn_register_service(dc, &mdstore_service_v2);
1764b9ab11dSkettenis 	ds_conn_register_service(dc, &mdstore_service_v3);
177a0709405Skettenis }
178cceaa36bSkettenis 
179cceaa36bSkettenis void
mdstore_start(struct ldc_conn * lc,uint64_t svc_handle)180cceaa36bSkettenis mdstore_start(struct ldc_conn *lc, uint64_t svc_handle)
181cceaa36bSkettenis {
182cceaa36bSkettenis 	struct mdstore_msg mm;
183cceaa36bSkettenis 
184cceaa36bSkettenis 	bzero(&mm, sizeof(mm));
185cceaa36bSkettenis 	mm.msg_type = DS_DATA;
186cceaa36bSkettenis 	mm.payload_len = sizeof(mm) - 8;
187cceaa36bSkettenis 	mm.svc_handle = svc_handle;
1886aace0ceSkettenis 	mm.reqnum = mdstore_reqnum++;
1896aace0ceSkettenis 	mm.command = mdstore_command = MDSET_LIST_REQUEST;
190cceaa36bSkettenis 	ds_send_msg(lc, &mm, sizeof(mm));
191cceaa36bSkettenis }
192cceaa36bSkettenis 
193cceaa36bSkettenis void
mdstore_start_v2(struct ldc_conn * lc,uint64_t svc_handle)194a0709405Skettenis mdstore_start_v2(struct ldc_conn *lc, uint64_t svc_handle)
195a0709405Skettenis {
196a0709405Skettenis 	mdstore_major = 2;
197a0709405Skettenis 	mdstore_start(lc, svc_handle);
198a0709405Skettenis }
199a0709405Skettenis 
200a0709405Skettenis void
mdstore_start_v3(struct ldc_conn * lc,uint64_t svc_handle)2014b9ab11dSkettenis mdstore_start_v3(struct ldc_conn *lc, uint64_t svc_handle)
2024b9ab11dSkettenis {
2034b9ab11dSkettenis 	mdstore_major = 3;
2044b9ab11dSkettenis 	mdstore_start(lc, svc_handle);
2054b9ab11dSkettenis }
2064b9ab11dSkettenis 
2074b9ab11dSkettenis void
mdstore_rx_data(struct ldc_conn * lc,uint64_t svc_handle,void * data,size_t len)208cceaa36bSkettenis mdstore_rx_data(struct ldc_conn *lc, uint64_t svc_handle, void *data,
209cceaa36bSkettenis     size_t len)
210cceaa36bSkettenis {
211cceaa36bSkettenis 	struct mdstore_list_resp *mr = data;
212cceaa36bSkettenis 	struct mdstore_set *set;
213cceaa36bSkettenis 	int idx;
214cceaa36bSkettenis 
215cceaa36bSkettenis 	if (mr->result != MDST_SUCCESS) {
216a2ea7dabSkettenis 		switch (mr->result) {
217a2ea7dabSkettenis 		case MDST_SET_EXISTS_ERR:
218a2ea7dabSkettenis 			errx(1, "Configuration already exists");
219a2ea7dabSkettenis 			break;
220a2ea7dabSkettenis 		case MDST_NOT_EXIST_ERR:
221a2ea7dabSkettenis 			errx(1, "No such configuration");
222a2ea7dabSkettenis 			break;
223a2ea7dabSkettenis 		default:
224a2ea7dabSkettenis 			errx(1, "Unexpected result 0x%x\n", mr->result);
225a2ea7dabSkettenis 			break;
226a2ea7dabSkettenis 		}
227cceaa36bSkettenis 	}
228cceaa36bSkettenis 
2296aace0ceSkettenis 	switch (mdstore_command) {
2306aace0ceSkettenis 	case MDSET_LIST_REQUEST:
2316aace0ceSkettenis 		for (idx = 0, len = 0; len < mr->payload_len - 24; idx++) {
232cceaa36bSkettenis 			set = xmalloc(sizeof(*set));
233cceaa36bSkettenis 			set->name = xstrdup(&mr->sets[len]);
234cceaa36bSkettenis 			set->booted_set = (idx == mr->booted_set);
235cceaa36bSkettenis 			set->boot_set = (idx == mr->boot_set);
236cceaa36bSkettenis 			TAILQ_INSERT_TAIL(&mdstore_sets, set, link);
237cceaa36bSkettenis 			len += strlen(&mr->sets[len]) + 1;
2384b9ab11dSkettenis 			if (mdstore_major >= 2)
239a0709405Skettenis 				len += sizeof(uint64_t); /* skip timestamp */
2404b9ab11dSkettenis 			if (mdstore_major >= 3)
2414b9ab11dSkettenis 				len += sizeof(uint8_t);	/* skip has_degraded */
242cceaa36bSkettenis 		}
2436aace0ceSkettenis 		break;
2446aace0ceSkettenis 	}
245dc8fdf3dSkettenis 
246dc8fdf3dSkettenis 	mdstore_command = 0;
247dc8fdf3dSkettenis }
248dc8fdf3dSkettenis 
249dc8fdf3dSkettenis void
mdstore_begin_v1(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds)250a0709405Skettenis mdstore_begin_v1(struct ds_conn *dc, uint64_t svc_handle, const char *name,
251bb93e559Skettenis     int nmds)
252dc8fdf3dSkettenis {
253dc8fdf3dSkettenis 	struct mdstore_begin_end_req *mr;
254dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
255dc8fdf3dSkettenis 
256dc8fdf3dSkettenis 	mr = xzalloc(len);
257dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
258dc8fdf3dSkettenis 	mr->payload_len = len - 8;
259dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
260dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
261dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
262bb93e559Skettenis 	mr->nmds = nmds;
263dc8fdf3dSkettenis 	mr->namelen = strlen(name);
264dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
265dc8fdf3dSkettenis 
266dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
267dc8fdf3dSkettenis 	free(mr);
268dc8fdf3dSkettenis 
269dc8fdf3dSkettenis 	while (mdstore_command == MDSET_BEGIN_REQUEST)
270dc8fdf3dSkettenis 		ds_conn_handle(dc);
271dc8fdf3dSkettenis }
272dc8fdf3dSkettenis 
273dc8fdf3dSkettenis void
mdstore_begin_v2(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)274a0709405Skettenis mdstore_begin_v2(struct ds_conn *dc, uint64_t svc_handle, const char *name,
275a0709405Skettenis     int nmds, uint32_t config_size)
276a0709405Skettenis {
277a0709405Skettenis 	struct mdstore_begin_req_v2 *mr;
278a0709405Skettenis 	size_t len = sizeof(*mr) + strlen(name);
279a0709405Skettenis 
280a0709405Skettenis 	mr = xzalloc(len);
281a0709405Skettenis 	mr->msg_type = DS_DATA;
282a0709405Skettenis 	mr->payload_len = len - 8;
283a0709405Skettenis 	mr->svc_handle = svc_handle;
284a0709405Skettenis 	mr->reqnum = mdstore_reqnum++;
285a0709405Skettenis 	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
286a0709405Skettenis 	mr->config_size = config_size;
287a0709405Skettenis 	mr->timestamp = time(NULL);
288a0709405Skettenis 	mr->nmds = nmds;
289a0709405Skettenis 	mr->namelen = strlen(name);
290a0709405Skettenis 	memcpy(mr->name, name, strlen(name));
291a0709405Skettenis 
292a0709405Skettenis 	ds_send_msg(&dc->lc, mr, len);
293a0709405Skettenis 	free(mr);
294a0709405Skettenis 
295a0709405Skettenis 	while (mdstore_command == MDSET_BEGIN_REQUEST)
296a0709405Skettenis 		ds_conn_handle(dc);
297a0709405Skettenis }
298a0709405Skettenis 
299a0709405Skettenis void
mdstore_begin_v3(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)3004b9ab11dSkettenis mdstore_begin_v3(struct ds_conn *dc, uint64_t svc_handle, const char *name,
3014b9ab11dSkettenis     int nmds, uint32_t config_size)
3024b9ab11dSkettenis {
3034b9ab11dSkettenis 	struct mdstore_begin_req_v3 *mr;
3044b9ab11dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
3054b9ab11dSkettenis 
3064b9ab11dSkettenis 	mr = xzalloc(len);
3074b9ab11dSkettenis 	mr->msg_type = DS_DATA;
3084b9ab11dSkettenis 	mr->payload_len = len - 8;
3094b9ab11dSkettenis 	mr->svc_handle = svc_handle;
3104b9ab11dSkettenis 	mr->reqnum = mdstore_reqnum++;
3114b9ab11dSkettenis 	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
3124b9ab11dSkettenis 	mr->config_size = config_size;
3134b9ab11dSkettenis 	mr->timestamp = time(NULL);
3144b9ab11dSkettenis 	mr->degraded = CONFIG_NORMAL;
3154b9ab11dSkettenis 	mr->active_config = CONFIG_EXISTING;
3164b9ab11dSkettenis 	mr->nmds = nmds;
3174b9ab11dSkettenis 	mr->namelen = strlen(name);
3184b9ab11dSkettenis 	memcpy(mr->name, name, strlen(name));
3194b9ab11dSkettenis 
3204b9ab11dSkettenis 	ds_send_msg(&dc->lc, mr, len);
3214b9ab11dSkettenis 	free(mr);
3224b9ab11dSkettenis 
3234b9ab11dSkettenis 	while (mdstore_command == MDSET_BEGIN_REQUEST)
3244b9ab11dSkettenis 		ds_conn_handle(dc);
3254b9ab11dSkettenis }
3264b9ab11dSkettenis 
3274b9ab11dSkettenis void
mdstore_begin(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds,uint32_t config_size)328a0709405Skettenis mdstore_begin(struct ds_conn *dc, uint64_t svc_handle, const char *name,
329a0709405Skettenis     int nmds, uint32_t config_size)
330a0709405Skettenis {
3314b9ab11dSkettenis 	if (mdstore_major == 3)
3324b9ab11dSkettenis 		mdstore_begin_v3(dc, svc_handle, name, nmds, config_size);
3334b9ab11dSkettenis 	else if (mdstore_major == 2)
334a0709405Skettenis 		mdstore_begin_v2(dc, svc_handle, name, nmds, config_size);
335a0709405Skettenis 	else
336a0709405Skettenis 		mdstore_begin_v1(dc, svc_handle, name, nmds);
337a0709405Skettenis }
338a0709405Skettenis 
339a0709405Skettenis void
mdstore_transfer(struct ds_conn * dc,uint64_t svc_handle,const char * path,uint16_t type,uint64_t offset)340dc8fdf3dSkettenis mdstore_transfer(struct ds_conn *dc, uint64_t svc_handle, const char *path,
341dc8fdf3dSkettenis     uint16_t type, uint64_t offset)
342dc8fdf3dSkettenis {
343dc8fdf3dSkettenis 	struct mdstore_transfer_req *mr;
344dc8fdf3dSkettenis 	uint32_t size;
345dc8fdf3dSkettenis 	size_t len;
346dc8fdf3dSkettenis 	FILE *fp;
347dc8fdf3dSkettenis 
348dc8fdf3dSkettenis 	fp = fopen(path, "r");
349dc8fdf3dSkettenis 	if (fp == NULL)
350dc8fdf3dSkettenis 		err(1, "fopen");
351dc8fdf3dSkettenis 
352dc8fdf3dSkettenis 	fseek(fp, 0, SEEK_END);
353dc8fdf3dSkettenis 	size = ftell(fp);
354dc8fdf3dSkettenis 	fseek(fp, 0, SEEK_SET);
355dc8fdf3dSkettenis 
356dc8fdf3dSkettenis 	len = sizeof(*mr) + size;
357dc8fdf3dSkettenis 	mr = xzalloc(len);
358dc8fdf3dSkettenis 
359dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
360dc8fdf3dSkettenis 	mr->payload_len = len - 8;
361dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
362dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
363dc8fdf3dSkettenis 	mr->command = mdstore_command = MD_TRANSFER_REQUEST;
364dc8fdf3dSkettenis 	mr->type = type;
365dc8fdf3dSkettenis 	mr->size = size;
366dc8fdf3dSkettenis 	mr->offset = offset;
367dc8fdf3dSkettenis 	if (fread(&mr->md, size, 1, fp) != 1)
368dc8fdf3dSkettenis 		err(1, "fread");
369dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
370dc8fdf3dSkettenis 	free(mr);
371dc8fdf3dSkettenis 
372dc8fdf3dSkettenis 	fclose(fp);
373dc8fdf3dSkettenis 
374dc8fdf3dSkettenis 	while (mdstore_command == MD_TRANSFER_REQUEST)
375dc8fdf3dSkettenis 		ds_conn_handle(dc);
376dc8fdf3dSkettenis }
377dc8fdf3dSkettenis 
378dc8fdf3dSkettenis void
mdstore_end(struct ds_conn * dc,uint64_t svc_handle,const char * name,int nmds)379bb93e559Skettenis mdstore_end(struct ds_conn *dc, uint64_t svc_handle, const char *name,
380bb93e559Skettenis     int nmds)
381dc8fdf3dSkettenis {
382dc8fdf3dSkettenis 	struct mdstore_begin_end_req *mr;
383dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
384dc8fdf3dSkettenis 
385dc8fdf3dSkettenis 	mr = xzalloc(len);
386dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
387dc8fdf3dSkettenis 	mr->payload_len = len - 8;
388dc8fdf3dSkettenis 	mr->svc_handle = svc_handle;
389dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
390dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_END_REQUEST;
391bb93e559Skettenis 	mr->nmds = nmds;
392dc8fdf3dSkettenis 	mr->namelen = strlen(name);
393dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
394dc8fdf3dSkettenis 
395dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
396dc8fdf3dSkettenis 	free(mr);
397dc8fdf3dSkettenis 
398dc8fdf3dSkettenis 	while (mdstore_command == MDSET_END_REQUEST)
399dc8fdf3dSkettenis 		ds_conn_handle(dc);
4006aace0ceSkettenis }
4016aace0ceSkettenis 
4026aace0ceSkettenis void
mdstore_select(struct ds_conn * dc,const char * name)4036aace0ceSkettenis mdstore_select(struct ds_conn *dc, const char *name)
4046aace0ceSkettenis {
4056aace0ceSkettenis 	struct ds_conn_svc *dcs;
4066aace0ceSkettenis 	struct mdstore_sel_del_req *mr;
407dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
4086aace0ceSkettenis 
4096aace0ceSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
410b2093b6cSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
411b2093b6cSkettenis 		    dcs->svc_handle != 0)
4126aace0ceSkettenis 			break;
413abcbcc4dSdoug 	assert(dcs != NULL);
4146aace0ceSkettenis 
4156aace0ceSkettenis 	mr = xzalloc(len);
4166aace0ceSkettenis 	mr->msg_type = DS_DATA;
4176aace0ceSkettenis 	mr->payload_len = len - 8;
4186aace0ceSkettenis 	mr->svc_handle = dcs->svc_handle;
4196aace0ceSkettenis 	mr->reqnum = mdstore_reqnum++;
4206aace0ceSkettenis 	mr->command = mdstore_command = MDSET_SELECT_REQUEST;
4216aace0ceSkettenis 	mr->namelen = strlen(name);
4226aace0ceSkettenis 	memcpy(mr->name, name, strlen(name));
4236aace0ceSkettenis 
4246aace0ceSkettenis 	ds_send_msg(&dc->lc, mr, len);
4256aace0ceSkettenis 	free(mr);
4266aace0ceSkettenis 
4276aace0ceSkettenis 	while (mdstore_command == MDSET_SELECT_REQUEST)
4286aace0ceSkettenis 		ds_conn_handle(dc);
429cceaa36bSkettenis }
430dc8fdf3dSkettenis 
431dc8fdf3dSkettenis void
mdstore_delete(struct ds_conn * dc,const char * name)432dc8fdf3dSkettenis mdstore_delete(struct ds_conn *dc, const char *name)
433dc8fdf3dSkettenis {
434dc8fdf3dSkettenis 	struct ds_conn_svc *dcs;
435dc8fdf3dSkettenis 	struct mdstore_sel_del_req *mr;
436dc8fdf3dSkettenis 	size_t len = sizeof(*mr) + strlen(name);
437dc8fdf3dSkettenis 
438dc8fdf3dSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
439b2093b6cSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
440b2093b6cSkettenis 		    dcs->svc_handle != 0)
441dc8fdf3dSkettenis 			break;
442abcbcc4dSdoug 	assert(dcs != NULL);
443dc8fdf3dSkettenis 
444dc8fdf3dSkettenis 	mr = xzalloc(len);
445dc8fdf3dSkettenis 	mr->msg_type = DS_DATA;
446dc8fdf3dSkettenis 	mr->payload_len = len - 8;
447dc8fdf3dSkettenis 	mr->svc_handle = dcs->svc_handle;
448dc8fdf3dSkettenis 	mr->reqnum = mdstore_reqnum++;
449dc8fdf3dSkettenis 	mr->command = mdstore_command = MDSET_DELETE_REQUEST;
450dc8fdf3dSkettenis 	mr->namelen = strlen(name);
451dc8fdf3dSkettenis 	memcpy(mr->name, name, strlen(name));
452dc8fdf3dSkettenis 
453dc8fdf3dSkettenis 	ds_send_msg(&dc->lc, mr, len);
454dc8fdf3dSkettenis 	free(mr);
455dc8fdf3dSkettenis 
456dc8fdf3dSkettenis 	while (mdstore_command == MDSET_DELETE_REQUEST)
457dc8fdf3dSkettenis 		ds_conn_handle(dc);
458dc8fdf3dSkettenis }
459dc8fdf3dSkettenis 
460bb93e559Skettenis void frag_init(void);
461bb93e559Skettenis void add_frag_mblock(struct md_node *);
462bb93e559Skettenis void add_frag(uint64_t);
463bb93e559Skettenis void delete_frag(uint64_t);
464bb93e559Skettenis uint64_t alloc_frag(void);
465bb93e559Skettenis 
466dc8fdf3dSkettenis void
mdstore_download(struct ds_conn * dc,const char * name)467dc8fdf3dSkettenis mdstore_download(struct ds_conn *dc, const char *name)
468dc8fdf3dSkettenis {
469dc8fdf3dSkettenis 	struct ds_conn_svc *dcs;
470bb93e559Skettenis 	struct md_node *node;
471bb93e559Skettenis 	struct md_prop *prop;
472bb93e559Skettenis 	struct guest *guest;
473bb93e559Skettenis 	int nmds = 2;
474bb93e559Skettenis 	char *path;
475a0709405Skettenis 	uint32_t total_size = 0;
476bb93e559Skettenis 	uint16_t type;
477dc8fdf3dSkettenis 
478dc8fdf3dSkettenis 	TAILQ_FOREACH(dcs, &dc->services, link)
479b2093b6cSkettenis 		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
480b2093b6cSkettenis 		    dcs->svc_handle != 0)
481dc8fdf3dSkettenis 			break;
482abcbcc4dSdoug 	assert(dcs != NULL);
483dc8fdf3dSkettenis 
484bb93e559Skettenis 	if (asprintf(&path, "%s/hv.md", name) == -1)
485bb93e559Skettenis 		err(1, "asprintf");
486bb93e559Skettenis 	hvmd = md_read(path);
487bb93e559Skettenis 	free(path);
488bb93e559Skettenis 
489bb93e559Skettenis 	if (hvmd == NULL)
490bb93e559Skettenis 		err(1, "%s", name);
491bb93e559Skettenis 
492bb93e559Skettenis 	node = md_find_node(hvmd, "guests");
49397d8cafcSkettenis 	TAILQ_INIT(&guest_list);
494bb93e559Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
495bb93e559Skettenis 		if (prop->tag == MD_PROP_ARC &&
496bb93e559Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
497bb93e559Skettenis 			add_guest(prop->d.arc.node);
498bb93e559Skettenis 			nmds++;
499bb93e559Skettenis 		}
500bb93e559Skettenis 	}
501bb93e559Skettenis 
502bb93e559Skettenis 	frag_init();
503bb93e559Skettenis 	hv_mdpa = alloc_frag();
504bb93e559Skettenis 
505a0709405Skettenis 	TAILQ_FOREACH(guest, &guest_list, link) {
506a0709405Skettenis 		if (asprintf(&path, "%s/%s.md", name, guest->name) == -1)
507a0709405Skettenis 			err(1, "asprintf");
508a0709405Skettenis 		total_size += md_size(path);
509a0709405Skettenis 	}
510a0709405Skettenis 	if (asprintf(&path, "%s/hv.md", name) == -1)
511a0709405Skettenis 		err(1, "asprintf");
512a0709405Skettenis 	total_size += md_size(path);
513a0709405Skettenis 	if (asprintf(&path, "%s/pri", name) == -1)
514a0709405Skettenis 		err(1, "asprintf");
515a0709405Skettenis 	total_size += md_size(path);
516a0709405Skettenis 
517a0709405Skettenis 	mdstore_begin(dc, dcs->svc_handle, name, nmds, total_size);
51897d8cafcSkettenis 	TAILQ_FOREACH(guest, &guest_list, link) {
519bb93e559Skettenis 		if (asprintf(&path, "%s/%s.md", name, guest->name) == -1)
520bb93e559Skettenis 			err(1, "asprintf");
521bb93e559Skettenis 		type = 0;
522bb93e559Skettenis 		if (strcmp(guest->name, "primary") == 0)
523bb93e559Skettenis 			type = MDSTORE_CTL_DOM_MD_TYPE;
524bb93e559Skettenis 		mdstore_transfer(dc, dcs->svc_handle, path, type, guest->mdpa);
525bb93e559Skettenis 		free(path);
526bb93e559Skettenis 	}
527bb93e559Skettenis 	if (asprintf(&path, "%s/hv.md", name) == -1)
528bb93e559Skettenis 		err(1, "asprintf");
529bb93e559Skettenis 	mdstore_transfer(dc, dcs->svc_handle, path,
530bb93e559Skettenis 	    MDSTORE_HV_MD_TYPE, hv_mdpa);
531bb93e559Skettenis 	free(path);
532bb93e559Skettenis 	if (asprintf(&path, "%s/pri", name) == -1)
533bb93e559Skettenis 		err(1, "asprintf");
534bb93e559Skettenis 	mdstore_transfer(dc, dcs->svc_handle, path,
535dc8fdf3dSkettenis 	    MDSTORE_PRI_TYPE, 0);
536bb93e559Skettenis 	free(path);
537bb93e559Skettenis 	mdstore_end(dc, dcs->svc_handle, name, nmds);
538bb93e559Skettenis }
539bb93e559Skettenis 
540bb93e559Skettenis struct frag {
541bb93e559Skettenis 	TAILQ_ENTRY(frag) link;
542bb93e559Skettenis 	uint64_t base;
543bb93e559Skettenis };
544bb93e559Skettenis 
545*72b890efSkettenis TAILQ_HEAD(frag_head, frag) mdstore_frags;
546bb93e559Skettenis 
547*72b890efSkettenis uint64_t mdstore_fragsize;
548bb93e559Skettenis 
549bb93e559Skettenis void
frag_init(void)550bb93e559Skettenis frag_init(void)
551bb93e559Skettenis {
552bb93e559Skettenis 	struct md_node *node;
553bb93e559Skettenis 	struct md_prop *prop;
554bb93e559Skettenis 
555bb93e559Skettenis 	node = md_find_node(hvmd, "frag_space");
556*72b890efSkettenis 	md_get_prop_val(hvmd, node, "fragsize", &mdstore_fragsize);
557*72b890efSkettenis 	TAILQ_INIT(&mdstore_frags);
558bb93e559Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
559bb93e559Skettenis 		if (prop->tag == MD_PROP_ARC &&
560bb93e559Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
561bb93e559Skettenis 			add_frag_mblock(prop->d.arc.node);
562bb93e559Skettenis 	}
563bb93e559Skettenis }
564bb93e559Skettenis 
565bb93e559Skettenis void
add_frag_mblock(struct md_node * node)566bb93e559Skettenis add_frag_mblock(struct md_node *node)
567bb93e559Skettenis {
568bb93e559Skettenis 	uint64_t base, size;
569bb93e559Skettenis 	struct guest *guest;
570bb93e559Skettenis 
571bb93e559Skettenis 	md_get_prop_val(hvmd, node, "base", &base);
572bb93e559Skettenis 	md_get_prop_val(hvmd, node, "size", &size);
573*72b890efSkettenis 	while (size > mdstore_fragsize) {
574bb93e559Skettenis 		add_frag(base);
575*72b890efSkettenis 		size -= mdstore_fragsize;
576*72b890efSkettenis 		base += mdstore_fragsize;
577bb93e559Skettenis 	}
578bb93e559Skettenis 
579bb93e559Skettenis 	delete_frag(hv_mdpa);
58097d8cafcSkettenis 	TAILQ_FOREACH(guest, &guest_list, link)
581bb93e559Skettenis 		delete_frag(guest->mdpa);
582bb93e559Skettenis }
583bb93e559Skettenis 
584bb93e559Skettenis void
add_frag(uint64_t base)585bb93e559Skettenis add_frag(uint64_t base)
586bb93e559Skettenis {
587bb93e559Skettenis 	struct frag *frag;
588bb93e559Skettenis 
589bb93e559Skettenis 	frag = xmalloc(sizeof(*frag));
590bb93e559Skettenis 	frag->base = base;
591*72b890efSkettenis 	TAILQ_INSERT_TAIL(&mdstore_frags, frag, link);
592bb93e559Skettenis }
593bb93e559Skettenis 
594bb93e559Skettenis void
delete_frag(uint64_t base)595bb93e559Skettenis delete_frag(uint64_t base)
596bb93e559Skettenis {
597bb93e559Skettenis 	struct frag *frag;
598bb93e559Skettenis 	struct frag *tmp;
599bb93e559Skettenis 
600*72b890efSkettenis 	TAILQ_FOREACH_SAFE(frag, &mdstore_frags, link, tmp) {
601bb93e559Skettenis 		if (frag->base == base) {
602*72b890efSkettenis 			TAILQ_REMOVE(&mdstore_frags, frag, link);
603bb93e559Skettenis 			free(frag);
604bb93e559Skettenis 		}
605bb93e559Skettenis 	}
606bb93e559Skettenis }
607bb93e559Skettenis 
608bb93e559Skettenis uint64_t
alloc_frag(void)609bb93e559Skettenis alloc_frag(void)
610bb93e559Skettenis {
611bb93e559Skettenis 	struct frag *frag;
612bb93e559Skettenis 	uint64_t base;
613bb93e559Skettenis 
614*72b890efSkettenis 	frag = TAILQ_FIRST(&mdstore_frags);
615bb93e559Skettenis 	if (frag == NULL)
616bb93e559Skettenis 		return -1;
617bb93e559Skettenis 
618*72b890efSkettenis 	TAILQ_REMOVE(&mdstore_frags, frag, link);
619bb93e559Skettenis 	base = frag->base;
620bb93e559Skettenis 	free(frag);
621bb93e559Skettenis 
622bb93e559Skettenis 	return base;
623dc8fdf3dSkettenis }
624