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