void libxl_report_child_exitstatus(libxl_ctx *ctx, xentoollog_level level, const char *what, pid_t pid, int status) { if (WIFEXITED(status)) { int st = WEXITSTATUS(status); if (st) LIBXL__LOG(ctx, level, "%s [%ld] exited" " with error status %d", what, (unsigned long)pid, st); else LIBXL__LOG(ctx, level, "%s [%ld] unexpectedly" " exited status zero", what, (unsigned long)pid); } else if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); const char *str = strsignal(sig); const char *coredump = WCOREDUMP(status) ? " (core dumped)" : ""; if (str) LIBXL__LOG(ctx, level, "%s [%ld] died due to" " fatal signal %s%s", what, (unsigned long)pid, str, coredump); else LIBXL__LOG(ctx, level, "%s [%ld] died due to unknown" " fatal signal number %d%s", what, (unsigned long)pid, sig, coredump); } else { LIBXL__LOG(ctx, level, "%s [%ld] gave unknown" " wait status 0x%x", what, (unsigned long)pid, status); } }
static char *dm_spice_options(libxl__gc *gc, const libxl_spice_info *spice) { char *opt; if (!spice->port && !spice->tls_port) { LIBXL__LOG(CTX, LIBXL__LOG_ERROR, "at least one of the spiceport or tls_port must be provided"); return NULL; } if (!libxl_defbool_val(spice->disable_ticketing)) { if (!spice->passwd) { LIBXL__LOG(CTX, LIBXL__LOG_ERROR, "spice ticketing is enabled but missing password"); return NULL; } else if (!spice->passwd[0]) { LIBXL__LOG(CTX, LIBXL__LOG_ERROR, "spice password can't be empty"); return NULL; } } opt = libxl__sprintf(gc, "port=%d,tls-port=%d", spice->port, spice->tls_port); if (spice->host) opt = libxl__sprintf(gc, "%s,addr=%s", opt, spice->host); if (libxl_defbool_val(spice->disable_ticketing)) opt = libxl__sprintf(gc, "%s,disable-ticketing", opt); else opt = libxl__sprintf(gc, "%s,password=%s", opt, spice->passwd); opt = libxl__sprintf(gc, "%s,agent-mouse=%s", opt, libxl_defbool_val(spice->agent_mouse) ? "on" : "off"); return opt; }
const char *libxl__domain_device_model(libxl__gc *gc, const libxl_domain_build_info *info) { libxl_ctx *ctx = libxl__gc_owner(gc); const char *dm; if (libxl_defbool_val(info->device_model_stubdomain)) return NULL; if (info->device_model) { dm = libxl__strdup(gc, info->device_model); } else { switch (info->device_model_version) { case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL: dm = libxl__abs_path(gc, "qemu-dm", libxl__libexec_path()); break; case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN: dm = qemu_xen_path(gc); break; default: LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "invalid device model version %d\n", info->device_model_version); dm = NULL; break; } } return dm; }
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_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++) { ret = libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1); if (ret < 0) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_device_pci_add failed: %d", ret); goto error_out; } } 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; } } domcreate_console_available(egc, dcs); domcreate_complete(egc, dcs, 0); return; error_out: assert(ret); domcreate_complete(egc, dcs, ret); }
int libxl__destroy_device_model(libxl_ctx *ctx, uint32_t domid) { libxl__gc gc = LIBXL_INIT_GC(ctx); char *pid; int ret; pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid)); if (!pid) { int stubdomid = libxl_get_stubdom_id(ctx, domid); if (!stubdomid) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't find device model's pid"); ret = ERROR_INVAL; goto out; } LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device model is a stubdom, domid=%d\n", stubdomid); ret = libxl_domain_destroy(ctx, stubdomid, 0); if (ret) goto out; } else { ret = kill(atoi(pid), SIGHUP); if (ret < 0 && errno == ESRCH) { LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model already exited"); ret = 0; } else if (ret == 0) { LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model signaled"); ret = 0; } else { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to kill Device Model [%d]", atoi(pid)); ret = ERROR_FAIL; goto out; } } xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", domid)); out: libxl__free_all(&gc); return 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 nic devices"); goto error_out; } for (i = 0; i < d_config->num_pcidevs; i++) { // TODO(Yusuke Suzuki): we should check target device is nvc0 libxl__device_pci_add_with_nvc0(gc, domid, &d_config->pcidevs[i], 1, d_config->b_info.u.hvm.nvc0 >= 0); } 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_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_pci; libxl__add_nics(egc, ao, domid, d_config, &dcs->multidev); libxl__multidev_prepared(egc, &dcs->multidev, 0); return; } domcreate_attach_pci(egc, &dcs->multidev, 0); return; error_out: assert(ret); domcreate_complete(egc, dcs, ret); }
int libxl__device_model_version_running(libxl__gc *gc, uint32_t domid) { char *path = NULL; char *dm_version = NULL; libxl_device_model_version value; path = libxl__xs_libxl_path(gc, domid); path = libxl__sprintf(gc, "%s/dm-version", path); dm_version = libxl__xs_read(gc, XBT_NULL, path); if (!dm_version) { return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL; } if (libxl_device_model_version_from_string(dm_version, &value) < 0) { libxl_ctx *ctx = libxl__gc_owner(gc); LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "fatal: %s contain a wrong value (%s)", path, dm_version); return -1; } return value; }
void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) { /* convenience aliases */ const int domid = dmss->guest_domid; libxl__domain_build_state *const state = dmss->build_state; libxl__spawn_state *const spawn = &dmss->spawn; STATE_AO_GC(dmss->spawn.ao); libxl_ctx *ctx = CTX; libxl_domain_config *guest_config = dmss->guest_config; const libxl_domain_create_info *c_info = &guest_config->c_info; const libxl_domain_build_info *b_info = &guest_config->b_info; const libxl_vnc_info *vnc = libxl__dm_vnc(guest_config); char *path, *logfile; int logfile_w, null; int rc; char **args, **arg; xs_transaction_t t; char *vm_path; char **pass_stuff; const char *dm; if (libxl_defbool_val(b_info->device_model_stubdomain)) { abort(); } dm = libxl__domain_device_model(gc, b_info); if (!dm) { rc = ERROR_FAIL; goto out; } if (access(dm, X_OK) < 0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "device model %s is not executable", dm); rc = ERROR_FAIL; goto out; } args = libxl__build_device_model_args(gc, dm, domid, guest_config, state); if (!args) { rc = ERROR_FAIL; goto out; } if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) { path = xs_get_domain_path(ctx->xsh, domid); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/hvmloader/bios", path), "%s", libxl_bios_type_to_string(b_info->u.hvm.bios)); /* Disable relocating memory to make the MMIO hole larger * unless we're running qemu-traditional */ libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/hvmloader/allow-memory-relocate", path), "%d", b_info->device_model_version==LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL); free(path); } path = libxl__sprintf(gc, "/local/domain/0/device-model/%d", domid); xs_mkdir(ctx->xsh, XBT_NULL, path); if (b_info->type == LIBXL_DOMAIN_TYPE_HVM && b_info->device_model_version == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL) libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/disable_pf", path), "%d", !libxl_defbool_val(b_info->u.hvm.xen_platform_pci)); libxl_create_logfile(ctx, libxl__sprintf(gc, "qemu-dm-%s", c_info->name), &logfile); logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); free(logfile); null = open("/dev/null", O_RDONLY); const char *dom_path = libxl__xs_get_dompath(gc, domid); spawn->pidpath = GCSPRINTF("%s/%s", dom_path, "image/device-model-pid"); if (vnc && vnc->passwd) { /* This xenstore key will only be used by qemu-xen-traditionnal. * The code to supply vncpasswd to qemu-xen is later. */ retry_transaction: /* Find uuid and the write the vnc password to xenstore for qemu. */ t = xs_transaction_start(ctx->xsh); vm_path = libxl__xs_read(gc,t,libxl__sprintf(gc, "%s/vm", dom_path)); if (vm_path) { /* Now write the vncpassword into it. */ pass_stuff = libxl__calloc(gc, 3, sizeof(char *)); pass_stuff[0] = "vncpasswd"; pass_stuff[1] = vnc->passwd; libxl__xs_writev(gc,t,vm_path,pass_stuff); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; } } LIBXL__LOG(CTX, XTL_DEBUG, "Spawning device-model %s with arguments:", dm); for (arg = args; *arg; arg++) LIBXL__LOG(CTX, XTL_DEBUG, " %s", *arg); spawn->what = GCSPRINTF("domain %d device model", domid); spawn->xspath = GCSPRINTF("/local/domain/0/device-model/%d/state", domid); spawn->timeout_ms = LIBXL_DEVICE_MODEL_START_TIMEOUT * 1000; spawn->pidpath = GCSPRINTF("%s/image/device-model-pid", dom_path); spawn->midproc_cb = libxl__spawn_record_pid; spawn->confirm_cb = device_model_confirm; spawn->failure_cb = device_model_startup_failed; spawn->detached_cb = device_model_detached; rc = libxl__spawn_spawn(egc, spawn); if (rc < 0) goto out_close; if (!rc) { /* inner child */ setsid(); libxl__exec(gc, null, logfile_w, logfile_w, dm, args, NULL); } rc = 0; out_close: close(null); close(logfile_w); out: if (rc) device_model_spawn_outcome(egc, dmss, 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); }
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; }
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 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; size_t last_devid = -1; bool pod_enabled = false; /* 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; /* If target_memkb is smaller than max_memkb, the subsequent call * to libxc when building HVM domain will enable PoD mode. */ pod_enabled = (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) && (d_config->b_info.target_memkb < d_config->b_info.max_memkb); /* We cannot have PoD and PCI device assignment at the same time * for HVM guest. It was reported that IOMMU cannot work with PoD * enabled because it needs to populated entire page table for * guest. To stay on the safe side, we disable PCI device * assignment when PoD is enabled. */ if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM && d_config->num_pcidevs && pod_enabled) { ret = ERROR_INVAL; LOG(ERROR, "PCI device assignment for HVM guest failed due to PoD enabled"); goto error_out; } 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; /* * The devid has to be set before launching the device model. For the * hotplug case this is done in libxl_device_nic_add but on domain * creation this is called too late. * Make two runs over configured NICs in order to avoid duplicate IDs * in case the caller partially assigned IDs. */ 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 when domcreate_launch_dm gets called, * 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; if (d_config->nics[i].devid > last_devid) last_devid = d_config->nics[i].devid; } for (i = 0; i < d_config->num_nics; i++) { if (d_config->nics[i].devid < 0) d_config->nics[i].devid = ++last_devid; } 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); }