[BACK]Return to mdstore.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / ldomctl

File: [local] / src / usr.sbin / ldomctl / mdstore.c (download)

Revision 1.14, Mon Feb 1 16:27:06 2021 UTC (3 years, 4 months ago) by kettenis
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, OPENBSD_7_1_BASE, OPENBSD_7_1, OPENBSD_7_0_BASE, OPENBSD_7_0, OPENBSD_6_9_BASE, OPENBSD_6_9, HEAD
Changes since 1.13: +13 -13 lines

The code in mdstore.c should stand on its own, so rename the global
variables used here instead of using the ones from config.c.

ok deraadt@, kn@

/*	$OpenBSD: mdstore.c,v 1.14 2021/02/01 16:27:06 kettenis Exp $	*/

/*
 * Copyright (c) 2012 Mark Kettenis
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "ds.h"
#include "mdesc.h"
#include "mdstore.h"
#include "ldom_util.h"
#include "ldomctl.h"

void	mdstore_start(struct ldc_conn *, uint64_t);
void	mdstore_start_v2(struct ldc_conn *, uint64_t);
void	mdstore_start_v3(struct ldc_conn *, uint64_t);
void	mdstore_rx_data(struct ldc_conn *, uint64_t, void *, size_t);

struct ds_service mdstore_service = {
	"mdstore", 1, 0, mdstore_start, mdstore_rx_data
};

struct ds_service mdstore_service_v2 = {
	"mdstore", 2, 0, mdstore_start_v2, mdstore_rx_data
};

struct ds_service mdstore_service_v3 = {
	"mdstore", 3, 0, mdstore_start_v3, mdstore_rx_data
};

#define MDSET_BEGIN_REQUEST	0x0001
#define MDSET_END_REQUEST	0x0002
#define MD_TRANSFER_REQUEST	0x0003
#define MDSET_LIST_REQUEST	0x0004
#define MDSET_SELECT_REQUEST	0x0005
#define MDSET_DELETE_REQUEST	0x0006
#define MDSET_RETREIVE_REQUEST	0x0007

struct mdstore_msg {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint8_t		reserved[6];
} __packed;

struct mdstore_begin_end_req {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint16_t	nmds;
	uint32_t	namelen;
	char		name[1];
} __packed;

struct mdstore_begin_req_v2 {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint16_t	nmds;
	uint32_t	config_size;
  	uint64_t	timestamp;
	uint32_t	namelen;
	char		name[1];
} __packed;

struct mdstore_begin_req_v3 {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint16_t	nmds;
	uint32_t	config_size;
  	uint64_t	timestamp;
	uint8_t		degraded;
	uint8_t		active_config;
	uint8_t		reserved[2];
	uint32_t	namelen;
	char		name[1];
} __packed;

#define CONFIG_NORMAL		0x00
#define CONFIG_DEGRADED		0x01

#define CONFIG_EXISTING		0x00
#define CONFIG_ACTIVE		0x01

struct mdstore_transfer_req {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint16_t	type;
	uint32_t	size;
	uint64_t	offset;
	char		md[];
} __packed;

#define MDSTORE_PRI_TYPE	0x01
#define MDSTORE_HV_MD_TYPE	0x02
#define MDSTORE_CTL_DOM_MD_TYPE	0x04
#define MDSTORE_SVC_DOM_MD_TYPE	0x08

struct mdstore_sel_del_req {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint16_t	command;
	uint8_t		reserved[2];
	uint32_t	namelen;
	char		name[1];
} __packed;

#define MDSET_LIST_REPLY	0x0104

struct mdstore_list_resp {
	uint32_t	msg_type;
	uint32_t	payload_len;
	uint64_t	svc_handle;
	uint64_t	reqnum;
	uint32_t	result;
	uint16_t	booted_set;
	uint16_t	boot_set;
	char		sets[1];
} __packed;

#define MDST_SUCCESS		0x0
#define MDST_FAILURE		0x1
#define MDST_INVALID_MSG	0x2
#define MDST_MAX_MDS_ERR	0x3
#define MDST_BAD_NAME_ERR	0x4
#define MDST_SET_EXISTS_ERR	0x5
#define MDST_ALLOC_SET_ERR	0x6
#define MDST_ALLOC_MD_ERR	0x7
#define MDST_MD_COUNT_ERR	0x8
#define MDST_MD_SIZE_ERR	0x9
#define MDST_MD_TYPE_ERR	0xa
#define MDST_NOT_EXIST_ERR	0xb

struct mdstore_set_head mdstore_sets = TAILQ_HEAD_INITIALIZER(mdstore_sets);
uint64_t mdstore_reqnum;
uint64_t mdstore_command;
uint16_t mdstore_major;

void
mdstore_register(struct ds_conn *dc)
{
	ds_conn_register_service(dc, &mdstore_service);
	ds_conn_register_service(dc, &mdstore_service_v2);
	ds_conn_register_service(dc, &mdstore_service_v3);
}

void
mdstore_start(struct ldc_conn *lc, uint64_t svc_handle)
{
	struct mdstore_msg mm;

	bzero(&mm, sizeof(mm));
	mm.msg_type = DS_DATA;
	mm.payload_len = sizeof(mm) - 8;
	mm.svc_handle = svc_handle;
	mm.reqnum = mdstore_reqnum++;
	mm.command = mdstore_command = MDSET_LIST_REQUEST;
	ds_send_msg(lc, &mm, sizeof(mm));
}

void
mdstore_start_v2(struct ldc_conn *lc, uint64_t svc_handle)
{
	mdstore_major = 2;
	mdstore_start(lc, svc_handle);
}

void
mdstore_start_v3(struct ldc_conn *lc, uint64_t svc_handle)
{
	mdstore_major = 3;
	mdstore_start(lc, svc_handle);
}

void
mdstore_rx_data(struct ldc_conn *lc, uint64_t svc_handle, void *data,
    size_t len)
{
	struct mdstore_list_resp *mr = data;
	struct mdstore_set *set;
	int idx;

	if (mr->result != MDST_SUCCESS) {
		switch (mr->result) {
		case MDST_SET_EXISTS_ERR:
			errx(1, "Configuration already exists");
			break;
		case MDST_NOT_EXIST_ERR:
			errx(1, "No such configuration");
			break;
		default:
			errx(1, "Unexpected result 0x%x\n", mr->result);
			break;
		}
	}

	switch (mdstore_command) {
	case MDSET_LIST_REQUEST:
		for (idx = 0, len = 0; len < mr->payload_len - 24; idx++) {
			set = xmalloc(sizeof(*set));
			set->name = xstrdup(&mr->sets[len]);
			set->booted_set = (idx == mr->booted_set);
			set->boot_set = (idx == mr->boot_set);
			TAILQ_INSERT_TAIL(&mdstore_sets, set, link);
			len += strlen(&mr->sets[len]) + 1;
			if (mdstore_major >= 2)
				len += sizeof(uint64_t); /* skip timestamp */
			if (mdstore_major >= 3)
				len += sizeof(uint8_t);	/* skip has_degraded */
		}
		break;
	}

	mdstore_command = 0;
}

