From patchwork Wed Sep 25 15:48:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 11160995 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3CE451747 for ; Wed, 25 Sep 2019 15:51:29 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1736F21D7B for ; Wed, 25 Sep 2019 15:51:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1736F21D7B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iD9YF-00015x-SH; Wed, 25 Sep 2019 15:49:59 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iD9YD-000147-UH for xen-devel@lists.xenproject.org; Wed, 25 Sep 2019 15:49:57 +0000 X-Inumbo-ID: 15103845-dfac-11e9-9637-12813bfff9fa Received: from mga12.intel.com (unknown [192.55.52.136]) by localhost (Halon) with ESMTPS id 15103845-dfac-11e9-9637-12813bfff9fa; Wed, 25 Sep 2019 15:49:40 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Sep 2019 08:49:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,548,1559545200"; d="scan'208";a="193812722" Received: from tlengyel-mobl2.amr.corp.intel.com (HELO localhost.localdomain) ([10.252.129.153]) by orsmga006.jf.intel.com with ESMTP; 25 Sep 2019 08:49:39 -0700 From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Wed, 25 Sep 2019 08:48:56 -0700 Message-Id: X-Mailer: git-send-email 2.20.1 In-Reply-To: References: MIME-Version: 1.0 Subject: [Xen-devel] [RFC PATCH for-next 18/18] xen/tools: VM forking toolstack side X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Anthony PERARD , Ian Jackson , Tamas K Lengyel , Wei Liu Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Add necessary bits to implement "xl fork-vm" and "xl fork-launch-dm" commands. The process is split in two to allow tools needing access to the new VM as fast as possible after it was forked. It is expected that under certain use-cases the second command that launches QEMU will be skipped entirely. Signed-off-by: Tamas K Lengyel --- tools/libxc/include/xenctrl.h | 4 + tools/libxc/xc_memshr.c | 12 ++ tools/libxl/libxl.h | 6 + tools/libxl/libxl_create.c | 212 +++++++++++++++++++++++----------- tools/libxl/libxl_dm.c | 2 +- tools/libxl/libxl_dom.c | 83 ++++++++----- tools/libxl/libxl_internal.h | 1 + tools/libxl/libxl_types.idl | 1 + tools/xl/xl.h | 4 + tools/xl/xl_cmdtable.c | 15 +++ tools/xl/xl_saverestore.c | 69 +++++++++++ tools/xl/xl_vmcontrol.c | 8 ++ 12 files changed, 323 insertions(+), 94 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index b7c990aafd..8719893f1b 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2221,6 +2221,10 @@ int xc_memshr_range_share(xc_interface *xch, uint64_t first_gfn, uint64_t last_gfn); +int xc_memshr_fork(xc_interface *xch, + uint32_t source_domain, + uint32_t client_domain); + /* Debug calls: return the number of pages referencing the shared frame backing * the input argument. Should be one or greater. * diff --git a/tools/libxc/xc_memshr.c b/tools/libxc/xc_memshr.c index 5ef56a6933..1e01140e1d 100644 --- a/tools/libxc/xc_memshr.c +++ b/tools/libxc/xc_memshr.c @@ -237,6 +237,18 @@ int xc_memshr_debug_gref(xc_interface *xch, return xc_memshr_memop(xch, domid, &mso); } +int xc_memshr_fork(xc_interface *xch, uint32_t pdomid, uint32_t domid) +{ + xen_mem_sharing_op_t mso; + + memset(&mso, 0, sizeof(mso)); + + mso.op = XENMEM_sharing_op_fork; + mso.u.fork.parent_domain = pdomid; + + return xc_memshr_memop(xch, domid, &mso); +} + int xc_memshr_audit(xc_interface *xch) { xen_mem_sharing_op_t mso; diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 3421e5aa98..1ceda6f7de 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -1494,6 +1494,12 @@ int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config, const libxl_asyncop_how *ao_how, const libxl_asyncprogress_how *aop_console_how) LIBXL_EXTERNAL_CALLERS_ONLY; +int libxl_domain_fork_vm(libxl_ctx *ctx, uint32_t pdomid, uint32_t *domid) + LIBXL_EXTERNAL_CALLERS_ONLY; +int libxl_domain_fork_launch_dm(libxl_ctx *ctx, libxl_domain_config *d_config, + uint32_t domid, + const libxl_asyncprogress_how *aop_console_how) + LIBXL_EXTERNAL_CALLERS_ONLY; int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, uint32_t *domid, int restore_fd, int send_back_fd, diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 93fbe1d740..c38af0a214 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -535,12 +535,12 @@ out: return ret; } -int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, - libxl__domain_build_state *state, - uint32_t *domid) +static int libxl__domain_make_xs_entries(libxl__gc *gc, libxl_domain_config *d_config, + libxl__domain_build_state *state, + uint32_t domid) { libxl_ctx *ctx = libxl__gc_owner(gc); - int ret, rc, nb_vm; + int rc, nb_vm; const char *dom_type; char *uuid_string; char *dom_path, *vm_path, *libxl_path; @@ -552,7 +552,6 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, /* convenience aliases */ libxl_domain_create_info *info = &d_config->c_info; - libxl_domain_build_info *b_info = &d_config->b_info; uuid_string = libxl__uuid2string(gc, info->uuid); if (!uuid_string) { @@ -560,54 +559,7 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, goto out; } - /* Valid domid here means we're soft resetting. */ - if (!libxl_domid_valid_guest(*domid)) { - struct xen_domctl_createdomain create = { - .ssidref = info->ssidref, - .max_vcpus = b_info->max_vcpus, - .max_evtchn_port = b_info->event_channels, - .max_grant_frames = b_info->max_grant_frames, - .max_maptrack_frames = b_info->max_maptrack_frames, - }; - - if (info->type != LIBXL_DOMAIN_TYPE_PV) { - create.flags |= XEN_DOMCTL_CDF_hvm; - create.flags |= - libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0; - create.flags |= - libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; - } - - /* Ultimately, handle is an array of 16 uint8_t, same as uuid */ - libxl_uuid_copy(ctx, (libxl_uuid *)&create.handle, &info->uuid); - - ret = libxl__arch_domain_prepare_config(gc, d_config, &create); - if (ret < 0) { - LOGED(ERROR, *domid, "fail to get domain config"); - rc = ERROR_FAIL; - goto out; - } - - ret = xc_domain_create(ctx->xch, domid, &create); - if (ret < 0) { - LOGED(ERROR, *domid, "domain creation fail"); - rc = ERROR_FAIL; - goto out; - } - - rc = libxl__arch_domain_save_config(gc, d_config, state, &create); - if (rc < 0) - goto out; - } - - ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid); - if (ret < 0) { - LOGED(ERROR, *domid, "domain move fail"); - rc = ERROR_FAIL; - goto out; - } - - dom_path = libxl__xs_get_dompath(gc, *domid); + dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { rc = ERROR_FAIL; goto out; @@ -615,12 +567,12 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, vm_path = GCSPRINTF("/vm/%s", uuid_string); if (!vm_path) { - LOGD(ERROR, *domid, "cannot allocate create paths"); + LOGD(ERROR, domid, "cannot allocate create paths"); rc = ERROR_FAIL; goto out; } - libxl_path = libxl__xs_libxl_path(gc, *domid); + libxl_path = libxl__xs_libxl_path(gc, domid); if (!libxl_path) { rc = ERROR_FAIL; goto out; @@ -631,10 +583,10 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; - roperm[1].id = *domid; + roperm[1].id = domid; roperm[1].perms = XS_PERM_READ; - rwperm[0].id = *domid; + rwperm[0].id = domid; rwperm[0].perms = XS_PERM_NONE; retry_transaction: @@ -652,7 +604,7 @@ retry_transaction: noperm, ARRAY_SIZE(noperm)); xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, strlen(vm_path)); - rc = libxl__domain_rename(gc, *domid, 0, info->name, t); + rc = libxl__domain_rename(gc, domid, 0, info->name, t); if (rc) goto out; @@ -729,7 +681,7 @@ retry_transaction: vm_list = libxl_list_vm(ctx, &nb_vm); if (!vm_list) { - LOGD(ERROR, *domid, "cannot get number of running guests"); + LOGD(ERROR, domid, "cannot get number of running guests"); rc = ERROR_FAIL; goto out; } @@ -753,7 +705,7 @@ retry_transaction: t = 0; goto retry_transaction; } - LOGED(ERROR, *domid, "domain creation ""xenstore transaction commit failed"); + LOGED(ERROR, domid, "domain creation ""xenstore transaction commit failed"); rc = ERROR_FAIL; goto out; } @@ -765,6 +717,70 @@ retry_transaction: return rc; } +int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, + libxl__domain_build_state *state, + uint32_t *domid) +{ + libxl_ctx *ctx = libxl__gc_owner(gc); + int ret, rc; + + /* convenience aliases */ + libxl_domain_create_info *info = &d_config->c_info; + libxl_domain_build_info *b_info = &d_config->b_info; + + /* Valid domid here means we're soft resetting. */ + if (!libxl_domid_valid_guest(*domid)) { + struct xen_domctl_createdomain create = { + .ssidref = info->ssidref, + .max_vcpus = b_info->max_vcpus, + .max_evtchn_port = b_info->event_channels, + .max_grant_frames = b_info->max_grant_frames, + .max_maptrack_frames = b_info->max_maptrack_frames, + }; + + if (info->type != LIBXL_DOMAIN_TYPE_PV) { + create.flags |= XEN_DOMCTL_CDF_hvm; + create.flags |= + libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0; + create.flags |= + libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; + } + + /* Ultimately, handle is an array of 16 uint8_t, same as uuid */ + libxl_uuid_copy(ctx, (libxl_uuid *)&create.handle, &info->uuid); + + ret = libxl__arch_domain_prepare_config(gc, d_config, &create); + if (ret < 0) { + LOGED(ERROR, *domid, "fail to get domain config"); + rc = ERROR_FAIL; + goto out; + } + + ret = xc_domain_create(ctx->xch, domid, &create); + if (ret < 0) { + LOGED(ERROR, *domid, "domain creation fail"); + rc = ERROR_FAIL; + goto out; + } + + rc = libxl__arch_domain_save_config(gc, d_config, state, &create); + if (rc < 0) + goto out; + } + + ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid); + if (ret < 0) { + LOGED(ERROR, *domid, "domain move fail"); + rc = ERROR_FAIL; + goto out; + } + + rc = libxl__domain_make_xs_entries(gc, d_config, state, *domid); + +out: + return rc; +} + static int store_libxl_entry(libxl__gc *gc, uint32_t domid, libxl_domain_build_info *b_info) { @@ -985,15 +1001,31 @@ static void initiate_domain_create(libxl__egc *egc, goto error_out; } - ret = libxl__domain_make(gc, d_config, &dcs->build_state, &domid); - if (ret) { - LOGD(ERROR, domid, "cannot make domain: %d", ret); + if ( !d_config->dm_restore_file ) + { + ret = libxl__domain_make(gc, d_config, &dcs->build_state, &domid); dcs->guest_domid = domid; + + if (ret) { + LOGD(ERROR, domid, "cannot make domain: %d", ret); + ret = ERROR_FAIL; + goto error_out; + } + } else if ( dcs->guest_domid != INVALID_DOMID ) { + domid = dcs->guest_domid; + + ret = libxl__domain_make_xs_entries(gc, d_config, &dcs->build_state, domid); + if (ret) { + LOGD(ERROR, domid, "cannot make domain: %d", ret); + ret = ERROR_FAIL; + goto error_out; + } + } else { + LOGD(ERROR, domid, "cannot make domain"); ret = ERROR_FAIL; goto error_out; } - dcs->guest_domid = domid; dcs->sdss.dm.guest_domid = 0; /* means we haven't spawned */ /* @@ -1026,7 +1058,7 @@ static void initiate_domain_create(libxl__egc *egc, if (ret) goto error_out; - if (restore_fd >= 0 || dcs->domid_soft_reset != INVALID_DOMID) { + if (restore_fd >= 0 || dcs->domid_soft_reset != INVALID_DOMID || d_config->dm_restore_file) { LOGD(DEBUG, domid, "restoring, not running bootloader"); domcreate_bootloader_done(egc, &dcs->bl, 0); } else { @@ -1102,7 +1134,16 @@ static void domcreate_bootloader_done(libxl__egc *egc, dcs->sdss.dm.callback = domcreate_devmodel_started; dcs->sdss.callback = domcreate_devmodel_started; - if (restore_fd < 0 && dcs->domid_soft_reset == INVALID_DOMID) { + if (restore_fd < 0 && dcs->domid_soft_reset == INVALID_DOMID && !d_config->dm_restore_file) { + rc = libxl__domain_build(gc, d_config, domid, state); + domcreate_rebuild_done(egc, dcs, rc); + return; + } + + if ( d_config->dm_restore_file ) { + dcs->srs.dcs = dcs; + dcs->srs.ao = ao; + state->forked_vm = true; rc = libxl__domain_build(gc, d_config, domid, state); domcreate_rebuild_done(egc, dcs, rc); return; @@ -1300,6 +1341,7 @@ static void domcreate_rebuild_done(libxl__egc *egc, /* 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) { LOGD(ERROR, domid, "cannot (re-)build domain: %d", ret); @@ -1307,6 +1349,9 @@ static void domcreate_rebuild_done(libxl__egc *egc, goto error_out; } + if ( d_config->dm_restore_file ) + state->saved_state = GCSPRINTF("%s", d_config->dm_restore_file); + store_libxl_entry(gc, domid, &d_config->b_info); libxl__multidev_begin(ao, &dcs->multidev); @@ -1708,10 +1753,13 @@ static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config, GCNEW(cdcs); cdcs->dcs.ao = ao; cdcs->dcs.guest_config = d_config; + cdcs->dcs.guest_domid = *domid; + libxl_domain_config_init(&cdcs->dcs.guest_config_saved); libxl_domain_config_copy(ctx, &cdcs->dcs.guest_config_saved, d_config); cdcs->dcs.restore_fd = cdcs->dcs.libxc_fd = restore_fd; cdcs->dcs.send_back_fd = send_back_fd; + if (restore_fd > -1) { cdcs->dcs.restore_params = *params; rc = libxl__fd_flags_modify_save(gc, cdcs->dcs.restore_fd, @@ -1954,6 +2002,38 @@ int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config, ao_how, aop_console_how); } +int libxl_domain_fork_vm(libxl_ctx *ctx, uint32_t pdomid, uint32_t *domid) +{ + int rc; + struct xen_domctl_createdomain create = {0}; + create.flags |= XEN_DOMCTL_CDF_hvm; + create.flags |= XEN_DOMCTL_CDF_hap; + create.flags |= XEN_DOMCTL_CDF_oos_off; + create.arch.emulation_flags = (XEN_X86_EMU_ALL & ~XEN_X86_EMU_VPCI); + + create.ssidref = SECINITSID_DOMU; + create.max_vcpus = 1; // placeholder, will be cloned from pdomid + create.max_evtchn_port = 1023; + create.max_grant_frames = LIBXL_MAX_GRANT_FRAMES_DEFAULT; + create.max_maptrack_frames = LIBXL_MAX_MAPTRACK_FRAMES_DEFAULT; + + if ( (rc = xc_domain_create(ctx->xch, domid, &create)) ) + return rc; + + if ( (rc = xc_memshr_fork(ctx->xch, pdomid, *domid)) ) + xc_domain_destroy(ctx->xch, *domid); + + return rc; +} + +int libxl_domain_fork_launch_dm(libxl_ctx *ctx, libxl_domain_config *d_config, + uint32_t domid, + const libxl_asyncprogress_how *aop_console_how) +{ + unset_disk_colo_restore(d_config); + return do_domain_create(ctx, d_config, &domid, -1, -1, 0, 0, aop_console_how); +} + int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, uint32_t *domid, int restore_fd, int send_back_fd, diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index c00356a2f1..72c6fb7541 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -2785,7 +2785,7 @@ static void device_model_spawn_outcome(libxl__egc *egc, libxl__domain_build_state *state = dmss->build_state; - if (state->saved_state) { + if (state->saved_state && !state->forked_vm) { ret2 = unlink(state->saved_state); if (ret2) { LOGED(ERROR, dmss->guest_domid, "%s: failed to remove device-model state %s", diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index c5685b061c..6e07893e3e 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -391,9 +391,12 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid, libxl_domain_build_info *const info = &d_config->b_info; libxl_ctx *ctx = libxl__gc_owner(gc); char *xs_domid, *con_domid; - int rc; + int rc = 0; uint64_t size; + if ( state->forked_vm ) + goto skip_fork; + if (xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus) != 0) { LOG(ERROR, "Couldn't set max vcpu count"); return ERROR_FAIL; @@ -498,29 +501,6 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid, } } - - rc = libxl__arch_extra_memory(gc, info, &size); - if (rc < 0) { - LOGE(ERROR, "Couldn't get arch extra constant memory size"); - return ERROR_FAIL; - } - - if (xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + size) < 0) { - LOGE(ERROR, "Couldn't set max memory"); - return ERROR_FAIL; - } - - xs_domid = xs_read(ctx->xsh, XBT_NULL, "/tool/xenstored/domid", NULL); - state->store_domid = xs_domid ? atoi(xs_domid) : 0; - free(xs_domid); - - con_domid = xs_read(ctx->xsh, XBT_NULL, "/tool/xenconsoled/domid", NULL); - state->console_domid = con_domid ? atoi(con_domid) : 0; - free(con_domid); - - state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->store_domid); - state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid); - if (info->type != LIBXL_DOMAIN_TYPE_PV) hvm_set_conf_params(ctx->xch, domid, info); @@ -555,8 +535,34 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid, info->altp2m); } + rc = libxl__arch_extra_memory(gc, info, &size); + if (rc < 0) { + LOGE(ERROR, "Couldn't get arch extra constant memory size"); + return ERROR_FAIL; + } + + if (xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + size) < 0) { + LOGE(ERROR, "Couldn't set max memory"); + return ERROR_FAIL; + } + rc = libxl__arch_domain_create(gc, d_config, domid); + if ( rc ) + goto out; +skip_fork: + xs_domid = xs_read(ctx->xsh, XBT_NULL, "/tool/xenstored/domid", NULL); + state->store_domid = xs_domid ? atoi(xs_domid) : 0; + free(xs_domid); + + con_domid = xs_read(ctx->xsh, XBT_NULL, "/tool/xenconsoled/domid", NULL); + state->console_domid = con_domid ? atoi(con_domid) : 0; + free(con_domid); + + state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->store_domid); + state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid); + +out: return rc; } @@ -614,6 +620,9 @@ int libxl__build_post(libxl__gc *gc, uint32_t domid, char **ents; int i, rc; + if ( state->forked_vm ) + goto skip_fork; + if (info->num_vnuma_nodes && !info->num_vcpu_soft_affinity) { rc = set_vnuma_affinity(gc, domid, info); if (rc) @@ -638,6 +647,7 @@ int libxl__build_post(libxl__gc *gc, uint32_t domid, } } +skip_fork: ents = libxl__calloc(gc, 12 + (info->max_vcpus * 2) + 2, sizeof(char *)); ents[0] = "memory/static-max"; ents[1] = GCSPRINTF("%"PRId64, info->max_memkb); @@ -900,14 +910,16 @@ static int hvm_build_set_params(xc_interface *handle, uint32_t domid, libxl_domain_build_info *info, int store_evtchn, unsigned long *store_mfn, int console_evtchn, unsigned long *console_mfn, - domid_t store_domid, domid_t console_domid) + domid_t store_domid, domid_t console_domid, + bool forked_vm) { struct hvm_info_table *va_hvm; uint8_t *va_map, sum; uint64_t str_mfn, cons_mfn; int i; - if (info->type == LIBXL_DOMAIN_TYPE_HVM) { + if ( info->type == LIBXL_DOMAIN_TYPE_HVM && !forked_vm ) + { va_map = xc_map_foreign_range(handle, domid, XC_PAGE_SIZE, PROT_READ | PROT_WRITE, HVM_INFO_PFN); @@ -1223,6 +1235,23 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid, struct xc_dom_image *dom = NULL; bool device_model = info->type == LIBXL_DOMAIN_TYPE_HVM ? true : false; + if ( state->forked_vm ) + { + rc = hvm_build_set_params(ctx->xch, domid, info, state->store_port, + &state->store_mfn, state->console_port, + &state->console_mfn, state->store_domid, + state->console_domid, state->forked_vm); + + if ( rc ) + return rc; + + return xc_dom_gnttab_seed(ctx->xch, domid, true, + state->console_mfn, + state->store_mfn, + state->console_domid, + state->store_domid); + } + xc_dom_loginit(ctx->xch); /* @@ -1347,7 +1376,7 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid, rc = hvm_build_set_params(ctx->xch, domid, info, state->store_port, &state->store_mfn, state->console_port, &state->console_mfn, state->store_domid, - state->console_domid); + state->console_domid, false); if (rc != 0) { LOG(ERROR, "hvm build set params failed"); goto out; diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index bfeb38e0ed..0becfc3e31 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1271,6 +1271,7 @@ typedef struct { char *saved_state; int dm_monitor_fd; + bool forked_vm; libxl__file_reference pv_kernel; libxl__file_reference pv_ramdisk; diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 04c9762af1..f12c1882dc 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -946,6 +946,7 @@ libxl_domain_config = Struct("domain_config", [ ("on_watchdog", libxl_action_on_shutdown), ("on_crash", libxl_action_on_shutdown), ("on_soft_reset", libxl_action_on_shutdown), + ("dm_restore_file", string, {'const': True}), ], dir=DIR_IN) libxl_diskinfo = Struct("diskinfo", [ diff --git a/tools/xl/xl.h b/tools/xl/xl.h index 60bdad8ffb..993a63d268 100644 --- a/tools/xl/xl.h +++ b/tools/xl/xl.h @@ -31,6 +31,7 @@ struct cmd_spec { }; struct domain_create { + uint32_t ddomid; /* fork launch dm for this domid */ int debug; int daemonize; int monitor; /* handle guest reboots etc */ @@ -45,6 +46,7 @@ struct domain_create { const char *config_file; char *extra_config; /* extra config string */ const char *restore_file; + const char *dm_restore_file; char *colo_proxy_script; bool userspace_colo_proxy; int migrate_fd; /* -1 means none */ @@ -127,6 +129,8 @@ int main_pciassignable_remove(int argc, char **argv); int main_pciassignable_list(int argc, char **argv); #ifndef LIBXL_HAVE_NO_SUSPEND_RESUME int main_restore(int argc, char **argv); +int main_fork_vm(int argc, char **argv); +int main_fork_launch_dm(int argc, char **argv); int main_migrate_receive(int argc, char **argv); int main_save(int argc, char **argv); int main_migrate(int argc, char **argv); diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c index 5baa6023aa..902b3d7b01 100644 --- a/tools/xl/xl_cmdtable.c +++ b/tools/xl/xl_cmdtable.c @@ -180,6 +180,21 @@ struct cmd_spec cmd_table[] = { "-V, --vncviewer Connect to the VNC display after the domain is created.\n" "-A, --vncviewer-autopass Pass VNC password to viewer via stdin." }, + { "fork-vm", + &main_fork_vm, 0, 1, + "Fork a domain from the running parent domid", + "[options] ", + "-h Print this help.\n" + "-d Enable debug messages.\n" + }, + { "fork-launch-dm", + &main_fork_launch_dm, 0, 1, + "Launch the device model for a forked VM", + "[options] ", + "-h Print this help.\n" + "-p Do not unpause domain after restoring it.\n" + "-d Enable debug messages.\n" + }, { "migrate-receive", &main_migrate_receive, 0, 1, "Restore a domain from a saved state", diff --git a/tools/xl/xl_saverestore.c b/tools/xl/xl_saverestore.c index 9be033fe65..ba0e300f2c 100644 --- a/tools/xl/xl_saverestore.c +++ b/tools/xl/xl_saverestore.c @@ -229,6 +229,75 @@ int main_restore(int argc, char **argv) return EXIT_SUCCESS; } +int main_fork_vm(int argc, char **argv) +{ + int debug = 0; + uint32_t pdomid = 0, domid = INVALID_DOMID; + int opt; + + SWITCH_FOREACH_OPT(opt, "d", NULL, "fork-vm", 1) { + case 'd': + debug = 1; + break; + } + + if (argc-optind == 1) { + pdomid = atoi(argv[optind]); + } else { + help("fork-vm"); + return EXIT_FAILURE; + } + + if (libxl_domain_fork_vm(ctx, pdomid, &domid) || domid == INVALID_DOMID) + return EXIT_FAILURE; + + fprintf(stderr, "VM fork created with domid: %u\n", domid); + return EXIT_SUCCESS; +} + +int main_fork_launch_dm(int argc, char **argv) +{ + const char *config_file = NULL; + const char *dm_restore_file = NULL; + struct domain_create dom_info; + int paused = 0, debug = 0; + uint32_t ddomid = 0; + int opt, rc; + + SWITCH_FOREACH_OPT(opt, "pd", NULL, "fork-launch-dm", 1) { + case 'p': + paused = 1; + break; + case 'd': + debug = 1; + break; + } + + if (argc-optind == 3) { + config_file = argv[optind]; + dm_restore_file = argv[optind + 1]; + ddomid = atoi(argv[optind + 2]); + } else { + help("fork-launch-dm"); + return EXIT_FAILURE; + } + + memset(&dom_info, 0, sizeof(dom_info)); + dom_info.ddomid = ddomid; + dom_info.dm_restore_file = dm_restore_file; + dom_info.debug = debug; + dom_info.paused = paused; + dom_info.config_file = config_file; + dom_info.migrate_fd = -1; + dom_info.send_back_fd = -1; + + rc = create_domain(&dom_info); + if (rc < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + int main_save(int argc, char **argv) { uint32_t domid; diff --git a/tools/xl/xl_vmcontrol.c b/tools/xl/xl_vmcontrol.c index eb6779a561..f32a4714ee 100644 --- a/tools/xl/xl_vmcontrol.c +++ b/tools/xl/xl_vmcontrol.c @@ -645,6 +645,7 @@ int create_domain(struct domain_create *dom_info) libxl_domain_config d_config; + uint32_t ddomid = dom_info->ddomid; // launch dm for this domain iff set int debug = dom_info->debug; int daemonize = dom_info->daemonize; int monitor = dom_info->monitor; @@ -655,6 +656,7 @@ int create_domain(struct domain_create *dom_info) const char *restore_file = dom_info->restore_file; const char *config_source = NULL; const char *restore_source = NULL; + const char *dm_restore_file = dom_info->dm_restore_file; int migrate_fd = dom_info->migrate_fd; bool config_in_json; @@ -923,6 +925,12 @@ start: * restore/migrate-receive it again. */ restoring = 0; + } else if ( ddomid ) { + d_config.dm_restore_file = dm_restore_file; + ret = libxl_domain_fork_launch_dm(ctx, &d_config, ddomid, + autoconnect_console_how); + domid = ddomid; + ddomid = INVALID_DOMID; } else if (domid_soft_reset != INVALID_DOMID) { /* Do soft reset. */ ret = libxl_domain_soft_reset(ctx, &d_config, domid_soft_reset,