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;
}