mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Having a file backed data base has the only advantage of being capable to dump the contents of it while Xenstore is running, and potentially using less swap space in case the data base can't be kept in memory. It has the major disadvantage of a huge performance overhead: switching to keep the data base in memory only speeds up live update of xenstored with 120000 nodes from 20 minutes to 11 seconds. A complete tree walk of this configuration will be reduced from 7 seconds to 280 msecs (measured by "xenstore-control check"). So make the internal memory data base the default and enhance the "--internal-db" command line parameter to take an optional parameter allowing to switch the internal data base back to the file based one. This is part of XSA-419. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Julien Grall <jgrall@amazon.com>
575 lines
15 KiB
C
575 lines
15 KiB
C
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <xenctrl.h>
|
|
#include <xenguest.h>
|
|
#include <xenstore.h>
|
|
#include <xentoollog.h>
|
|
#include <xen/sys/xenbus_dev.h>
|
|
#include <xen-xsm/flask/flask.h>
|
|
#include <xen/io/xenbus.h>
|
|
|
|
#include "init-dom-json.h"
|
|
|
|
#define LAPIC_BASE_ADDRESS 0xfee00000UL
|
|
#define MB(x) ((uint64_t)x << 20)
|
|
#define GB(x) ((uint64_t)x << 30)
|
|
|
|
static uint32_t domid = ~0;
|
|
static char *kernel;
|
|
static char *ramdisk;
|
|
static char *flask;
|
|
static char *param;
|
|
static char *name = "Xenstore";
|
|
static int memory;
|
|
static int maxmem;
|
|
static xen_pfn_t console_gfn;
|
|
static xc_evtchn_port_or_error_t console_evtchn;
|
|
|
|
static struct option options[] = {
|
|
{ "kernel", 1, NULL, 'k' },
|
|
{ "memory", 1, NULL, 'm' },
|
|
{ "flask", 1, NULL, 'f' },
|
|
{ "ramdisk", 1, NULL, 'r' },
|
|
{ "param", 1, NULL, 'p' },
|
|
{ "name", 1, NULL, 'n' },
|
|
{ "maxmem", 1, NULL, 'M' },
|
|
{ "verbose", 0, NULL, 'v' },
|
|
{ NULL, 0, NULL, 0 }
|
|
};
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage:\n"
|
|
"\n"
|
|
"init-xenstore-domain <options>\n"
|
|
"\n"
|
|
"where options may include:\n"
|
|
"\n"
|
|
" --kernel <xenstore-kernel> kernel file of the xenstore domain, mandatory\n"
|
|
" --memory <memory size> size of the domain in MB, mandatory\n"
|
|
" --flask <flask-label> optional flask label of the domain\n"
|
|
" --ramdisk <ramdisk-file> optional ramdisk file for the domain\n"
|
|
" --param <cmdline> optional additional parameters for the domain\n"
|
|
" --name <name> name of the domain (default: Xenstore)\n"
|
|
" --maxmem <max size> maximum memory size in the format:\n"
|
|
" <MB val>|<a>/<b>|<MB val>:<a>/<b>\n"
|
|
" (an absolute value in MB, a fraction a/b of\n"
|
|
" the host memory, or the maximum of both)\n"
|
|
" -v[v[v]] verbosity of domain building\n");
|
|
}
|
|
|
|
static int build(xc_interface *xch)
|
|
{
|
|
char cmdline[512];
|
|
int rv, xs_fd;
|
|
struct xc_dom_image *dom = NULL;
|
|
int limit_kb = (maxmem ? : memory) * 1024 + X86_HVM_NR_SPECIAL_PAGES * 4;
|
|
uint64_t mem_size = MB(memory);
|
|
uint64_t max_size = MB(maxmem ? : memory);
|
|
struct e820entry e820[3];
|
|
struct xen_domctl_createdomain config = {
|
|
.ssidref = SECINITSID_DOMU,
|
|
.flags = XEN_DOMCTL_CDF_xs_domain,
|
|
.max_vcpus = 1,
|
|
.max_evtchn_port = -1, /* No limit. */
|
|
|
|
/*
|
|
* 1 grant frame is enough: we don't need many grants.
|
|
* Mini-OS doesn't like less than 4, though, so use 4.
|
|
* 128 maptrack frames: 256 entries per frame, enough for 32768 domains.
|
|
* Currently Mini-OS only supports grant v1.
|
|
*/
|
|
.max_grant_frames = 4,
|
|
.max_maptrack_frames = 128,
|
|
.grant_opts = XEN_DOMCTL_GRANT_version(1),
|
|
};
|
|
|
|
xs_fd = open("/dev/xen/xenbus_backend", O_RDWR);
|
|
if ( xs_fd == -1 )
|
|
{
|
|
fprintf(stderr, "Could not open /dev/xen/xenbus_backend\n");
|
|
return -1;
|
|
}
|
|
|
|
if ( flask )
|
|
{
|
|
rv = xc_flask_context_to_sid(xch, flask, strlen(flask), &config.ssidref);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_flask_context_to_sid failed\n");
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
dom = xc_dom_allocate(xch, NULL, NULL);
|
|
if ( !dom )
|
|
{
|
|
fprintf(stderr, "xc_dom_allocate failed\n");
|
|
rv = -1;
|
|
goto err;
|
|
}
|
|
|
|
rv = xc_dom_kernel_file(dom, kernel);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_kernel_file failed\n");
|
|
goto err;
|
|
}
|
|
|
|
if ( ramdisk )
|
|
{
|
|
rv = xc_dom_module_file(dom, ramdisk, NULL);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_module_file failed\n");
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
rv = xc_dom_boot_xen_init(dom, xch, domid);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_boot_xen_init failed\n");
|
|
goto err;
|
|
}
|
|
|
|
dom->container_type = XC_DOM_HVM_CONTAINER;
|
|
rv = xc_dom_parse_image(dom);
|
|
if ( rv )
|
|
{
|
|
dom->container_type = XC_DOM_PV_CONTAINER;
|
|
rv = xc_dom_parse_image(dom);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_parse_image failed\n");
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config.flags |= XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap;
|
|
config.arch.emulation_flags = XEN_X86_EMU_LAPIC;
|
|
dom->target_pages = mem_size >> XC_PAGE_SHIFT;
|
|
dom->mmio_size = GB(4) - LAPIC_BASE_ADDRESS;
|
|
dom->lowmem_end = (mem_size > LAPIC_BASE_ADDRESS) ?
|
|
LAPIC_BASE_ADDRESS : mem_size;
|
|
dom->highmem_end = (mem_size > LAPIC_BASE_ADDRESS) ?
|
|
GB(4) + mem_size - LAPIC_BASE_ADDRESS : 0;
|
|
dom->mmio_start = LAPIC_BASE_ADDRESS;
|
|
dom->max_vcpus = 1;
|
|
e820[0].addr = 0;
|
|
e820[0].size = (max_size > LAPIC_BASE_ADDRESS) ?
|
|
LAPIC_BASE_ADDRESS : max_size;
|
|
e820[0].type = E820_RAM;
|
|
e820[1].addr = (X86_HVM_END_SPECIAL_REGION -
|
|
X86_HVM_NR_SPECIAL_PAGES) << XC_PAGE_SHIFT;
|
|
e820[1].size = X86_HVM_NR_SPECIAL_PAGES << XC_PAGE_SHIFT;
|
|
e820[1].type = E820_RESERVED;
|
|
e820[2].addr = GB(4);
|
|
e820[2].size = (max_size > LAPIC_BASE_ADDRESS) ?
|
|
max_size - LAPIC_BASE_ADDRESS : 0;
|
|
e820[2].type = E820_RAM;
|
|
}
|
|
|
|
rv = xc_domain_create(xch, &domid, &config);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_create failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_domain_max_vcpus(xch, domid, config.max_vcpus);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_max_vcpus failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_domain_setmaxmem(xch, domid, limit_kb);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_setmaxmem failed\n");
|
|
goto err;
|
|
}
|
|
console_evtchn = xc_evtchn_alloc_unbound(xch, domid, 0);
|
|
if ( console_evtchn < 0 )
|
|
{
|
|
fprintf(stderr, "xc_evtchn_alloc_unbound failed\n");
|
|
goto err;
|
|
}
|
|
|
|
if ( dom->container_type == XC_DOM_PV_CONTAINER )
|
|
{
|
|
rv = xc_domain_set_memmap_limit(xch, domid, limit_kb);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_set_memmap_limit failed\n");
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
rv = ioctl(xs_fd, IOCTL_XENBUS_BACKEND_SETUP, domid);
|
|
if ( rv < 0 )
|
|
{
|
|
fprintf(stderr, "Xenbus setup ioctl failed\n");
|
|
goto err;
|
|
}
|
|
|
|
if ( param )
|
|
snprintf(cmdline, 512, "--event %d %s", rv, param);
|
|
else
|
|
snprintf(cmdline, 512, "--event %d", rv);
|
|
|
|
dom->guest_domid = domid;
|
|
dom->cmdline = xc_dom_strdup(dom, cmdline);
|
|
dom->xenstore_domid = domid;
|
|
dom->console_evtchn = console_evtchn;
|
|
|
|
rv = xc_dom_mem_init(dom, memory);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_mem_init failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_dom_boot_mem_init(dom);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_boot_mem_init failed\n");
|
|
goto err;
|
|
}
|
|
if ( dom->container_type == XC_DOM_HVM_CONTAINER )
|
|
{
|
|
rv = xc_domain_set_memory_map(xch, domid, e820,
|
|
dom->highmem_end ? 3 : 2);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_set_memory_map failed\n");
|
|
goto err;
|
|
}
|
|
}
|
|
rv = xc_dom_build_image(dom);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_build_image failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_dom_boot_image(dom);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_boot_image failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_dom_gnttab_init(dom);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_dom_gnttab_init failed\n");
|
|
goto err;
|
|
}
|
|
|
|
rv = xc_domain_set_virq_handler(xch, domid, VIRQ_DOM_EXC);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_set_virq_handler failed\n");
|
|
goto err;
|
|
}
|
|
rv = xc_domain_unpause(xch, domid);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_domain_unpause failed\n");
|
|
goto err;
|
|
}
|
|
|
|
rv = 0;
|
|
console_gfn = (dom->container_type == XC_DOM_PV_CONTAINER)
|
|
? xc_dom_p2m(dom, dom->console_pfn)
|
|
: dom->console_pfn;
|
|
|
|
err:
|
|
if ( dom )
|
|
xc_dom_release(dom);
|
|
if ( xs_fd >= 0 )
|
|
close(xs_fd);
|
|
|
|
/* if we failed then destroy the domain */
|
|
if ( rv && domid != ~0 )
|
|
xc_domain_destroy(xch, domid);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int check_domain(xc_interface *xch)
|
|
{
|
|
xc_dominfo_t info;
|
|
uint32_t dom;
|
|
int ret;
|
|
|
|
dom = 1;
|
|
while ( (ret = xc_domain_getinfo(xch, dom, 1, &info)) == 1 )
|
|
{
|
|
if ( info.xenstore )
|
|
return 1;
|
|
dom = info.domid + 1;
|
|
}
|
|
if ( ret < 0 && errno != ESRCH )
|
|
{
|
|
fprintf(stderr, "xc_domain_getinfo failed\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_maxmem(xc_interface *xch, char *str)
|
|
{
|
|
xc_physinfo_t info;
|
|
int rv;
|
|
unsigned long mb = 0, a = 0, b = 0;
|
|
unsigned long val;
|
|
unsigned long *res;
|
|
char *p;
|
|
char *s = str;
|
|
|
|
rv = xc_physinfo(xch, &info);
|
|
if ( rv )
|
|
{
|
|
fprintf(stderr, "xc_physinfo failed\n");
|
|
return -1;
|
|
}
|
|
|
|
res = &mb;
|
|
for (p = s; *p; s = p + 1)
|
|
{
|
|
val = strtoul(s, &p, 10);
|
|
if ( val == 0 || val >= INT_MAX / 1024 )
|
|
goto err;
|
|
if ( *p == '/' )
|
|
{
|
|
if ( res != &mb || a != 0 )
|
|
goto err;
|
|
a = val;
|
|
res = &b;
|
|
continue;
|
|
}
|
|
if ( *res != 0 )
|
|
goto err;
|
|
*res = val;
|
|
if ( *p != 0 && *p != ':' )
|
|
goto err;
|
|
res = &mb;
|
|
}
|
|
if ( a && !b )
|
|
goto err;
|
|
|
|
val = a ? info.total_pages * a / (b * 1024 * 1024 / XC_PAGE_SIZE) : 0;
|
|
if ( val >= INT_MAX / 1024 )
|
|
goto err;
|
|
|
|
maxmem = mb < val ? val : mb;
|
|
if ( maxmem < memory )
|
|
maxmem = 0;
|
|
|
|
return maxmem;
|
|
|
|
err:
|
|
fprintf(stderr, "illegal value for maxmem: %s\n", str);
|
|
return -1;
|
|
}
|
|
|
|
static void do_xs_write(struct xs_handle *xsh, char *path, char *val)
|
|
{
|
|
if ( !xs_write(xsh, XBT_NULL, path, val, strlen(val)) )
|
|
fprintf(stderr, "writing %s to xenstore failed.\n", path);
|
|
}
|
|
|
|
static void do_xs_write_dir_node(struct xs_handle *xsh, char *dir, char *node,
|
|
char *val)
|
|
{
|
|
char full_path[100];
|
|
|
|
snprintf(full_path, 100, "%s/%s", dir, node);
|
|
do_xs_write(xsh, full_path, val);
|
|
}
|
|
|
|
static void do_xs_write_dom(struct xs_handle *xsh, char *path, char *val)
|
|
{
|
|
char full_path[64];
|
|
|
|
snprintf(full_path, 64, "/local/domain/%d/%s", domid, path);
|
|
do_xs_write(xsh, full_path, val);
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int opt;
|
|
xc_interface *xch;
|
|
struct xs_handle *xsh;
|
|
char buf[16], be_path[64], fe_path[64];
|
|
int rv, fd;
|
|
char *maxmem_str = NULL;
|
|
xentoollog_level minmsglevel = XTL_PROGRESS;
|
|
xentoollog_logger *logger = NULL;
|
|
|
|
while ( (opt = getopt_long(argc, argv, "v", options, NULL)) != -1 )
|
|
{
|
|
switch ( opt )
|
|
{
|
|
case 'k':
|
|
kernel = optarg;
|
|
break;
|
|
case 'm':
|
|
memory = strtol(optarg, NULL, 10);
|
|
break;
|
|
case 'f':
|
|
flask = optarg;
|
|
break;
|
|
case 'r':
|
|
ramdisk = optarg;
|
|
break;
|
|
case 'p':
|
|
param = optarg;
|
|
break;
|
|
case 'n':
|
|
name = optarg;
|
|
break;
|
|
case 'M':
|
|
maxmem_str = optarg;
|
|
break;
|
|
case 'v':
|
|
if ( minmsglevel )
|
|
minmsglevel--;
|
|
break;
|
|
default:
|
|
usage();
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
if ( optind != argc || !kernel || !memory )
|
|
{
|
|
usage();
|
|
return 2;
|
|
}
|
|
|
|
logger = (xentoollog_logger *)xtl_createlogger_stdiostream(stderr,
|
|
minmsglevel, 0);
|
|
|
|
xch = xc_interface_open(logger, logger, 0);
|
|
if ( !xch )
|
|
{
|
|
fprintf(stderr, "xc_interface_open() failed\n");
|
|
rv = 1;
|
|
goto out;
|
|
}
|
|
|
|
if ( maxmem_str )
|
|
{
|
|
maxmem = parse_maxmem(xch, maxmem_str);
|
|
if ( maxmem < 0 )
|
|
{
|
|
xc_interface_close(xch);
|
|
rv = 1;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
rv = check_domain(xch);
|
|
|
|
if ( !rv )
|
|
rv = build(xch);
|
|
else if ( rv > 0 )
|
|
fprintf(stderr, "xenstore domain already present.\n");
|
|
|
|
xc_interface_close(xch);
|
|
|
|
if ( rv )
|
|
{
|
|
rv = 1;
|
|
goto out;
|
|
}
|
|
|
|
rv = gen_stub_json_config(domid, NULL);
|
|
if ( rv )
|
|
{
|
|
rv = 3;
|
|
goto out;
|
|
}
|
|
|
|
xsh = xs_open(0);
|
|
if ( !xsh )
|
|
{
|
|
fprintf(stderr, "xs_open() failed.\n");
|
|
rv = 3;
|
|
goto out;
|
|
}
|
|
snprintf(buf, 16, "%d", domid);
|
|
do_xs_write(xsh, "/tool/xenstored/domid", buf);
|
|
do_xs_write_dom(xsh, "domid", buf);
|
|
do_xs_write_dom(xsh, "name", name);
|
|
snprintf(buf, 16, "%d", memory * 1024);
|
|
do_xs_write_dom(xsh, "memory/target", buf);
|
|
if (maxmem)
|
|
snprintf(buf, 16, "%d", maxmem * 1024);
|
|
do_xs_write_dom(xsh, "memory/static-max", buf);
|
|
snprintf(be_path, 64, "/local/domain/0/backend/console/%d/0", domid);
|
|
snprintf(fe_path, 64, "/local/domain/%d/console", domid);
|
|
snprintf(buf, 16, "%d", domid);
|
|
do_xs_write_dir_node(xsh, be_path, "frontend-id", buf);
|
|
do_xs_write_dir_node(xsh, be_path, "frontend", fe_path);
|
|
do_xs_write_dir_node(xsh, be_path, "online", "1");
|
|
snprintf(buf, 16, "%d", XenbusStateInitialising);
|
|
do_xs_write_dir_node(xsh, be_path, "state", buf);
|
|
do_xs_write_dir_node(xsh, be_path, "protocol", "vt100");
|
|
do_xs_write_dir_node(xsh, fe_path, "backend", be_path);
|
|
do_xs_write_dir_node(xsh, fe_path, "backend-id", "0");
|
|
do_xs_write_dir_node(xsh, fe_path, "limit", "1048576");
|
|
do_xs_write_dir_node(xsh, fe_path, "type", "xenconsoled");
|
|
do_xs_write_dir_node(xsh, fe_path, "output", "pty");
|
|
do_xs_write_dir_node(xsh, fe_path, "tty", "");
|
|
snprintf(buf, 16, "%d", console_evtchn);
|
|
do_xs_write_dir_node(xsh, fe_path, "port", buf);
|
|
snprintf(buf, 16, "%ld", console_gfn);
|
|
do_xs_write_dir_node(xsh, fe_path, "ring-ref", buf);
|
|
xs_close(xsh);
|
|
|
|
fd = creat(XEN_RUN_DIR "/xenstored.pid", 0666);
|
|
if ( fd < 0 )
|
|
{
|
|
fprintf(stderr, "Creating " XEN_RUN_DIR "/xenstored.pid failed\n");
|
|
rv = 3;
|
|
goto out;
|
|
}
|
|
rv = snprintf(buf, 16, "domid:%d\n", domid);
|
|
rv = write(fd, buf, rv);
|
|
close(fd);
|
|
if ( rv < 0 )
|
|
{
|
|
fprintf(stderr,
|
|
"Writing domid to " XEN_RUN_DIR "/xenstored.pid failed\n");
|
|
rv = 3;
|
|
goto out;
|
|
}
|
|
|
|
rv = 0;
|
|
|
|
out:
|
|
if ( logger )
|
|
xtl_logger_destroy(logger);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|