mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
When the console is connected to a domain other than dom0, the console device's backend field should be set so the xenstore permissions for the console device reflect the domain that will be accessing them. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
1252 lines
42 KiB
C
1252 lines
42 KiB
C
/*
|
|
* Copyright (C) 2010 Citrix Ltd.
|
|
* Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
|
|
* Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
|
|
* Author Gianni Tedesco <gianni.tedesco@citrix.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; version 2.1 only. with the special
|
|
* exception on linking described in file LICENSE.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*/
|
|
|
|
#include "libxl_osdeps.h" /* must come before any other headers */
|
|
|
|
#include "libxl_internal.h"
|
|
#include "libxl_arch.h"
|
|
|
|
#include <xc_dom.h>
|
|
#include <xenguest.h>
|
|
#include <xen/hvm/hvm_info_table.h>
|
|
|
|
int libxl__domain_create_info_setdefault(libxl__gc *gc,
|
|
libxl_domain_create_info *c_info)
|
|
{
|
|
if (!c_info->type)
|
|
return ERROR_INVAL;
|
|
|
|
if (c_info->type == LIBXL_DOMAIN_TYPE_HVM) {
|
|
libxl_defbool_setdefault(&c_info->hap, true);
|
|
libxl_defbool_setdefault(&c_info->oos, true);
|
|
}
|
|
|
|
libxl_defbool_setdefault(&c_info->run_hotplug_scripts, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sched_params_valid(libxl__gc *gc,
|
|
uint32_t domid, libxl_domain_sched_params *scp)
|
|
{
|
|
int has_weight = scp->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT;
|
|
int has_period = scp->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT;
|
|
int has_slice = scp->slice != LIBXL_DOMAIN_SCHED_PARAM_SLICE_DEFAULT;
|
|
int has_extratime =
|
|
scp->extratime != LIBXL_DOMAIN_SCHED_PARAM_EXTRATIME_DEFAULT;
|
|
|
|
/* The sedf scheduler needs some more consistency checking */
|
|
if (libxl__domain_scheduler(gc, domid) == LIBXL_SCHEDULER_SEDF) {
|
|
if (has_weight && (has_period || has_slice))
|
|
return 0;
|
|
/* If you want a real-time domain, with its own period and
|
|
* slice, please, do provide both! */
|
|
if (has_period != has_slice)
|
|
return 0;
|
|
|
|
/*
|
|
* Idea is, if we specify a weight, then both period and
|
|
* slice has to be zero. OTOH, if we do specify a period and
|
|
* slice, it is weight that should be zeroed. See
|
|
* docs/misc/sedf_scheduler_mini-HOWTO.txt for more details
|
|
* on the meaningful combinations and their meanings.
|
|
*/
|
|
if (has_weight) {
|
|
scp->slice = 0;
|
|
scp->period = 0;
|
|
}
|
|
else if (!has_period) {
|
|
/* No weight nor slice/period means best effort. Parameters needs
|
|
* some mangling in order to properly ask for that, though. */
|
|
|
|
/*
|
|
* Providing no weight does not make any sense if we do not allow
|
|
* the domain to run in extra time. On the other hand, if we have
|
|
* extra time, weight will be ignored (and zeroed) by Xen, but it
|
|
* can't be zero here, or the call for setting the scheduling
|
|
* parameters will fail. So, avoid the latter by setting a random
|
|
* weight (namely, 1), as it will be ignored anyway.
|
|
*/
|
|
|
|
/* We can setup a proper best effort domain (extra time only)
|
|
* iff we either already have or are asking for some extra time. */
|
|
scp->weight = has_extratime ? scp->extratime : 1;
|
|
scp->period = 0;
|
|
} else {
|
|
/* Real-time domain: will get slice CPU time over every period */
|
|
scp->weight = 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int libxl__domain_build_info_setdefault(libxl__gc *gc,
|
|
libxl_domain_build_info *b_info)
|
|
{
|
|
if (b_info->type != LIBXL_DOMAIN_TYPE_HVM &&
|
|
b_info->type != LIBXL_DOMAIN_TYPE_PV)
|
|
return ERROR_INVAL;
|
|
|
|
libxl_defbool_setdefault(&b_info->device_model_stubdomain, false);
|
|
|
|
if (!b_info->device_model_version) {
|
|
if (b_info->type == LIBXL_DOMAIN_TYPE_HVM)
|
|
b_info->device_model_version =
|
|
LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
|
|
else {
|
|
const char *dm;
|
|
int rc;
|
|
|
|
b_info->device_model_version =
|
|
LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
|
|
dm = libxl__domain_device_model(gc, b_info);
|
|
rc = access(dm, X_OK);
|
|
if (rc < 0) {
|
|
/* qemu-xen unavailable, use qemu-xen-traditional */
|
|
if (errno == ENOENT) {
|
|
LIBXL__LOG_ERRNO(CTX, XTL_VERBOSE, "qemu-xen is unavailable"
|
|
", use qemu-xen-traditional instead");
|
|
b_info->device_model_version =
|
|
LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
|
|
} else {
|
|
LIBXL__LOG_ERRNO(CTX, XTL_ERROR, "qemu-xen access error");
|
|
return ERROR_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (b_info->blkdev_start == NULL)
|
|
b_info->blkdev_start = libxl__strdup(NOGC, "xvda");
|
|
|
|
if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) {
|
|
if (!b_info->u.hvm.bios)
|
|
switch (b_info->device_model_version) {
|
|
case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
|
|
b_info->u.hvm.bios = LIBXL_BIOS_TYPE_ROMBIOS; break;
|
|
case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
|
|
b_info->u.hvm.bios = LIBXL_BIOS_TYPE_SEABIOS; break;
|
|
default:return ERROR_INVAL;
|
|
}
|
|
|
|
/* Enforce BIOS<->Device Model version relationship */
|
|
switch (b_info->device_model_version) {
|
|
case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
|
|
if (b_info->u.hvm.bios != LIBXL_BIOS_TYPE_ROMBIOS)
|
|
return ERROR_INVAL;
|
|
break;
|
|
case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
|
|
if (b_info->u.hvm.bios == LIBXL_BIOS_TYPE_ROMBIOS)
|
|
return ERROR_INVAL;
|
|
break;
|
|
default:abort();
|
|
}
|
|
}
|
|
|
|
if (b_info->type == LIBXL_DOMAIN_TYPE_HVM &&
|
|
b_info->device_model_version !=
|
|
LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL &&
|
|
libxl_defbool_val(b_info->device_model_stubdomain)) {
|
|
LIBXL__LOG(CTX, XTL_ERROR,
|
|
"device model stubdomains require \"qemu-xen-traditional\"");
|
|
return ERROR_INVAL;
|
|
}
|
|
|
|
if (!b_info->max_vcpus)
|
|
b_info->max_vcpus = 1;
|
|
if (!b_info->avail_vcpus.size) {
|
|
if (libxl_cpu_bitmap_alloc(CTX, &b_info->avail_vcpus, 1))
|
|
return ERROR_FAIL;
|
|
libxl_bitmap_set(&b_info->avail_vcpus, 0);
|
|
} else if (b_info->avail_vcpus.size > HVM_MAX_VCPUS)
|
|
return ERROR_FAIL;
|
|
|
|
if (!b_info->cpumap.size) {
|
|
if (libxl_cpu_bitmap_alloc(CTX, &b_info->cpumap, 0))
|
|
return ERROR_FAIL;
|
|
libxl_bitmap_set_any(&b_info->cpumap);
|
|
}
|
|
|
|
libxl_defbool_setdefault(&b_info->numa_placement, true);
|
|
|
|
if (b_info->max_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->max_memkb = 32 * 1024;
|
|
if (b_info->target_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->target_memkb = b_info->max_memkb;
|
|
|
|
libxl_defbool_setdefault(&b_info->localtime, false);
|
|
|
|
libxl_defbool_setdefault(&b_info->disable_migrate, false);
|
|
|
|
switch (b_info->type) {
|
|
case LIBXL_DOMAIN_TYPE_HVM:
|
|
if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->shadow_memkb = 0;
|
|
if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->video_memkb = 8 * 1024;
|
|
if (b_info->u.hvm.timer_mode == LIBXL_TIMER_MODE_DEFAULT)
|
|
b_info->u.hvm.timer_mode =
|
|
LIBXL_TIMER_MODE_NO_DELAY_FOR_MISSED_TICKS;
|
|
|
|
libxl_defbool_setdefault(&b_info->u.hvm.pae, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.apic, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.acpi, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.acpi_s3, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.acpi_s4, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.nx, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.viridian, false);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.hpet, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.vpt_align, true);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.nested_hvm, false);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.usb, false);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.xen_platform_pci, true);
|
|
|
|
if (!b_info->u.hvm.boot) {
|
|
b_info->u.hvm.boot = strdup("cda");
|
|
if (!b_info->u.hvm.boot) return ERROR_NOMEM;
|
|
}
|
|
|
|
if (!b_info->u.hvm.vga.kind)
|
|
b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
|
|
libxl_defbool_setdefault(&b_info->u.hvm.vnc.enable, true);
|
|
if (libxl_defbool_val(b_info->u.hvm.vnc.enable)) {
|
|
libxl_defbool_setdefault(&b_info->u.hvm.vnc.findunused, true);
|
|
if (!b_info->u.hvm.vnc.listen) {
|
|
b_info->u.hvm.vnc.listen = strdup("127.0.0.1");
|
|
if (!b_info->u.hvm.vnc.listen) return ERROR_NOMEM;
|
|
}
|
|
}
|
|
|
|
libxl_defbool_setdefault(&b_info->u.hvm.sdl.enable, false);
|
|
if (libxl_defbool_val(b_info->u.hvm.sdl.enable)) {
|
|
libxl_defbool_setdefault(&b_info->u.hvm.sdl.opengl, false);
|
|
}
|
|
|
|
libxl_defbool_setdefault(&b_info->u.hvm.spice.enable, false);
|
|
if (libxl_defbool_val(b_info->u.hvm.spice.enable)) {
|
|
libxl_defbool_setdefault(&b_info->u.hvm.spice.disable_ticketing,
|
|
false);
|
|
libxl_defbool_setdefault(&b_info->u.hvm.spice.agent_mouse, true);
|
|
}
|
|
|
|
libxl_defbool_setdefault(&b_info->u.hvm.nographic, false);
|
|
|
|
libxl_defbool_setdefault(&b_info->u.hvm.gfx_passthru, false);
|
|
|
|
break;
|
|
case LIBXL_DOMAIN_TYPE_PV:
|
|
libxl_defbool_setdefault(&b_info->u.pv.e820_host, false);
|
|
if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->shadow_memkb = 0;
|
|
if (b_info->u.pv.slack_memkb == LIBXL_MEMKB_DEFAULT)
|
|
b_info->u.pv.slack_memkb = 0;
|
|
break;
|
|
default:
|
|
LIBXL__LOG(CTX, LIBXL__LOG_ERROR,
|
|
"invalid domain type %s in create info",
|
|
libxl_domain_type_to_string(b_info->type));
|
|
return ERROR_INVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int init_console_info(libxl__device_console *console, int dev_num)
|
|
{
|
|
memset(console, 0x00, sizeof(libxl__device_console));
|
|
console->devid = dev_num;
|
|
console->consback = LIBXL__CONSOLE_BACKEND_XENCONSOLED;
|
|
console->output = strdup("pty");
|
|
if (!console->output)
|
|
return ERROR_NOMEM;
|
|
return 0;
|
|
}
|
|
|
|
int libxl__domain_build(libxl__gc *gc,
|
|
libxl_domain_build_info *info,
|
|
uint32_t domid,
|
|
libxl__domain_build_state *state)
|
|
{
|
|
char **vments = NULL, **localents = NULL;
|
|
struct timeval start_time;
|
|
int i, ret;
|
|
|
|
ret = libxl__build_pre(gc, domid, info, state);
|
|
if (ret)
|
|
goto out;
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
switch (info->type) {
|
|
case LIBXL_DOMAIN_TYPE_HVM:
|
|
ret = libxl__build_hvm(gc, domid, info, state);
|
|
if (ret)
|
|
goto out;
|
|
|
|
vments = libxl__calloc(gc, 7, sizeof(char *));
|
|
vments[0] = "rtc/timeoffset";
|
|
vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
|
|
vments[2] = "image/ostype";
|
|
vments[3] = "hvm";
|
|
vments[4] = "start_time";
|
|
vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
|
|
|
|
localents = libxl__calloc(gc, 7, sizeof(char *));
|
|
localents[0] = "platform/acpi";
|
|
localents[1] = libxl_defbool_val(info->u.hvm.acpi) ? "1" : "0";
|
|
localents[2] = "platform/acpi_s3";
|
|
localents[3] = libxl_defbool_val(info->u.hvm.acpi_s3) ? "1" : "0";
|
|
localents[4] = "platform/acpi_s4";
|
|
localents[5] = libxl_defbool_val(info->u.hvm.acpi_s4) ? "1" : "0";
|
|
|
|
break;
|
|
case LIBXL_DOMAIN_TYPE_PV:
|
|
ret = libxl__build_pv(gc, domid, info, state);
|
|
if (ret)
|
|
goto out;
|
|
|
|
vments = libxl__calloc(gc, 11, sizeof(char *));
|
|
i = 0;
|
|
vments[i++] = "image/ostype";
|
|
vments[i++] = "linux";
|
|
vments[i++] = "image/kernel";
|
|
vments[i++] = (char *) state->pv_kernel.path;
|
|
vments[i++] = "start_time";
|
|
vments[i++] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
|
|
if (state->pv_ramdisk.path) {
|
|
vments[i++] = "image/ramdisk";
|
|
vments[i++] = (char *) state->pv_ramdisk.path;
|
|
}
|
|
if (state->pv_cmdline) {
|
|
vments[i++] = "image/cmdline";
|
|
vments[i++] = (char *) state->pv_cmdline;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
ret = ERROR_INVAL;
|
|
goto out;
|
|
}
|
|
ret = libxl__build_post(gc, domid, info, state, vments, localents);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info,
|
|
uint32_t *domid)
|
|
{
|
|
libxl_ctx *ctx = libxl__gc_owner(gc);
|
|
int flags, ret, rc, nb_vm;
|
|
char *uuid_string;
|
|
char *dom_path, *vm_path, *libxl_path;
|
|
struct xs_permissions roperm[2];
|
|
struct xs_permissions rwperm[1];
|
|
struct xs_permissions noperm[1];
|
|
xs_transaction_t t = 0;
|
|
xen_domain_handle_t handle;
|
|
libxl_vminfo *vm_list;
|
|
|
|
|
|
assert(!libxl_domid_valid_guest(*domid));
|
|
|
|
uuid_string = libxl__uuid2string(gc, info->uuid);
|
|
if (!uuid_string) {
|
|
rc = ERROR_NOMEM;
|
|
goto out;
|
|
}
|
|
|
|
flags = 0;
|
|
if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
|
|
flags |= XEN_DOMCTL_CDF_hvm_guest;
|
|
flags |= libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0;
|
|
flags |= libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off;
|
|
}
|
|
*domid = -1;
|
|
|
|
/* Ultimately, handle is an array of 16 uint8_t, same as uuid */
|
|
libxl_uuid_copy((libxl_uuid *)handle, &info->uuid);
|
|
|
|
ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
|
|
if (ret < 0) {
|
|
LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
|
|
if (ret < 0) {
|
|
LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
dom_path = libxl__xs_get_dompath(gc, *domid);
|
|
if (!dom_path) {
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string);
|
|
if (!vm_path) {
|
|
LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
libxl_path = libxl__xs_libxl_path(gc, *domid);
|
|
if (!libxl_path) {
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
noperm[0].id = 0;
|
|
noperm[0].perms = XS_PERM_NONE;
|
|
|
|
roperm[0].id = 0;
|
|
roperm[0].perms = XS_PERM_NONE;
|
|
roperm[1].id = *domid;
|
|
roperm[1].perms = XS_PERM_READ;
|
|
|
|
rwperm[0].id = *domid;
|
|
rwperm[0].perms = XS_PERM_NONE;
|
|
|
|
retry_transaction:
|
|
t = xs_transaction_start(ctx->xsh);
|
|
|
|
xs_rm(ctx->xsh, t, dom_path);
|
|
libxl__xs_mkdir(gc, t, dom_path, roperm, ARRAY_SIZE(roperm));
|
|
|
|
xs_rm(ctx->xsh, t, vm_path);
|
|
libxl__xs_mkdir(gc, t, vm_path, roperm, ARRAY_SIZE(roperm));
|
|
|
|
xs_rm(ctx->xsh, t, libxl_path);
|
|
libxl__xs_mkdir(gc, t, libxl_path, noperm, ARRAY_SIZE(noperm));
|
|
|
|
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
|
|
rc = libxl__domain_rename(gc, *domid, 0, info->name, t);
|
|
if (rc)
|
|
goto out;
|
|
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/cpu", dom_path),
|
|
roperm, ARRAY_SIZE(roperm));
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/memory", dom_path),
|
|
roperm, ARRAY_SIZE(roperm));
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/device", dom_path),
|
|
roperm, ARRAY_SIZE(roperm));
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/control", dom_path),
|
|
roperm, ARRAY_SIZE(roperm));
|
|
if (info->type == LIBXL_DOMAIN_TYPE_HVM)
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/hvmloader", dom_path),
|
|
roperm, ARRAY_SIZE(roperm));
|
|
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/control/shutdown", dom_path),
|
|
rwperm, ARRAY_SIZE(rwperm));
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/device/suspend/event-channel", dom_path),
|
|
rwperm, ARRAY_SIZE(rwperm));
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/data", dom_path),
|
|
rwperm, ARRAY_SIZE(rwperm));
|
|
if (info->type == LIBXL_DOMAIN_TYPE_HVM)
|
|
libxl__xs_mkdir(gc, t,
|
|
libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path),
|
|
rwperm, ARRAY_SIZE(rwperm));
|
|
|
|
vm_list = libxl_list_vm(ctx, &nb_vm);
|
|
if (!vm_list) {
|
|
LOG(ERROR, "cannot get number of running guests");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
libxl_vminfo_list_free(vm_list, nb_vm);
|
|
int hotplug_setting = libxl__hotplug_settings(gc, t);
|
|
if (hotplug_setting < 0) {
|
|
LOG(ERROR, "unable to get current hotplug scripts execution setting");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
if (libxl_defbool_val(info->run_hotplug_scripts) != hotplug_setting &&
|
|
(nb_vm - 1)) {
|
|
LOG(ERROR, "cannot change hotplug execution option once set, "
|
|
"please shutdown all guests before changing it");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
if (libxl_defbool_val(info->run_hotplug_scripts)) {
|
|
rc = libxl__xs_write_checked(gc, t, DISABLE_UDEV_PATH, "1");
|
|
if (rc) {
|
|
LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH);
|
|
goto out;
|
|
}
|
|
} else {
|
|
rc = libxl__xs_rm_checked(gc, t, DISABLE_UDEV_PATH);
|
|
if (rc) {
|
|
LOGE(ERROR, "unable to delete %s", DISABLE_UDEV_PATH);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
|
|
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name));
|
|
|
|
libxl__xs_writev(gc, t, dom_path, info->xsdata);
|
|
libxl__xs_writev(gc, t, libxl__sprintf(gc, "%s/platform", dom_path), info->platformdata);
|
|
|
|
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
|
|
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-xs_reset_watches", dom_path), "1", 1);
|
|
if (!xs_transaction_end(ctx->xsh, t, 0)) {
|
|
if (errno == EAGAIN) {
|
|
t = 0;
|
|
goto retry_transaction;
|
|
}
|
|
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "domain creation "
|
|
"xenstore transaction commit failed");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
t = 0;
|
|
|
|
rc = 0;
|
|
out:
|
|
if (t) xs_transaction_end(ctx->xsh, t, 1);
|
|
return rc;
|
|
}
|
|
|
|
static int store_libxl_entry(libxl__gc *gc, uint32_t domid,
|
|
libxl_domain_build_info *b_info)
|
|
{
|
|
char *path = NULL;
|
|
|
|
path = libxl__xs_libxl_path(gc, domid);
|
|
path = libxl__sprintf(gc, "%s/dm-version", path);
|
|
return libxl__xs_write(gc, XBT_NULL, path, "%s",
|
|
libxl_device_model_version_to_string(b_info->device_model_version));
|
|
}
|
|
|
|
/*----- main domain creation -----*/
|
|
|
|
/* We have a linear control flow; only one event callback is
|
|
* outstanding at any time. Each initiation and callback function
|
|
* arranges for the next to be called, as the very last thing it
|
|
* does. (If that particular sub-operation is not needed, a
|
|
* function will call the next event callback directly.)
|
|
*/
|
|
|
|
/* Event callbacks, in this order: */
|
|
static void domcreate_devmodel_started(libxl__egc *egc,
|
|
libxl__dm_spawn_state *dmss,
|
|
int rc);
|
|
static void domcreate_bootloader_console_available(libxl__egc *egc,
|
|
libxl__bootloader_state *bl);
|
|
static void domcreate_bootloader_done(libxl__egc *egc,
|
|
libxl__bootloader_state *bl,
|
|
int rc);
|
|
|
|
static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *aodevs,
|
|
int ret);
|
|
|
|
static void domcreate_attach_vtpms(libxl__egc *egc, libxl__multidev *multidev,
|
|
int ret);
|
|
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *aodevs,
|
|
int ret);
|
|
|
|
static void domcreate_console_available(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs);
|
|
|
|
static void domcreate_rebuild_done(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int ret);
|
|
|
|
/* Our own function to clean up and call the user's callback.
|
|
* The final call in the sequence. */
|
|
static void domcreate_complete(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int rc);
|
|
|
|
/* If creation is not successful, this callback will be executed
|
|
* when domain destruction is finished */
|
|
static void domcreate_destruction_cb(libxl__egc *egc,
|
|
libxl__domain_destroy_state *dds,
|
|
int rc);
|
|
|
|
static void initiate_domain_create(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs)
|
|
{
|
|
STATE_AO_GC(dcs->ao);
|
|
libxl_ctx *ctx = libxl__gc_owner(gc);
|
|
uint32_t domid;
|
|
int i, ret;
|
|
|
|
/* convenience aliases */
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
const int restore_fd = dcs->restore_fd;
|
|
memset(&dcs->build_state, 0, sizeof(dcs->build_state));
|
|
|
|
domid = 0;
|
|
|
|
ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info);
|
|
if (ret) goto error_out;
|
|
|
|
ret = libxl__domain_make(gc, &d_config->c_info, &domid);
|
|
if (ret) {
|
|
LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot make domain: %d", ret);
|
|
dcs->guest_domid = domid;
|
|
ret = ERROR_FAIL;
|
|
goto error_out;
|
|
}
|
|
|
|
dcs->guest_domid = domid;
|
|
dcs->dmss.dm.guest_domid = 0; /* means we haven't spawned */
|
|
|
|
ret = libxl__domain_build_info_setdefault(gc, &d_config->b_info);
|
|
if (ret) goto error_out;
|
|
|
|
if (!sched_params_valid(gc, domid, &d_config->b_info.sched_params)) {
|
|
LOG(ERROR, "Invalid scheduling parameters\n");
|
|
ret = ERROR_INVAL;
|
|
goto error_out;
|
|
}
|
|
|
|
for (i = 0; i < d_config->num_disks; i++) {
|
|
ret = libxl__device_disk_setdefault(gc, &d_config->disks[i]);
|
|
if (ret) goto error_out;
|
|
}
|
|
|
|
dcs->bl.ao = ao;
|
|
libxl_device_disk *bootdisk =
|
|
d_config->num_disks > 0 ? &d_config->disks[0] : NULL;
|
|
|
|
if (restore_fd >= 0) {
|
|
LOG(DEBUG, "restoring, not running bootloader\n");
|
|
domcreate_bootloader_done(egc, &dcs->bl, 0);
|
|
} else {
|
|
LOG(DEBUG, "running bootloader");
|
|
dcs->bl.callback = domcreate_bootloader_done;
|
|
dcs->bl.console_available = domcreate_bootloader_console_available;
|
|
dcs->bl.info = &d_config->b_info;
|
|
dcs->bl.disk = bootdisk;
|
|
dcs->bl.domid = dcs->guest_domid;
|
|
|
|
dcs->bl.kernel = &dcs->build_state.pv_kernel;
|
|
dcs->bl.ramdisk = &dcs->build_state.pv_ramdisk;
|
|
|
|
libxl__bootloader_run(egc, &dcs->bl);
|
|
}
|
|
return;
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_bootloader_console_available(libxl__egc *egc,
|
|
libxl__bootloader_state *bl)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
|
|
STATE_AO_GC(bl->ao);
|
|
domcreate_console_available(egc, dcs);
|
|
}
|
|
|
|
static void domcreate_console_available(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs) {
|
|
libxl__ao_progress_report(egc, dcs->ao, &dcs->aop_console_how,
|
|
NEW_EVENT(egc, DOMAIN_CREATE_CONSOLE_AVAILABLE,
|
|
dcs->guest_domid,
|
|
dcs->aop_console_how.for_event));
|
|
}
|
|
|
|
static void domcreate_bootloader_done(libxl__egc *egc,
|
|
libxl__bootloader_state *bl,
|
|
int rc)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
|
|
STATE_AO_GC(bl->ao);
|
|
|
|
/* convenience aliases */
|
|
const uint32_t domid = dcs->guest_domid;
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
libxl_domain_build_info *const info = &d_config->b_info;
|
|
const int restore_fd = dcs->restore_fd;
|
|
libxl__domain_build_state *const state = &dcs->build_state;
|
|
libxl__srm_restore_autogen_callbacks *const callbacks =
|
|
&dcs->shs.callbacks.restore.a;
|
|
|
|
if (rc) {
|
|
domcreate_rebuild_done(egc, dcs, rc);
|
|
return;
|
|
}
|
|
|
|
/* consume bootloader outputs. state->pv_{kernel,ramdisk} have
|
|
* been initialised by the bootloader already.
|
|
*/
|
|
state->pv_cmdline = bl->cmdline;
|
|
|
|
/* We might be going to call libxl__spawn_local_dm, or _spawn_stub_dm.
|
|
* Fill in any field required by either, including both relevant
|
|
* callbacks (_spawn_stub_dm will overwrite our trespass if needed). */
|
|
dcs->dmss.dm.spawn.ao = ao;
|
|
dcs->dmss.dm.guest_config = dcs->guest_config;
|
|
dcs->dmss.dm.build_state = &dcs->build_state;
|
|
dcs->dmss.dm.callback = domcreate_devmodel_started;
|
|
dcs->dmss.callback = domcreate_devmodel_started;
|
|
|
|
if ( restore_fd < 0 ) {
|
|
rc = libxl__domain_build(gc, &d_config->b_info, domid, state);
|
|
domcreate_rebuild_done(egc, dcs, rc);
|
|
return;
|
|
}
|
|
|
|
/* Restore */
|
|
|
|
rc = libxl__build_pre(gc, domid, info, state);
|
|
if (rc)
|
|
goto out;
|
|
|
|
/* read signature */
|
|
int hvm, pae, superpages;
|
|
switch (info->type) {
|
|
case LIBXL_DOMAIN_TYPE_HVM:
|
|
hvm = 1;
|
|
superpages = 1;
|
|
pae = libxl_defbool_val(info->u.hvm.pae);
|
|
callbacks->toolstack_restore = libxl__toolstack_restore;
|
|
break;
|
|
case LIBXL_DOMAIN_TYPE_PV:
|
|
hvm = 0;
|
|
superpages = 0;
|
|
pae = 1;
|
|
break;
|
|
default:
|
|
rc = ERROR_INVAL;
|
|
goto out;
|
|
}
|
|
libxl__xc_domain_restore(egc, dcs,
|
|
hvm, pae, superpages, 1);
|
|
return;
|
|
|
|
out:
|
|
libxl__xc_domain_restore_done(egc, dcs, rc, 0, 0);
|
|
}
|
|
|
|
void libxl__srm_callout_callback_restore_results(unsigned long store_mfn,
|
|
unsigned long console_mfn, unsigned long genidad, void *user)
|
|
{
|
|
libxl__save_helper_state *shs = user;
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(shs, *dcs, shs);
|
|
STATE_AO_GC(dcs->ao);
|
|
libxl__domain_build_state *const state = &dcs->build_state;
|
|
|
|
state->store_mfn = store_mfn;
|
|
state->console_mfn = console_mfn;
|
|
state->vm_generationid_addr = genidad;
|
|
shs->need_results = 0;
|
|
}
|
|
|
|
void libxl__xc_domain_restore_done(libxl__egc *egc, void *dcs_void,
|
|
int ret, int retval, int errnoval)
|
|
{
|
|
libxl__domain_create_state *dcs = dcs_void;
|
|
STATE_AO_GC(dcs->ao);
|
|
libxl_ctx *ctx = libxl__gc_owner(gc);
|
|
char **vments = NULL, **localents = NULL;
|
|
struct timeval start_time;
|
|
int i, esave, flags;
|
|
|
|
/* convenience aliases */
|
|
const uint32_t domid = dcs->guest_domid;
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
libxl_domain_build_info *const info = &d_config->b_info;
|
|
libxl__domain_build_state *const state = &dcs->build_state;
|
|
const int fd = dcs->restore_fd;
|
|
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (retval) {
|
|
LOGEV(ERROR, errnoval, "restoring domain");
|
|
ret = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
switch (info->type) {
|
|
case LIBXL_DOMAIN_TYPE_HVM:
|
|
vments = libxl__calloc(gc, 7, sizeof(char *));
|
|
vments[0] = "rtc/timeoffset";
|
|
vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
|
|
vments[2] = "image/ostype";
|
|
vments[3] = "hvm";
|
|
vments[4] = "start_time";
|
|
vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
|
|
break;
|
|
case LIBXL_DOMAIN_TYPE_PV:
|
|
vments = libxl__calloc(gc, 11, sizeof(char *));
|
|
i = 0;
|
|
vments[i++] = "image/ostype";
|
|
vments[i++] = "linux";
|
|
vments[i++] = "image/kernel";
|
|
vments[i++] = (char *) state->pv_kernel.path;
|
|
vments[i++] = "start_time";
|
|
vments[i++] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
|
|
if (state->pv_ramdisk.path) {
|
|
vments[i++] = "image/ramdisk";
|
|
vments[i++] = (char *) state->pv_ramdisk.path;
|
|
}
|
|
if (state->pv_cmdline) {
|
|
vments[i++] = "image/cmdline";
|
|
vments[i++] = (char *) state->pv_cmdline;
|
|
}
|
|
break;
|
|
default:
|
|
ret = ERROR_INVAL;
|
|
goto out;
|
|
}
|
|
ret = libxl__build_post(gc, domid, info, state, vments, localents);
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
|
|
state->saved_state = GCSPRINTF(
|
|
XC_DEVICE_MODEL_RESTORE_FILE".%d", domid);
|
|
}
|
|
|
|
out:
|
|
if (info->type == LIBXL_DOMAIN_TYPE_PV) {
|
|
libxl__file_reference_unmap(&state->pv_kernel);
|
|
libxl__file_reference_unmap(&state->pv_ramdisk);
|
|
}
|
|
|
|
esave = errno;
|
|
|
|
flags = fcntl(fd, F_GETFL);
|
|
if (flags == -1) {
|
|
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get flags on restore fd");
|
|
} else {
|
|
flags &= ~O_NONBLOCK;
|
|
if (fcntl(fd, F_SETFL, flags) == -1)
|
|
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to put restore fd"
|
|
" back to blocking mode");
|
|
}
|
|
|
|
errno = esave;
|
|
domcreate_rebuild_done(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_rebuild_done(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int ret)
|
|
{
|
|
STATE_AO_GC(dcs->ao);
|
|
|
|
/* convenience aliases */
|
|
const uint32_t domid = dcs->guest_domid;
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
libxl_ctx *const ctx = CTX;
|
|
|
|
if (ret) {
|
|
LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot (re-)build domain: %d", ret);
|
|
ret = ERROR_FAIL;
|
|
goto error_out;
|
|
}
|
|
|
|
store_libxl_entry(gc, domid, &d_config->b_info);
|
|
|
|
libxl__multidev_begin(ao, &dcs->multidev);
|
|
dcs->multidev.callback = domcreate_launch_dm;
|
|
libxl__add_disks(egc, ao, domid, d_config, &dcs->multidev);
|
|
libxl__multidev_prepared(egc, &dcs->multidev, 0);
|
|
|
|
return;
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
|
|
int ret)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
|
|
STATE_AO_GC(dcs->ao);
|
|
int i;
|
|
|
|
/* convenience aliases */
|
|
const uint32_t domid = dcs->guest_domid;
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
libxl__domain_build_state *const state = &dcs->build_state;
|
|
|
|
if (ret) {
|
|
LOG(ERROR, "unable to add disk devices");
|
|
goto error_out;
|
|
}
|
|
|
|
for (i = 0; i < d_config->b_info.num_ioports; i++) {
|
|
libxl_ioport_range *io = &d_config->b_info.ioports[i];
|
|
|
|
LOG(DEBUG, "dom%d ioports %"PRIx32"-%"PRIx32,
|
|
domid, io->first, io->first + io->number - 1);
|
|
|
|
ret = xc_domain_ioport_permission(CTX->xch, domid,
|
|
io->first, io->number, 1);
|
|
if (ret < 0) {
|
|
LOGE(ERROR,
|
|
"failed give dom%d access to ioports %"PRIx32"-%"PRIx32,
|
|
domid, io->first, io->first + io->number - 1);
|
|
ret = ERROR_FAIL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < d_config->b_info.num_irqs; i++) {
|
|
uint32_t irq = d_config->b_info.irqs[i];
|
|
|
|
LOG(DEBUG, "dom%d irq %"PRIx32, domid, irq);
|
|
|
|
ret = xc_domain_irq_permission(CTX->xch, domid, irq, 1);
|
|
if (ret < 0) {
|
|
LOGE(ERROR,
|
|
"failed give dom%d access to irq %"PRId32, domid, irq);
|
|
ret = ERROR_FAIL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < d_config->b_info.num_iomem; i++) {
|
|
libxl_iomem_range *io = &d_config->b_info.iomem[i];
|
|
|
|
LOG(DEBUG, "dom%d iomem %"PRIx64"-%"PRIx64,
|
|
domid, io->start, io->start + io->number - 1);
|
|
|
|
ret = xc_domain_iomem_permission(CTX->xch, domid,
|
|
io->start, io->number, 1);
|
|
if (ret < 0) {
|
|
LOGE(ERROR,
|
|
"failed give dom%d access to iomem range %"PRIx64"-%"PRIx64,
|
|
domid, io->start, io->start + io->number - 1);
|
|
ret = ERROR_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < d_config->num_nics; i++) {
|
|
/* We have to init the nic here, because we still haven't
|
|
* called libxl_device_nic_add at this point, but qemu needs
|
|
* the nic information to be complete.
|
|
*/
|
|
ret = libxl__device_nic_setdefault(gc, &d_config->nics[i], domid);
|
|
if (ret)
|
|
goto error_out;
|
|
}
|
|
switch (d_config->c_info.type) {
|
|
case LIBXL_DOMAIN_TYPE_HVM:
|
|
{
|
|
libxl__device_console console;
|
|
libxl_device_vkb vkb;
|
|
|
|
ret = init_console_info(&console, 0);
|
|
if ( ret )
|
|
goto error_out;
|
|
console.backend_domid = state->console_domid;
|
|
libxl__device_console_add(gc, domid, &console, state);
|
|
libxl__device_console_dispose(&console);
|
|
|
|
libxl_device_vkb_init(&vkb);
|
|
libxl__device_vkb_add(gc, domid, &vkb);
|
|
libxl_device_vkb_dispose(&vkb);
|
|
|
|
dcs->dmss.dm.guest_domid = domid;
|
|
if (libxl_defbool_val(d_config->b_info.device_model_stubdomain))
|
|
libxl__spawn_stub_dm(egc, &dcs->dmss);
|
|
else
|
|
libxl__spawn_local_dm(egc, &dcs->dmss.dm);
|
|
return;
|
|
}
|
|
case LIBXL_DOMAIN_TYPE_PV:
|
|
{
|
|
int need_qemu = 0;
|
|
libxl__device_console console;
|
|
|
|
for (i = 0; i < d_config->num_vfbs; i++) {
|
|
libxl__device_vfb_add(gc, domid, &d_config->vfbs[i]);
|
|
libxl__device_vkb_add(gc, domid, &d_config->vkbs[i]);
|
|
}
|
|
|
|
ret = init_console_info(&console, 0);
|
|
if ( ret )
|
|
goto error_out;
|
|
|
|
need_qemu = libxl__need_xenpv_qemu(gc, 1, &console,
|
|
d_config->num_vfbs, d_config->vfbs,
|
|
d_config->num_disks, &d_config->disks[0]);
|
|
|
|
console.backend_domid = state->console_domid;
|
|
libxl__device_console_add(gc, domid, &console, state);
|
|
libxl__device_console_dispose(&console);
|
|
|
|
if (need_qemu) {
|
|
dcs->dmss.dm.guest_domid = domid;
|
|
libxl__spawn_local_dm(egc, &dcs->dmss.dm);
|
|
return;
|
|
} else {
|
|
assert(!dcs->dmss.dm.guest_domid);
|
|
domcreate_devmodel_started(egc, &dcs->dmss.dm, 0);
|
|
return;
|
|
}
|
|
}
|
|
default:
|
|
ret = ERROR_INVAL;
|
|
goto error_out;
|
|
}
|
|
abort(); /* not reached */
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_devmodel_started(libxl__egc *egc,
|
|
libxl__dm_spawn_state *dmss,
|
|
int ret)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm);
|
|
STATE_AO_GC(dmss->spawn.ao);
|
|
libxl_ctx *ctx = CTX;
|
|
int domid = dcs->guest_domid;
|
|
|
|
/* convenience aliases */
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
|
|
if (ret) {
|
|
LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
|
|
"device model did not start: %d", ret);
|
|
goto error_out;
|
|
}
|
|
|
|
if (dcs->dmss.dm.guest_domid) {
|
|
if (d_config->b_info.device_model_version
|
|
== LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
|
|
libxl__qmp_initializations(gc, domid, d_config);
|
|
}
|
|
}
|
|
|
|
/* Plug nic interfaces */
|
|
if (d_config->num_nics > 0) {
|
|
/* Attach nics */
|
|
libxl__multidev_begin(ao, &dcs->multidev);
|
|
dcs->multidev.callback = domcreate_attach_vtpms;
|
|
libxl__add_nics(egc, ao, domid, d_config, &dcs->multidev);
|
|
libxl__multidev_prepared(egc, &dcs->multidev, 0);
|
|
return;
|
|
}
|
|
|
|
domcreate_attach_vtpms(egc, &dcs->multidev, 0);
|
|
return;
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_attach_vtpms(libxl__egc *egc,
|
|
libxl__multidev *multidev,
|
|
int ret)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
|
|
STATE_AO_GC(dcs->ao);
|
|
int domid = dcs->guest_domid;
|
|
|
|
libxl_domain_config* const d_config = dcs->guest_config;
|
|
|
|
if(ret) {
|
|
LOG(ERROR, "unable to add nic devices");
|
|
goto error_out;
|
|
}
|
|
|
|
/* Plug vtpm devices */
|
|
if (d_config->num_vtpms > 0) {
|
|
/* Attach vtpms */
|
|
libxl__multidev_begin(ao, &dcs->multidev);
|
|
dcs->multidev.callback = domcreate_attach_pci;
|
|
libxl__add_vtpms(egc, ao, domid, d_config, &dcs->multidev);
|
|
libxl__multidev_prepared(egc, &dcs->multidev, 0);
|
|
return;
|
|
}
|
|
|
|
domcreate_attach_pci(egc, multidev, 0);
|
|
return;
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
|
|
int ret)
|
|
{
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
|
|
STATE_AO_GC(dcs->ao);
|
|
int i;
|
|
libxl_ctx *ctx = CTX;
|
|
int domid = dcs->guest_domid;
|
|
|
|
/* convenience aliases */
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
|
|
if (ret) {
|
|
LOG(ERROR, "unable to add vtpm devices");
|
|
goto error_out;
|
|
}
|
|
|
|
for (i = 0; i < d_config->num_pcidevs; i++)
|
|
libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);
|
|
|
|
if (d_config->num_pcidevs > 0) {
|
|
ret = libxl__create_pci_backend(gc, domid, d_config->pcidevs,
|
|
d_config->num_pcidevs);
|
|
if (ret < 0) {
|
|
LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
|
|
"libxl_create_pci_backend failed: %d", ret);
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
libxl__arch_domain_create(gc, d_config, domid);
|
|
domcreate_console_available(egc, dcs);
|
|
|
|
domcreate_complete(egc, dcs, 0);
|
|
return;
|
|
|
|
error_out:
|
|
assert(ret);
|
|
domcreate_complete(egc, dcs, ret);
|
|
}
|
|
|
|
static void domcreate_complete(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int rc)
|
|
{
|
|
STATE_AO_GC(dcs->ao);
|
|
libxl_domain_config *const d_config = dcs->guest_config;
|
|
|
|
if (!rc && d_config->b_info.exec_ssidref)
|
|
rc = xc_flask_relabel_domain(CTX->xch, dcs->guest_domid, d_config->b_info.exec_ssidref);
|
|
|
|
if (rc) {
|
|
if (dcs->guest_domid) {
|
|
dcs->dds.ao = ao;
|
|
dcs->dds.domid = dcs->guest_domid;
|
|
dcs->dds.callback = domcreate_destruction_cb;
|
|
libxl__domain_destroy(egc, &dcs->dds);
|
|
return;
|
|
}
|
|
dcs->guest_domid = -1;
|
|
}
|
|
dcs->callback(egc, dcs, rc, dcs->guest_domid);
|
|
}
|
|
|
|
static void domcreate_destruction_cb(libxl__egc *egc,
|
|
libxl__domain_destroy_state *dds,
|
|
int rc)
|
|
{
|
|
STATE_AO_GC(dds->ao);
|
|
libxl__domain_create_state *dcs = CONTAINER_OF(dds, *dcs, dds);
|
|
|
|
if (rc)
|
|
LOG(ERROR, "unable to destroy domain %u following failed creation",
|
|
dds->domid);
|
|
|
|
dcs->callback(egc, dcs, ERROR_FAIL, dcs->guest_domid);
|
|
}
|
|
|
|
/*----- application-facing domain creation interface -----*/
|
|
|
|
typedef struct {
|
|
libxl__domain_create_state dcs;
|
|
uint32_t *domid_out;
|
|
} libxl__app_domain_create_state;
|
|
|
|
static void domain_create_cb(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int rc, uint32_t domid);
|
|
|
|
static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
|
|
uint32_t *domid,
|
|
int restore_fd, const libxl_asyncop_how *ao_how,
|
|
const libxl_asyncprogress_how *aop_console_how)
|
|
{
|
|
AO_CREATE(ctx, 0, ao_how);
|
|
libxl__app_domain_create_state *cdcs;
|
|
|
|
GCNEW(cdcs);
|
|
cdcs->dcs.ao = ao;
|
|
cdcs->dcs.guest_config = d_config;
|
|
cdcs->dcs.restore_fd = restore_fd;
|
|
cdcs->dcs.callback = domain_create_cb;
|
|
libxl__ao_progress_gethow(&cdcs->dcs.aop_console_how, aop_console_how);
|
|
cdcs->domid_out = domid;
|
|
|
|
initiate_domain_create(egc, &cdcs->dcs);
|
|
|
|
return AO_INPROGRESS;
|
|
}
|
|
|
|
static void domain_create_cb(libxl__egc *egc,
|
|
libxl__domain_create_state *dcs,
|
|
int rc, uint32_t domid)
|
|
{
|
|
libxl__app_domain_create_state *cdcs = CONTAINER_OF(dcs, *cdcs, dcs);
|
|
STATE_AO_GC(cdcs->dcs.ao);
|
|
|
|
if (!rc)
|
|
*cdcs->domid_out = domid;
|
|
|
|
libxl__ao_complete(egc, ao, rc);
|
|
}
|
|
|
|
int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
|
|
uint32_t *domid,
|
|
const libxl_asyncop_how *ao_how,
|
|
const libxl_asyncprogress_how *aop_console_how)
|
|
{
|
|
return do_domain_create(ctx, d_config, domid, -1,
|
|
ao_how, aop_console_how);
|
|
}
|
|
|
|
int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
|
|
uint32_t *domid, int restore_fd,
|
|
const libxl_asyncop_how *ao_how,
|
|
const libxl_asyncprogress_how *aop_console_how)
|
|
{
|
|
return do_domain_create(ctx, d_config, domid, restore_fd,
|
|
ao_how, aop_console_how);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|