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; }
void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss) { STATE_AO_GC(sdss->dm.spawn.ao); libxl_ctx *ctx = libxl__gc_owner(gc); int ret; libxl_device_vfb *vfb; libxl_device_vkb *vkb; char **args; struct xs_permissions perm[2]; xs_transaction_t t; /* convenience aliases */ libxl_domain_config *const dm_config = &sdss->dm_config; libxl_domain_config *const guest_config = sdss->dm.guest_config; const int guest_domid = sdss->dm.guest_domid; libxl__domain_build_state *const d_state = sdss->dm.build_state; libxl__domain_build_state *const stubdom_state = &sdss->dm_state; if (guest_config->b_info.device_model_version != LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL) { ret = ERROR_INVAL; goto out; } sdss->pvqemu.guest_domid = 0; libxl_domain_create_info_init(&dm_config->c_info); dm_config->c_info.type = LIBXL_DOMAIN_TYPE_PV; dm_config->c_info.name = libxl__stub_dm_name(gc, libxl__domid_to_name(gc, guest_domid)); dm_config->c_info.ssidref = guest_config->b_info.device_model_ssidref; libxl_uuid_generate(&dm_config->c_info.uuid); libxl_domain_build_info_init(&dm_config->b_info); libxl_domain_build_info_init_type(&dm_config->b_info, LIBXL_DOMAIN_TYPE_PV); dm_config->b_info.max_vcpus = 1; dm_config->b_info.max_memkb = 32 * 1024; dm_config->b_info.target_memkb = dm_config->b_info.max_memkb; dm_config->b_info.u.pv.features = ""; dm_config->b_info.device_model_version = guest_config->b_info.device_model_version; dm_config->b_info.device_model = guest_config->b_info.device_model; dm_config->b_info.extra = guest_config->b_info.extra; dm_config->b_info.extra_pv = guest_config->b_info.extra_pv; dm_config->b_info.extra_hvm = guest_config->b_info.extra_hvm; dm_config->disks = guest_config->disks; dm_config->num_disks = guest_config->num_disks; libxl__dm_vifs_from_hvm_guest_config(gc, guest_config, dm_config); dm_config->c_info.run_hotplug_scripts = guest_config->c_info.run_hotplug_scripts; ret = libxl__domain_create_info_setdefault(gc, &dm_config->c_info); if (ret) goto out; ret = libxl__domain_build_info_setdefault(gc, &dm_config->b_info); if (ret) goto out; GCNEW(vfb); GCNEW(vkb); libxl__vfb_and_vkb_from_hvm_guest_config(gc, guest_config, vfb, vkb); dm_config->vfbs = vfb; dm_config->num_vfbs = 1; dm_config->vkbs = vkb; dm_config->num_vkbs = 1; stubdom_state->pv_kernel.path = libxl__abs_path(gc, "ioemu-stubdom.gz", libxl__xenfirmwaredir_path()); stubdom_state->pv_cmdline = libxl__sprintf(gc, " -d %d", guest_domid); stubdom_state->pv_ramdisk.path = ""; /* fixme: this function can leak the stubdom if it fails */ ret = libxl__domain_make(gc, &dm_config->c_info, &sdss->pvqemu.guest_domid); if (ret) goto out; uint32_t dm_domid = sdss->pvqemu.guest_domid; ret = libxl__domain_build(gc, dm_config, dm_domid, stubdom_state); if (ret) goto out; args = libxl__build_device_model_args(gc, "stubdom-dm", guest_domid, guest_config, d_state); if (!args) { ret = ERROR_FAIL; goto out; } libxl__write_stub_dmargs(gc, dm_domid, guest_domid, args); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/image/device-model-domid", libxl__xs_get_dompath(gc, guest_domid)), "%d", dm_domid); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/target", libxl__xs_get_dompath(gc, dm_domid)), "%d", guest_domid); ret = xc_domain_set_target(ctx->xch, dm_domid, guest_domid); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", dm_domid, guest_domid); ret = ERROR_FAIL; goto out; } xs_set_target(ctx->xsh, dm_domid, guest_domid); perm[0].id = dm_domid; perm[0].perms = XS_PERM_NONE; perm[1].id = guest_domid; perm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_mkdir(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid), perm, ARRAY_SIZE(perm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; libxl__multidev_begin(ao, &sdss->multidev); sdss->multidev.callback = spawn_stub_launch_dm; libxl__add_disks(egc, ao, dm_domid, dm_config, &sdss->multidev); libxl__multidev_prepared(egc, &sdss->multidev, 0); return; out: assert(ret); spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret); }
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 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); }