void
mdstore_begin_v1(struct ds_conn *dc, uint64_t svc_handle, const char *name,
    int nmds)
{
	struct mdstore_begin_end_req *mr;
	size_t len = sizeof(*mr) + strlen(name);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
	mr->nmds = nmds;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_BEGIN_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_begin_v2(struct ds_conn *dc, uint64_t svc_handle, const char *name,
    int nmds, uint32_t config_size)
{
	struct mdstore_begin_req_v2 *mr;
	size_t len = sizeof(*mr) + strlen(name);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
	mr->config_size = config_size;
	mr->timestamp = time(NULL);
	mr->nmds = nmds;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_BEGIN_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_begin_v3(struct ds_conn *dc, uint64_t svc_handle, const char *name,
    int nmds, uint32_t config_size)
{
	struct mdstore_begin_req_v3 *mr;
	size_t len = sizeof(*mr) + strlen(name);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_BEGIN_REQUEST;
	mr->config_size = config_size;
	mr->timestamp = time(NULL);
	mr->degraded = CONFIG_NORMAL;
	mr->active_config = CONFIG_EXISTING;
	mr->nmds = nmds;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_BEGIN_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_begin(struct ds_conn *dc, uint64_t svc_handle, const char *name,
    int nmds, uint32_t config_size)
{
	if (mdstore_major == 3)
		mdstore_begin_v3(dc, svc_handle, name, nmds, config_size);
	else if (mdstore_major == 2)
		mdstore_begin_v2(dc, svc_handle, name, nmds, config_size);
	else
		mdstore_begin_v1(dc, svc_handle, name, nmds);
}

void
mdstore_transfer(struct ds_conn *dc, uint64_t svc_handle, const char *path,
    uint16_t type, uint64_t offset)
{
	struct mdstore_transfer_req *mr;
	uint32_t size;
	size_t len;
	FILE *fp;

	fp = fopen(path, "r");
	if (fp == NULL)
		err(1, "fopen");

	fseek(fp, 0, SEEK_END);
	size = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	len = sizeof(*mr) + size;
	mr = xzalloc(len);

	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MD_TRANSFER_REQUEST;
	mr->type = type;
	mr->size = size;
	mr->offset = offset;
	if (fread(&mr->md, size, 1, fp) != 1)
		err(1, "fread");
	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	fclose(fp);

	while (mdstore_command == MD_TRANSFER_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_end(struct ds_conn *dc, uint64_t svc_handle, const char *name,
    int nmds)
{
	struct mdstore_begin_end_req *mr;
	size_t len = sizeof(*mr) + strlen(name);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_END_REQUEST;
	mr->nmds = nmds;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_END_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_select(struct ds_conn *dc, const char *name)
{
	struct ds_conn_svc *dcs;
	struct mdstore_sel_del_req *mr;
	size_t len = sizeof(*mr) + strlen(name);

	TAILQ_FOREACH(dcs, &dc->services, link)
		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
		    dcs->svc_handle != 0)
			break;
	assert(dcs != NULL);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = dcs->svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_SELECT_REQUEST;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_SELECT_REQUEST)
		ds_conn_handle(dc);
}

void
mdstore_delete(struct ds_conn *dc, const char *name)
{
	struct ds_conn_svc *dcs;
	struct mdstore_sel_del_req *mr;
	size_t len = sizeof(*mr) + strlen(name);

	TAILQ_FOREACH(dcs, &dc->services, link)
		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
		    dcs->svc_handle != 0)
			break;
	assert(dcs != NULL);

	mr = xzalloc(len);
	mr->msg_type = DS_DATA;
	mr->payload_len = len - 8;
	mr->svc_handle = dcs->svc_handle;
	mr->reqnum = mdstore_reqnum++;
	mr->command = mdstore_command = MDSET_DELETE_REQUEST;
	mr->namelen = strlen(name);
	memcpy(mr->name, name, strlen(name));

	ds_send_msg(&dc->lc, mr, len);
	free(mr);

	while (mdstore_command == MDSET_DELETE_REQUEST)
		ds_conn_handle(dc);
}

void frag_init(void);
void add_frag_mblock(struct md_node *);
void add_frag(uint64_t);
void delete_frag(uint64_t);
uint64_t alloc_frag(void);

void
mdstore_download(struct ds_conn *dc, const char *name)
{
	struct ds_conn_svc *dcs;
	struct md_node *node;
	struct md_prop *prop;
	struct guest *guest;
	int nmds = 2;
	char *path;
	uint32_t total_size = 0;
	uint16_t type;

	TAILQ_FOREACH(dcs, &dc->services, link)
		if (strcmp(dcs->service->ds_svc_id, "mdstore") == 0 &&
		    dcs->svc_handle != 0)
			break;
	assert(dcs != NULL);

	if (asprintf(&path, "%s/hv.md", name) == -1)
		err(1, "asprintf");
	hvmd = md_read(path);
	free(path);

	if (hvmd == NULL)
		err(1, "%s", name);

	node = md_find_node(hvmd, "guests");
	TAILQ_INIT(&guest_list);
	TAILQ_FOREACH(prop, &node->prop_list, link) {
		if (prop->tag == MD_PROP_ARC &&
		    strcmp(prop->name->str, "fwd") == 0) {
			add_guest(prop->d.arc.node);
			nmds++;
		}
	}

	frag_init();
	hv_mdpa = alloc_frag();

	TAILQ_FOREACH(guest, &guest_list, link) {
		if (asprintf(&path, "%s/%s.md", name, guest->name) == -1)
			err(1, "asprintf");
		total_size += md_size(path);
	}
	if (asprintf(&path, "%s/hv.md", name) == -1)
		err(1, "asprintf");
	total_size += md_size(path);
	if (asprintf(&path, "%s/pri", name) == -1)
		err(1, "asprintf");
	total_size += md_size(path);

	mdstore_begin(dc, dcs->svc_handle, name, nmds, total_size);
	TAILQ_FOREACH(guest, &guest_list, link) {
		if (asprintf(&path, "%s/%s.md", name, guest->name) == -1)
			err(1, "asprintf");
		type = 0;
		if (strcmp(guest->name, "primary") == 0)
			type = MDSTORE_CTL_DOM_MD_TYPE;
		mdstore_transfer(dc, dcs->svc_handle, path, type, guest->mdpa);
		free(path);
	}
	if (asprintf(&path, "%s/hv.md", name) == -1)
		err(1, "asprintf");
	mdstore_transfer(dc, dcs->svc_handle, path,
	    MDSTORE_HV_MD_TYPE, hv_mdpa);
	free(path);
	if (asprintf(&path, "%s/pri", name) == -1)
		err(1, "asprintf");
	mdstore_transfer(dc, dcs->svc_handle, path,
	    MDSTORE_PRI_TYPE, 0);
	free(path);
	mdstore_end(dc, dcs->svc_handle, name, nmds);
}

struct frag {
	TAILQ_ENTRY(frag) link;
	uint64_t base;
};

TAILQ_HEAD(frag_head, frag) mdstore_frags;

uint64_t mdstore_fragsize;

void
frag_init(void)
{
	struct md_node *node;
	struct md_prop *prop;

	node = md_find_node(hvmd, "frag_space");
	md_get_prop_val(hvmd, node, "fragsize", &mdstore_fragsize);
	TAILQ_INIT(&mdstore_frags);
	TAILQ_FOREACH(prop, &node->prop_list, link) {
		if (prop->tag == MD_PROP_ARC &&
		    strcmp(prop->name->str, "fwd") == 0)
			add_frag_mblock(prop->d.arc.node);
	}
}

void
add_frag_mblock(struct md_node *node)
{
	uint64_t base, size;
	struct guest *guest;

	md_get_prop_val(hvmd, node, "base", &base);
	md_get_prop_val(hvmd, node, "size", &size);
	while (size > mdstore_fragsize) {
		add_frag(base);
		size -= mdstore_fragsize;
		base += mdstore_fragsize;
	}

	delete_frag(hv_mdpa);
	TAILQ_FOREACH(guest, &guest_list, link)
		delete_frag(guest->mdpa);
}

void
add_frag(uint64_t base)
{
	struct frag *frag;

	frag = xmalloc(sizeof(*frag));
	frag->base = base;
	TAILQ_INSERT_TAIL(&mdstore_frags, frag, link);
}

void
delete_frag(uint64_t base)
{
	struct frag *frag;
	struct frag *tmp;

	TAILQ_FOREACH_SAFE(frag, &mdstore_frags, link, tmp) {
		if (frag->base == base) {
			TAILQ_REMOVE(&mdstore_frags, frag, link);
			free(frag);
		}
	}
}

uint64_t
alloc_frag(void)
{
	struct frag *frag;
	uint64_t base;

	frag = TAILQ_FIRST(&mdstore_frags);
	if (frag == NULL)
		return -1;

	TAILQ_REMOVE(&mdstore_frags, frag, link);
	base = frag->base;
	free(frag);

	return base;
}