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; }
static int libxlMakeVfbList(libxlDriverPrivatePtr driver, virDomainDefPtr def, libxl_domain_config *d_config) { virDomainGraphicsDefPtr *l_vfbs = def->graphics; int nvfbs = def->ngraphics; libxl_device_vfb *x_vfbs; libxl_device_vkb *x_vkbs; size_t i; if (nvfbs == 0) return 0; if (VIR_ALLOC_N(x_vfbs, nvfbs) < 0) return -1; if (VIR_ALLOC_N(x_vkbs, nvfbs) < 0) { VIR_FREE(x_vfbs); return -1; } for (i = 0; i < nvfbs; i++) { libxl_device_vkb_init(&x_vkbs[i]); if (libxlMakeVfb(driver, l_vfbs[i], &x_vfbs[i]) < 0) goto error; } d_config->vfbs = x_vfbs; d_config->vkbs = x_vkbs; d_config->num_vfbs = d_config->num_vkbs = nvfbs; /* * VNC or SDL info must also be set in libxl_domain_build_info * for HVM domains. Use the first vfb device. */ if (STREQ(def->os.type, "hvm")) { libxl_domain_build_info *b_info = &d_config->b_info; libxl_device_vfb vfb = d_config->vfbs[0]; if (libxl_defbool_val(vfb.vnc.enable)) memcpy(&b_info->u.hvm.vnc, &vfb.vnc, sizeof(libxl_vnc_info)); else if (libxl_defbool_val(vfb.sdl.enable)) memcpy(&b_info->u.hvm.sdl, &vfb.sdl, sizeof(libxl_sdl_info)); } return 0; error: for (i = 0; i < nvfbs; i++) { libxl_device_vfb_dispose(&x_vfbs[i]); libxl_device_vkb_dispose(&x_vkbs[i]); } VIR_FREE(x_vfbs); VIR_FREE(x_vkbs); return -1; }
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 domain_save_done(libxl__egc *egc, libxl__domain_save_state *dss, int rc) { STATE_AO_GC(dss->ao); /* Convenience aliases */ const uint32_t domid = dss->domid; libxl__domain_suspend_state *dsps = &dss->dsps; libxl__ev_evtchn_cancel(gc, &dsps->guest_evtchn); if (dsps->guest_evtchn.port > 0) xc_suspend_evtchn_release(CTX->xch, CTX->xce, domid, dsps->guest_evtchn.port, &dsps->guest_evtchn_lockfd); if (dss->remus) { /* * With Remus/COLO, if we reach this point, it means either * backup died or some network error occurred preventing us * from sending checkpoints. Teardown the network buffers and * release netlink resources. This is an async op. */ if (libxl_defbool_val(dss->remus->colo)) libxl__colo_save_teardown(egc, &dss->css, rc); else libxl__remus_teardown(egc, &dss->rs, rc); return; } dss->callback(egc, dss, rc); }
static int libxl__e820_alloc(libxl__gc *gc, uint32_t domid, libxl_domain_config *d_config) { libxl_ctx *ctx = libxl__gc_owner(gc); int rc; uint32_t nr; struct e820entry map[E820MAX]; libxl_domain_build_info *b_info; if (d_config == NULL || d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) return ERROR_INVAL; b_info = &d_config->b_info; if (!libxl_defbool_val(b_info->u.pv.e820_host)) return ERROR_INVAL; nr = E820MAX; rc = e820_host_sanitize(gc, b_info, map, &nr); if (rc) return ERROR_FAIL; rc = xc_domain_set_memory_map(ctx->xch, domid, map, nr); if (rc < 0) return ERROR_FAIL; return 0; }
const libxl_vnc_info *libxl__dm_vnc(const libxl_domain_config *guest_config) { const libxl_vnc_info *vnc = NULL; if (guest_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM) { vnc = &guest_config->b_info.u.hvm.vnc; } else if (guest_config->num_vfbs > 0) { vnc = &guest_config->vfbs[0].vnc; } return vnc && libxl_defbool_val(vnc->enable) ? vnc : NULL; }
static const libxl_sdl_info *dm_sdl(const libxl_domain_config *guest_config) { const libxl_sdl_info *sdl = NULL; if (guest_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM) { sdl = &guest_config->b_info.u.hvm.sdl; } else if (guest_config->num_vfbs > 0) { sdl = &guest_config->vfbs[0].sdl; } return sdl && libxl_defbool_val(sdl->enable) ? sdl : NULL; }
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); } else { libxl_defbool_setdefault(&c_info->pvh, false); libxl_defbool_setdefault(&c_info->hap, libxl_defbool_val(c_info->pvh)); } libxl_defbool_setdefault(&c_info->run_hotplug_scripts, true); libxl_defbool_setdefault(&c_info->driver_domain, false); return 0; }
int libxl__arch_domain_prepare_config(libxl__gc *gc, libxl_domain_config *d_config, xc_domain_configuration_t *xc_config) { if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) { if (d_config->b_info.device_model_version != LIBXL_DEVICE_MODEL_VERSION_NONE) { xc_config->emulation_flags = XEN_X86_EMU_ALL; } else if (libxl_defbool_val(d_config->b_info.u.hvm.apic)) { /* * HVM guests without device model may want * to have LAPIC emulation. */ xc_config->emulation_flags = XEN_X86_EMU_LAPIC; } } else { xc_config->emulation_flags = 0; } return 0; }
int libxl_domain_need_memory(libxl_ctx *ctx, const libxl_domain_build_info *b_info_in, uint64_t *need_memkb) { GC_INIT(ctx); libxl_domain_build_info b_info[1]; int rc; libxl_domain_build_info_init(b_info); libxl_domain_build_info_copy(ctx, b_info, b_info_in); rc = libxl__domain_build_info_setdefault(gc, b_info); if (rc) goto out; *need_memkb = b_info->target_memkb; switch (b_info->type) { case LIBXL_DOMAIN_TYPE_PVH: case LIBXL_DOMAIN_TYPE_HVM: *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY; if (libxl_defbool_val(b_info->device_model_stubdomain)) *need_memkb += 32 * 1024; break; case LIBXL_DOMAIN_TYPE_PV: *need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY; break; default: rc = ERROR_INVAL; goto out; } if (*need_memkb % (2 * 1024)) *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024)); rc = 0; out: GC_FREE; libxl_domain_build_info_dispose(b_info); return rc; }
static int libxl__e820_alloc(libxl__gc *gc, uint32_t domid, libxl_domain_config *d_config) { libxl_ctx *ctx = libxl__gc_owner(gc); int rc; uint32_t nr; struct e820entry map[E820MAX]; libxl_domain_build_info *b_info; if (d_config == NULL || d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) return ERROR_INVAL; b_info = &d_config->b_info; if (!libxl_defbool_val(b_info->u.pv.e820_host)) return ERROR_INVAL; rc = xc_get_machine_memory_map(ctx->xch, map, E820MAX); if (rc < 0) { errno = rc; return ERROR_FAIL; } nr = rc; rc = e820_sanitize(ctx, map, &nr, b_info->target_memkb, (b_info->max_memkb - b_info->target_memkb) + b_info->u.pv.slack_memkb); if (rc) return ERROR_FAIL; rc = xc_domain_set_memory_map(ctx->xch, domid, map, nr); if (rc < 0) { errno = rc; return ERROR_FAIL; } return 0; }
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__domain_save(libxl__egc *egc, libxl__domain_save_state *dss) { STATE_AO_GC(dss->ao); int rc, ret; /* Convenience aliases */ const uint32_t domid = dss->domid; const libxl_domain_type type = dss->type; const int live = dss->live; const int debug = dss->debug; const libxl_domain_remus_info *const r_info = dss->remus; libxl__srm_save_autogen_callbacks *const callbacks = &dss->sws.shs.callbacks.save.a; unsigned int nr_vnodes = 0, nr_vmemranges = 0, nr_vcpus = 0; libxl__domain_suspend_state *dsps = &dss->dsps; if (dss->checkpointed_stream != LIBXL_CHECKPOINTED_STREAM_NONE && !r_info) { LOG(ERROR, "Migration stream is checkpointed, but there's no " "checkpoint info!"); rc = ERROR_INVAL; goto out; } dss->rc = 0; libxl__logdirty_init(&dss->logdirty); dss->logdirty.ao = ao; dsps->ao = ao; dsps->domid = domid; rc = libxl__domain_suspend_init(egc, dsps, type); if (rc) goto out; switch (type) { case LIBXL_DOMAIN_TYPE_HVM: { dss->hvm = 1; break; } case LIBXL_DOMAIN_TYPE_PV: dss->hvm = 0; break; default: abort(); } dss->xcflags = (live ? XCFLAGS_LIVE : 0) | (debug ? XCFLAGS_DEBUG : 0) | (dss->hvm ? XCFLAGS_HVM : 0); /* Disallow saving a guest with vNUMA configured because migration * stream does not preserve node information. * * Reject any domain which has vnuma enabled, even if the * configuration is empty. Only domains which have no vnuma * configuration at all are supported. */ ret = xc_domain_getvnuma(CTX->xch, domid, &nr_vnodes, &nr_vmemranges, &nr_vcpus, NULL, NULL, NULL); if (ret != -1 || errno != EOPNOTSUPP) { LOG(ERROR, "Cannot save a guest with vNUMA configured"); rc = ERROR_FAIL; goto out; } if (dss->checkpointed_stream == LIBXL_CHECKPOINTED_STREAM_REMUS) { if (libxl_defbool_val(r_info->compression)) dss->xcflags |= XCFLAGS_CHECKPOINT_COMPRESS; } if (dss->checkpointed_stream == LIBXL_CHECKPOINTED_STREAM_NONE) callbacks->suspend = libxl__domain_suspend_callback; callbacks->switch_qemu_logdirty = libxl__domain_suspend_common_switch_qemu_logdirty; dss->sws.ao = dss->ao; dss->sws.dss = dss; dss->sws.fd = dss->fd; dss->sws.back_channel = false; dss->sws.completion_callback = stream_done; libxl__stream_write_start(egc, &dss->sws); return; out: domain_save_done(egc, dss, rc); }
void libxl__colo_save_setup(libxl__egc *egc, libxl__colo_save_state *css) { libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css); /* Convenience aliases */ libxl__checkpoint_devices_state *const cds = &dss->cds; libxl__srm_save_autogen_callbacks *const callbacks = &dss->sws.shs.callbacks.save.a; STATE_AO_GC(dss->ao); if (dss->type != LIBXL_DOMAIN_TYPE_HVM) { LOGD(ERROR, dss->domid, "COLO only supports hvm now"); goto out; } css->send_fd = dss->fd; css->recv_fd = dss->recv_fd; css->svm_running = false; css->paused = true; css->qdisk_setuped = false; css->qdisk_used = false; libxl__ev_child_init(&css->child); css->cps.is_userspace_proxy = libxl_defbool_val(dss->remus->userspace_colo_proxy); if (dss->remus->netbufscript) css->colo_proxy_script = libxl__strdup(gc, dss->remus->netbufscript); else css->colo_proxy_script = GCSPRINTF("%s/colo-proxy-setup", libxl__xen_script_dir_path()); cds->ops = colo_ops; cds->callback = colo_save_setup_done; cds->ao = ao; cds->domid = dss->domid; cds->concrete_data = css; /* If enable userspace proxy mode, we don't need VIF */ if (css->cps.is_userspace_proxy) { cds->device_kind_flags = (1 << LIBXL__DEVICE_KIND_VBD); /* Use this args we can connect to qemu colo-compare */ cds->nics = libxl__device_list(gc, &libxl__nic_devtype, cds->domid, &cds->num_nics); if (cds->num_nics > 0) { css->cps.checkpoint_host = cds->nics[0].colo_checkpoint_host; css->cps.checkpoint_port = cds->nics[0].colo_checkpoint_port; } } else { cds->device_kind_flags = (1 << LIBXL__DEVICE_KIND_VIF) | (1 << LIBXL__DEVICE_KIND_VBD); } css->srs.ao = ao; css->srs.fd = css->recv_fd; css->srs.back_channel = true; libxl__stream_read_start(egc, &css->srs); css->cps.ao = ao; if (colo_proxy_setup(&css->cps)) { LOGD(ERROR, cds->domid, "COLO: failed to setup colo proxy for guest"); goto out; } if (init_device_subkind(cds)) goto out; callbacks->suspend = libxl__colo_save_domain_suspend_callback; callbacks->checkpoint = libxl__colo_save_domain_checkpoint_callback; callbacks->postcopy = libxl__colo_save_domain_resume_callback; callbacks->wait_checkpoint = libxl__colo_save_domain_wait_checkpoint_callback; libxl__checkpoint_devices_setup(egc, &dss->cds); return; out: dss->callback(egc, dss, ERROR_FAIL); }
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); }
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; }
/* Return 0 on success, ERROR_* on failure. */ int libxl__arch_vnuma_build_vmemrange(libxl__gc *gc, uint32_t domid, libxl_domain_build_info *b_info, libxl__domain_build_state *state) { int nid, nr_vmemrange, rc; uint32_t nr_e820, e820_count; struct e820entry map[E820MAX]; xen_vmemrange_t *vmemranges; unsigned int array_size; /* If e820_host is not set, call the generic function */ if (!(b_info->type == LIBXL_DOMAIN_TYPE_PV && libxl_defbool_val(b_info->u.pv.e820_host))) return libxl__vnuma_build_vmemrange_pv_generic(gc, domid, b_info, state); assert(state->vmemranges == NULL); nr_e820 = E820MAX; rc = e820_host_sanitize(gc, b_info, map, &nr_e820); if (rc) goto out; e820_count = 0; nr_vmemrange = 0; vmemranges = NULL; array_size = 0; for (nid = 0; nid < b_info->num_vnuma_nodes; nid++) { libxl_vnode_info *p = &b_info->vnuma_nodes[nid]; uint64_t remaining_bytes = (p->memkb << 10), bytes; while (remaining_bytes > 0) { if (e820_count >= nr_e820) { rc = ERROR_NOMEM; goto out; } /* Skip non RAM region */ if (map[e820_count].type != E820_RAM) { e820_count++; continue; } if (nr_vmemrange >= array_size) { array_size += 32; GCREALLOC_ARRAY(vmemranges, array_size); } bytes = map[e820_count].size >= remaining_bytes ? remaining_bytes : map[e820_count].size; vmemranges[nr_vmemrange].start = map[e820_count].addr; vmemranges[nr_vmemrange].end = map[e820_count].addr + bytes; if (map[e820_count].size >= remaining_bytes) { map[e820_count].addr += bytes; map[e820_count].size -= bytes; } else { e820_count++; } remaining_bytes -= bytes; vmemranges[nr_vmemrange].flags = 0; vmemranges[nr_vmemrange].nid = nid; nr_vmemrange++; } } state->vmemranges = vmemranges; state->num_vmemranges = nr_vmemrange; rc = 0; out: return rc; }
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__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config, uint32_t domid) { int ret = 0; int tsc_mode; uint32_t rtc_timeoffset; libxl_ctx *ctx = libxl__gc_owner(gc); if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_PV) xc_domain_set_memmap_limit(ctx->xch, domid, (d_config->b_info.max_memkb + d_config->b_info.u.pv.slack_memkb)); switch (d_config->b_info.tsc_mode) { case LIBXL_TSC_MODE_DEFAULT: tsc_mode = 0; break; case LIBXL_TSC_MODE_ALWAYS_EMULATE: tsc_mode = 1; break; case LIBXL_TSC_MODE_NATIVE: tsc_mode = 2; break; case LIBXL_TSC_MODE_NATIVE_PARAVIRT: tsc_mode = 3; break; default: abort(); } xc_domain_set_tsc_info(ctx->xch, domid, tsc_mode, 0, 0, 0); if (libxl_defbool_val(d_config->b_info.disable_migrate)) xc_domain_disable_migrate(ctx->xch, domid); rtc_timeoffset = d_config->b_info.rtc_timeoffset; if (libxl_defbool_val(d_config->b_info.localtime)) { time_t t; struct tm *tm, result; t = time(NULL); tm = localtime_r(&t, &result); if (!tm) { LOGE(ERROR, "Failed to call localtime_r"); ret = ERROR_FAIL; goto out; } rtc_timeoffset += tm->tm_gmtoff; } if (rtc_timeoffset) xc_domain_set_time_offset(ctx->xch, domid, rtc_timeoffset); if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM || libxl_defbool_val(d_config->c_info.pvh)) { unsigned long shadow; shadow = (d_config->b_info.shadow_memkb + 1023) / 1024; xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL); } if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV && libxl_defbool_val(d_config->b_info.u.pv.e820_host)) { ret = libxl__e820_alloc(gc, domid, d_config); if (ret) { LOGE(ERROR, "Failed while collecting E820 with: %d (errno:%d)\n", ret, errno); } } 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 libxlMakeVfbList(virPortAllocatorPtr graphicsports, virDomainDefPtr def, libxl_domain_config *d_config) { virDomainGraphicsDefPtr *l_vfbs = def->graphics; int nvfbs = def->ngraphics; libxl_device_vfb *x_vfbs; libxl_device_vkb *x_vkbs; size_t i; if (nvfbs == 0) return 0; if (VIR_ALLOC_N(x_vfbs, nvfbs) < 0) return -1; if (VIR_ALLOC_N(x_vkbs, nvfbs) < 0) { VIR_FREE(x_vfbs); return -1; } for (i = 0; i < nvfbs; i++) { libxl_device_vkb_init(&x_vkbs[i]); if (libxlMakeVfb(graphicsports, l_vfbs[i], &x_vfbs[i]) < 0) goto error; } d_config->vfbs = x_vfbs; d_config->vkbs = x_vkbs; d_config->num_vfbs = d_config->num_vkbs = nvfbs; /* * VNC or SDL info must also be set in libxl_domain_build_info * for HVM domains. Use the first vfb device. */ if (STREQ(def->os.type, "hvm")) { libxl_domain_build_info *b_info = &d_config->b_info; libxl_device_vfb vfb = d_config->vfbs[0]; if (libxl_defbool_val(vfb.vnc.enable)) { libxl_defbool_set(&b_info->u.hvm.vnc.enable, true); if (VIR_STRDUP(b_info->u.hvm.vnc.listen, vfb.vnc.listen) < 0) goto error; if (VIR_STRDUP(b_info->u.hvm.vnc.passwd, vfb.vnc.passwd) < 0) goto error; b_info->u.hvm.vnc.display = vfb.vnc.display; libxl_defbool_set(&b_info->u.hvm.vnc.findunused, libxl_defbool_val(vfb.vnc.findunused)); } else if (libxl_defbool_val(vfb.sdl.enable)) { libxl_defbool_set(&b_info->u.hvm.sdl.enable, true); libxl_defbool_set(&b_info->u.hvm.sdl.opengl, libxl_defbool_val(vfb.sdl.opengl)); if (VIR_STRDUP(b_info->u.hvm.sdl.display, vfb.sdl.display) < 0) goto error; if (VIR_STRDUP(b_info->u.hvm.sdl.xauthority, vfb.sdl.xauthority) < 0) goto error; } } return 0; error: for (i = 0; i < nvfbs; i++) { libxl_device_vfb_dispose(&x_vfbs[i]); libxl_device_vkb_dispose(&x_vkbs[i]); } VIR_FREE(x_vfbs); VIR_FREE(x_vkbs); return -1; }
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->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; 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]); 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); }
/* * Checks for the beginnig and end of RAM in e820 map for domain * and aligns start of first and end of last vNUMA memory block to * that map. vnode memory size are passed here Megabytes. * For PV guest e820 map has fixed hole sizes. */ int libxl__vnuma_align_mem(libxl__gc *gc, uint32_t domid, libxl_domain_build_info *b_info, /* IN: mem sizes */ vmemrange_t *memblks) /* OUT: linux numa blocks in pfn */ { int i, j, rc; uint64_t next_start_pfn, end_max = 0, size, mem_hole; uint32_t nr; struct e820entry map[E820MAX]; if (b_info->nr_vnodes == 0) return -EINVAL; libxl_ctx *ctx = libxl__gc_owner(gc); /* retreive e820 map for this host */ rc = xc_get_machine_memory_map(ctx->xch, map, E820MAX); if (rc < 0) { errno = rc; return -EINVAL; } nr = rc; rc = e820_sanitize(ctx, map, &nr, b_info->target_memkb, (b_info->max_memkb - b_info->target_memkb) + b_info->u.pv.slack_memkb); if (rc) { errno = rc; return -EINVAL; } /* max pfn for this host */ for (j = nr - 1; j >= 0; j--) if (map[j].type == E820_RAM) { end_max = map[j].addr + map[j].size; break; } memset(memblks, 0, sizeof(*memblks) * b_info->nr_vnodes); next_start_pfn = 0; memblks[0].start = map[0].addr; for(i = 0; i < b_info->nr_vnodes; i++) { /* start can be not zero */ memblks[i].start += next_start_pfn; memblks[i].end = memblks[i].start + (b_info->vnuma_memszs[i] << 20); size = memblks[i].end - memblks[i].start; /* * For pv host with e820_host option turned on we need * to rake into account memory holes. For pv host with * e820_host disabled or unset, the map is contiguous * RAM region. */ if (libxl_defbool_val(b_info->u.pv.e820_host)) { while (mem_hole = e820_memory_hole_size(memblks[i].start, memblks[i].end, map, nr), memblks[i].end - memblks[i].start - mem_hole < size) { memblks[i].end += mem_hole; if (memblks[i].end > end_max) { memblks[i].end = end_max; break; } } } next_start_pfn = memblks[i].end; } if (memblks[i-1].end > end_max) memblks[i-1].end = end_max; return 0; }