[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] libxl: carve out domain specific functions from libxl.c



commit 59164cefd474ec70a7494ccff92d94e1e21692d0
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Wed Feb 8 17:09:31 2017 +0100
Commit:     Wei Liu <wei.liu2@xxxxxxxxxx>
CommitDate: Mon Feb 13 10:59:19 2017 +0000

    libxl: carve out domain specific functions from libxl.c
    
    libxl.c has grown to an uncomfortable size. Carve out the domain
    related functions to libxl_domain.c.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Wei Liu <wei.liu2@xxxxxxxxxx>
    Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 tools/libxl/Makefile       |    1 +
 tools/libxl/libxl.c        | 1808 ++------------------------------------------
 tools/libxl/libxl_domain.c | 1744 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1788 insertions(+), 1765 deletions(-)

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 99ddae1..6cc7b45 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -138,6 +138,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o 
libxl_pci.o \
                        libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
                        libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
                        libxl_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.o \
+                       libxl_domain.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 101cbb9..0ef8744 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -16,8 +16,6 @@
 
 #include "libxl_internal.h"
 
-#define PAGE_TO_MEMKB(pages) ((pages) * 4)
-
 int libxl_ctx_alloc(libxl_ctx **pctx, int version,
                     unsigned flags, xentoollog_logger * lg)
 {
@@ -287,1251 +285,69 @@ void libxl_key_value_list_dispose(libxl_key_value_list 
*pkvl)
     *pkvl = NULL;
 }
 
-void libxl_key_value_list_copy(libxl_ctx *ctx,
-                               libxl_key_value_list *dst,
-                               const libxl_key_value_list *src)
-{
-    GC_INIT(ctx);
-    int i, len;
-
-    if (*src == NULL) {
-        *dst = NULL;
-        goto out;
-    }
-
-    len = libxl_key_value_list_length(src);
-    /* one extra slot for sentinel */
-    *dst = libxl__calloc(NOGC, len * 2 + 1, sizeof(char *));
-
-    for (i = 0; i < len * 2; i += 2) {
-        (*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
-        if ((*src)[i+1])
-            (*dst)[i+1] = libxl__strdup(NOGC, (*src)[i+1]);
-        else
-            (*dst)[i+1] = NULL;
-    }
-
-out:
-    GC_FREE;
-}
-
-void libxl_defbool_set(libxl_defbool *db, bool b)
-{
-    db->val = b ? LIBXL__DEFBOOL_TRUE : LIBXL__DEFBOOL_FALSE;
-}
-
-void libxl_defbool_unset(libxl_defbool *db)
-{
-    db->val = LIBXL__DEFBOOL_DEFAULT;
-}
-
-bool libxl_defbool_is_default(libxl_defbool db)
-{
-    return !db.val;
-}
-
-void libxl_defbool_setdefault(libxl_defbool *db, bool b)
-{
-    if (libxl_defbool_is_default(*db))
-        libxl_defbool_set(db, b);
-}
-
-bool libxl_defbool_val(libxl_defbool db)
-{
-    assert(!libxl_defbool_is_default(db));
-    return db.val > 0;
-}
-
-const char *libxl_defbool_to_string(libxl_defbool b)
-{
-    if (b.val < 0)
-        return LIBXL__DEFBOOL_STR_FALSE;
-    else if (b.val > 0)
-        return LIBXL__DEFBOOL_STR_TRUE;
-    else
-        return LIBXL__DEFBOOL_STR_DEFAULT;
-}
-
-/******************************************************************************/
-int libxl__domain_rename(libxl__gc *gc, uint32_t domid,
-                         const char *old_name, const char *new_name,
-                         xs_transaction_t trans)
-{
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-    char *dom_path = 0;
-    const char *name_path;
-    char *got_old_name;
-    unsigned int got_old_len;
-    xs_transaction_t our_trans = 0;
-    uint32_t stub_dm_domid;
-    const char *stub_dm_old_name = NULL, *stub_dm_new_name = NULL;
-    int rc;
-    libxl_dominfo info;
-    char *uuid;
-    const char *vm_name_path;
-
-    libxl_dominfo_init(&info);
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) goto x_nomem;
-
-    name_path= GCSPRINTF("%s/name", dom_path);
-    if (!name_path) goto x_nomem;
-
-    stub_dm_domid = libxl_get_stubdom_id(CTX, domid);
-    if (stub_dm_domid) {
-        stub_dm_old_name = libxl__stub_dm_name(gc, old_name);
-        stub_dm_new_name = libxl__stub_dm_name(gc, new_name);
-    }
-
- retry_transaction:
-    if (!trans) {
-        trans = our_trans = xs_transaction_start(ctx->xsh);
-        if (!our_trans) {
-            LOGEVD(ERROR, errno, domid, "Create xs transaction for domain 
(re)name");
-            goto x_fail;
-        }
-    }
-
-    if (!new_name) {
-        LOGD(ERROR, domid, "New domain name not specified");
-        rc = ERROR_INVAL;
-        goto x_rc;
-    }
-
-    if (new_name[0]) {
-        /* nonempty names must be unique */
-        uint32_t domid_e;
-        rc = libxl_name_to_domid(ctx, new_name, &domid_e);
-        if (rc == ERROR_INVAL) {
-            /* no such domain, good */
-        } else if (rc != 0) {
-            LOGD(ERROR, domid, "Unexpected error checking for existing 
domain");
-            goto x_rc;
-        } else if (domid_e == domid) {
-            /* domain already has this name, ok (but we do still
-             * need the rest of the code as we may need to check
-             * old_name, for example). */
-        } else {
-            LOGD(ERROR, domid, "Domain with name \"%s\" already exists.", 
new_name);
-            rc = ERROR_INVAL;
-            goto x_rc;
-        }
-    }
-
-    if (old_name) {
-        got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
-        if (!got_old_name) {
-            LOGEVD(ERROR, errno, domid,
-                   "Check old name for domain allegedly named `%s'",
-                   old_name);
-            goto x_fail;
-        }
-        if (strcmp(old_name, got_old_name)) {
-            LOGD(ERROR, domid,
-                 "Allegedly named `%s' is actually named `%s' - racing ?",
-                 old_name,
-                 got_old_name);
-            free(got_old_name);
-            goto x_fail;
-        }
-        free(got_old_name);
-    }
-    if (!xs_write(ctx->xsh, trans, name_path,
-                  new_name, strlen(new_name))) {
-        LOGD(ERROR, domid,
-             "Failed to write new name `%s'"
-             " for domain previously named `%s'",
-             new_name,
-             old_name);
-        goto x_fail;
-    }
-
-    /* update /vm/<uuid>/name */
-    rc = libxl_domain_info(ctx, &info, domid);
-    if (rc)
-        goto x_rc;
-
-    uuid = GCSPRINTF(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid));
-    vm_name_path = GCSPRINTF("/vm/%s/name", uuid);
-    if (libxl__xs_write_checked(gc, trans, vm_name_path, new_name))
-        goto x_fail;
-
-    if (stub_dm_domid) {
-        rc = libxl__domain_rename(gc, stub_dm_domid,
-                                  stub_dm_old_name,
-                                  stub_dm_new_name,
-                                  trans);
-        if (rc) {
-            LOGED(ERROR, domid, "Unable to rename stub-domain");
-            goto x_rc;
-        }
-    }
-
-    if (our_trans) {
-        if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
-            trans = our_trans = 0;
-            if (errno != EAGAIN) {
-                LOGD(ERROR, domid,
-                     "Failed to commit new name `%s'"
-                     " for domain previously named `%s'",
-                     new_name,
-                     old_name);
-                goto x_fail;
-            }
-            LOGD(DEBUG, domid,
-                 "Need to retry rename transaction"
-                 " for domain (name_path=\"%s\", new_name=\"%s\")",
-                 name_path,
-                 new_name);
-            goto retry_transaction;
-        }
-        our_trans = 0;
-    }
-
-    rc = 0;
- x_rc:
-    if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
-    libxl_dominfo_dispose(&info);
-    return rc;
-
- x_fail:  rc = ERROR_FAIL;  goto x_rc;
- x_nomem: rc = ERROR_NOMEM; goto x_rc;
-}
-
-int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
-                        const char *old_name, const char *new_name)
-{
-    GC_INIT(ctx);
-    int rc;
-    rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL);
-    GC_FREE;
-    return rc;
-}
-
-int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel,
-                        const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc = libxl__domain_resume(gc, domid, suspend_cancel);
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-/*
- * Preserves a domain but rewrites xenstore etc to make it unique so
- * that the domain can be restarted.
- *
- * Does not modify info so that it may be reused.
- */
-int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
-                          libxl_domain_create_info *info, const char 
*name_suffix, libxl_uuid new_uuid)
-{
-    GC_INIT(ctx);
-    struct xs_permissions roperm[2];
-    xs_transaction_t t;
-    char *preserved_name;
-    char *uuid_string;
-    char *vm_path;
-    char *dom_path;
-
-    int rc;
-
-    preserved_name = GCSPRINTF("%s%s", info->name, name_suffix);
-    if (!preserved_name) {
-        GC_FREE;
-        return ERROR_NOMEM;
-    }
-
-    uuid_string = libxl__uuid2string(gc, new_uuid);
-    if (!uuid_string) {
-        GC_FREE;
-        return ERROR_NOMEM;
-    }
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-
-    vm_path = GCSPRINTF("/vm/%s", uuid_string);
-    if (!vm_path) {
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-
-    roperm[0].id = 0;
-    roperm[0].perms = XS_PERM_NONE;
-    roperm[1].id = domid;
-    roperm[1].perms = XS_PERM_READ;
-
- retry_transaction:
-    t = xs_transaction_start(ctx->xsh);
-
-    xs_rm(ctx->xsh, t, vm_path);
-    xs_mkdir(ctx->xsh, t, vm_path);
-    xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
-
-    xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, 
strlen(vm_path));
-    rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t);
-    if (rc) {
-        GC_FREE;
-        return rc;
-    }
-
-    xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, 
strlen(uuid_string));
-
-    if (!xs_transaction_end(ctx->xsh, t, 0))
-        if (errno == EAGAIN)
-            goto retry_transaction;
-
-    GC_FREE;
-    return 0;
-}
-
-void libxl__xcinfo2xlinfo(libxl_ctx *ctx,
-                          const xc_domaininfo_t *xcinfo,
-                          libxl_dominfo *xlinfo)
-{
-    size_t size;
-
-    memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
-    xlinfo->domid = xcinfo->domain;
-    xlinfo->ssidref = xcinfo->ssidref;
-    if (libxl_flask_sid_to_context(ctx, xlinfo->ssidref,
-                                   &xlinfo->ssid_label, &size) < 0)
-        xlinfo->ssid_label = NULL;
-
-    xlinfo->dying      = !!(xcinfo->flags&XEN_DOMINF_dying);
-    xlinfo->shutdown   = !!(xcinfo->flags&XEN_DOMINF_shutdown);
-    xlinfo->paused     = !!(xcinfo->flags&XEN_DOMINF_paused);
-    xlinfo->blocked    = !!(xcinfo->flags&XEN_DOMINF_blocked);
-    xlinfo->running    = !!(xcinfo->flags&XEN_DOMINF_running);
-    xlinfo->never_stop = !!(xcinfo->flags&XEN_DOMINF_xs_domain);
-
-    if (xlinfo->shutdown)
-        xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask;
-    else
-        xlinfo->shutdown_reason = LIBXL_SHUTDOWN_REASON_UNKNOWN;
-
-    xlinfo->outstanding_memkb = PAGE_TO_MEMKB(xcinfo->outstanding_pages);
-    xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
-    xlinfo->shared_memkb = PAGE_TO_MEMKB(xcinfo->shr_pages);
-    xlinfo->paged_memkb = PAGE_TO_MEMKB(xcinfo->paged_pages);
-    xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->max_pages);
-    xlinfo->cpu_time = xcinfo->cpu_time;
-    xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
-    xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
-    xlinfo->cpupool = xcinfo->cpupool;
-    xlinfo->domain_type = (xcinfo->flags & XEN_DOMINF_hvm_guest) ?
-        LIBXL_DOMAIN_TYPE_HVM : LIBXL_DOMAIN_TYPE_PV;
-}
-
-libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain_out)
-{
-    libxl_dominfo *ptr = NULL;
-    int i, ret;
-    xc_domaininfo_t info[1024];
-    int size = 0;
-    uint32_t domid = 0;
-    GC_INIT(ctx);
-
-    while ((ret = xc_domain_getinfolist(ctx->xch, domid, 1024, info)) > 0) {
-        ptr = libxl__realloc(NOGC, ptr, (size + ret) * sizeof(libxl_dominfo));
-        for (i = 0; i < ret; i++) {
-            libxl__xcinfo2xlinfo(ctx, &info[i], &ptr[size + i]);
-        }
-        domid = info[ret - 1].domain + 1;
-        size += ret;
-    }
-
-    if (ret < 0) {
-        LOGE(ERROR, "getting domain info list");
-        free(ptr);
-        GC_FREE;
-        return NULL;
-    }
-
-    *nb_domain_out = size;
-    GC_FREE;
-    return ptr;
-}
-
-int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
-                      uint32_t domid) {
-    xc_domaininfo_t xcinfo;
-    int ret;
-    GC_INIT(ctx);
-
-    ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
-    if (ret<0) {
-        LOGED(ERROR, domid, "Getting domain info list");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    if (ret==0 || xcinfo.domain != domid) {
-        GC_FREE;
-        return ERROR_DOMAIN_NOTFOUND;
-    }
-
-    if (info_r)
-        libxl__xcinfo2xlinfo(ctx, &xcinfo, info_r);
-    GC_FREE;
-    return 0;
-}
-
-/* this API call only list VM running on this host. A VM can
- * be an aggregate of multiple domains. */
-libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm_out)
-{
-    GC_INIT(ctx);
-    libxl_dominfo *info;
-    libxl_vminfo *ptr = NULL;
-    int idx, i, n_doms;
-
-    info = libxl_list_domain(ctx, &n_doms);
-    if (!info)
-        goto out;
-
-    /*
-     * Always make sure to allocate at least one element; if we don't and we
-     * request zero, libxl__calloc (might) think its internal call to calloc
-     * has failed (if it returns null), if so it would kill our process.
-     */
-    ptr = libxl__calloc(NOGC, n_doms ? n_doms : 1, sizeof(libxl_vminfo));
-
-    for (idx = i = 0; i < n_doms; i++) {
-        if (libxl_is_stubdom(ctx, info[i].domid, NULL))
-            continue;
-        ptr[idx].uuid = info[i].uuid;
-        ptr[idx].domid = info[i].domid;
-
-        idx++;
-    }
-    *nb_vm_out = idx;
-    libxl_dominfo_list_free(info, n_doms);
-
-out:
-    GC_FREE;
-    return ptr;
-}
-
-static void remus_failover_cb(libxl__egc *egc,
-                              libxl__domain_save_state *dss, int rc);
-
-int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info,
-                             uint32_t domid, int send_fd, int recv_fd,
-                             const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__domain_save_state *dss;
-    int rc;
-
-    libxl_domain_type type = libxl__domain_type(gc, domid);
-    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /* The caller must set this defbool */
-    if (libxl_defbool_is_default(info->colo)) {
-        LOGD(ERROR, domid, "Colo mode must be enabled/disabled");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    libxl_defbool_setdefault(&info->allow_unsafe, false);
-    libxl_defbool_setdefault(&info->blackhole, false);
-    libxl_defbool_setdefault(&info->compression,
-                             !libxl_defbool_val(info->colo));
-    libxl_defbool_setdefault(&info->netbuf, true);
-    libxl_defbool_setdefault(&info->diskbuf, true);
-
-    if (libxl_defbool_val(info->colo) &&
-        libxl_defbool_val(info->compression)) {
-            LOGD(ERROR, domid, "Cannot use memory checkpoint "
-                        "compression in COLO mode");
-            rc = ERROR_FAIL;
-            goto out;
-    }
-
-    if (!libxl_defbool_val(info->allow_unsafe) &&
-        (libxl_defbool_val(info->blackhole) ||
-         !libxl_defbool_val(info->netbuf) ||
-         !libxl_defbool_val(info->diskbuf))) {
-        LOGD(ERROR, domid, "Unsafe mode must be enabled to replicate to 
/dev/null,"
-                    "disable network buffering and disk replication");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-
-    GCNEW(dss);
-    dss->ao = ao;
-    dss->callback = remus_failover_cb;
-    dss->domid = domid;
-    dss->fd = send_fd;
-    dss->recv_fd = recv_fd;
-    dss->type = type;
-    dss->live = 1;
-    dss->debug = 0;
-    dss->remus = info;
-    if (libxl_defbool_val(info->colo))
-        dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_COLO;
-    else
-        dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_REMUS;
-
-    assert(info);
-
-    /* Point of no return */
-    if (libxl_defbool_val(info->colo))
-        libxl__colo_save_setup(egc, &dss->css);
-    else
-        libxl__remus_setup(egc, &dss->rs);
-    return AO_INPROGRESS;
-
- out:
-    return AO_CREATE_FAIL(rc);
-}
-
-static void remus_failover_cb(libxl__egc *egc,
-                              libxl__domain_save_state *dss, int rc)
-{
-    STATE_AO_GC(dss->ao);
-    /*
-     * With Remus, if we reach this point, it means either
-     * backup died or some network error occurred preventing us
-     * from sending checkpoints.
-     */
-    libxl__ao_complete(egc, ao, rc);
-}
-
-static void domain_suspend_cb(libxl__egc *egc,
-                              libxl__domain_save_state *dss, int rc)
-{
-    STATE_AO_GC(dss->ao);
-    int flrc;
-
-    flrc = libxl__fd_flags_restore(gc, dss->fd, dss->fdfl);
-    /* If suspend has failed already then report that error not this one. */
-    if (flrc && !rc) rc = flrc;
-
-    libxl__ao_complete(egc,ao,rc);
-
-}
-
-int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, int flags,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    libxl_domain_type type = libxl__domain_type(gc, domid);
-    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
-        rc = ERROR_FAIL;
-        goto out_err;
-    }
-
-    libxl__domain_save_state *dss;
-    GCNEW(dss);
-
-    dss->ao = ao;
-    dss->callback = domain_suspend_cb;
-
-    dss->domid = domid;
-    dss->fd = fd;
-    dss->type = type;
-    dss->live = flags & LIBXL_SUSPEND_LIVE;
-    dss->debug = flags & LIBXL_SUSPEND_DEBUG;
-    dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_NONE;
-
-    rc = libxl__fd_flags_modify_save(gc, dss->fd,
-                                     ~(O_NONBLOCK|O_NDELAY), 0,
-                                     &dss->fdfl);
-    if (rc < 0) goto out_err;
-
-    libxl__domain_save(egc, dss);
-    return AO_INPROGRESS;
-
- out_err:
-    return AO_CREATE_FAIL(rc);
-}
-
-int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
-{
-    int ret;
-    GC_INIT(ctx);
-    ret = xc_domain_pause(ctx->xch, domid);
-    if (ret<0) {
-        LOGED(ERROR, domid, "Pausing domain");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    GC_FREE;
-    return 0;
-}
-
-int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid,
-                           const char *filename,
-                           const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int ret, rc;
-
-    ret = xc_domain_dumpcore(ctx->xch, domid, filename);
-    if (ret<0) {
-        LOGED(ERROR, domid, "Core dumping domain to %s", filename);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-
-    libxl__ao_complete(egc, ao, rc);
-
-    return AO_INPROGRESS;
-}
-
-int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    int ret, rc = 0;
-
-    libxl_domain_type type = libxl__domain_type(gc, domid);
-    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (type == LIBXL_DOMAIN_TYPE_HVM) {
-        if (libxl__device_model_version_running(gc, domid) !=
-            LIBXL_DEVICE_MODEL_VERSION_NONE) {
-            rc = libxl__domain_resume_device_model(gc, domid);
-            if (rc < 0) {
-                LOGD(ERROR, domid, "Failed to unpause device model for 
domain:%d",
-                     rc);
-                goto out;
-            }
-        }
-    }
-    ret = xc_domain_unpause(ctx->xch, domid);
-    if (ret<0) {
-        LOGED(ERROR, domid, "Unpausing domain");
-        rc = ERROR_FAIL;
-    }
- out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl__domain_pvcontrol_available(libxl__gc *gc, uint32_t domid)
-{
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-
-    uint64_t pvdriver = 0;
-    int ret;
-
-    libxl_domain_type domtype = libxl__domain_type(gc, domid);
-    if (domtype == LIBXL_DOMAIN_TYPE_INVALID)
-        return ERROR_FAIL;
-
-    if (domtype == LIBXL_DOMAIN_TYPE_PV)
-        return 1;
-
-    ret = xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
-    if (ret<0) {
-        LOGED(ERROR, domid, "Getting HVM callback IRQ");
-        return ERROR_FAIL;
-    }
-    return !!pvdriver;
-}
-
-const char *libxl__domain_pvcontrol_xspath(libxl__gc *gc, uint32_t domid)
-{
-    const char *dom_path;
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path)
-        return NULL;
-
-    return GCSPRINTF("%s/control/shutdown", dom_path);
-}
-
-char * libxl__domain_pvcontrol_read(libxl__gc *gc, xs_transaction_t t,
-                                    uint32_t domid)
-{
-    const char *shutdown_path;
-
-    shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
-    if (!shutdown_path)
-        return NULL;
-
-    return libxl__xs_read(gc, t, shutdown_path);
-}
-
-int libxl__domain_pvcontrol_write(libxl__gc *gc, xs_transaction_t t,
-                                  uint32_t domid, const char *cmd)
-{
-    const char *shutdown_path;
-
-    shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
-    if (!shutdown_path)
-        return ERROR_FAIL;
-
-    return libxl__xs_printf(gc, t, shutdown_path, "%s", cmd);
-}
-
-static int libxl__domain_pvcontrol(libxl__gc *gc, uint32_t domid,
-                                   const char *cmd)
-{
-    int ret;
-
-    ret = libxl__domain_pvcontrol_available(gc, domid);
-    if (ret < 0)
-        return ret;
-
-    if (!ret)
-        return ERROR_NOPARAVIRT;
-
-    return libxl__domain_pvcontrol_write(gc, XBT_NULL, domid, cmd);
-}
-
-int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    int ret;
-    ret = libxl__domain_pvcontrol(gc, domid, "poweroff");
-    GC_FREE;
-    return ret;
-}
-
-int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    int ret;
-    ret = libxl__domain_pvcontrol(gc, domid, "reboot");
-    GC_FREE;
-    return ret;
-}
-
-static void domain_death_occurred(libxl__egc *egc,
-                                  libxl_evgen_domain_death **evg_upd,
-                                  const char *why) {
-    /* Removes **evg_upd from death_list and puts it on death_reported
-     * and advances *evg_upd to the next entry.
-     * Call sites in domain_death_xswatch_callback must use "continue". */
-    EGC_GC;
-    libxl_evgen_domain_death *const evg = *evg_upd;
-
-    LOGD(DEBUG, evg->domid, "%s", why);
-
-    libxl_evgen_domain_death *evg_next = LIBXL_TAILQ_NEXT(evg, entry);
-    *evg_upd = evg_next;
-
-    libxl_event *ev = NEW_EVENT(egc, DOMAIN_DEATH, evg->domid, evg->user);
-
-    libxl__event_occurred(egc, ev);
-
-    evg->death_reported = 1;
-    LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
-    LIBXL_TAILQ_INSERT_HEAD(&CTX->death_reported, evg, entry);
-}
-
-static void domain_death_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch 
*w,
-                                        const char *wpath, const char *epath) {
-    EGC_GC;
-    libxl_evgen_domain_death *evg;
-    int rc;
-
-    CTX_LOCK;
-
-    evg = LIBXL_TAILQ_FIRST(&CTX->death_list);
-
-    for (;;) {
-        if (!evg) goto out;
-
-        int nentries = LIBXL_TAILQ_NEXT(evg, entry) ? 200 : 1;
-        xc_domaininfo_t domaininfos[nentries];
-        const xc_domaininfo_t *got = domaininfos, *gotend;
-
-        rc = xc_domain_getinfolist(CTX->xch, evg->domid, nentries, 
domaininfos);
-        if (rc == -1) {
-            LIBXL__EVENT_DISASTER(egc, "xc_domain_getinfolist failed while"
-                                  " processing @releaseDomain watch event",
-                                  errno, 0);
-            goto out;
-        }
-        gotend = &domaininfos[rc];
-
-        LOGD(DEBUG, evg->domid, "[evg=%p] nentries=%d rc=%d %ld..%ld",
-             evg, nentries, rc,
-             rc>0 ? (long)domaininfos[0].domain : 0,
-             rc>0 ? (long)domaininfos[rc-1].domain : 0);
-
-        for (;;) {
-            if (!evg) {
-                LOG(DEBUG, "[evg=0] all reported");
-                goto all_reported;
-            }
-
-            LOGD(DEBUG, evg->domid, "[evg=%p]"
-                 "   got=domaininfos[%d] got->domain=%ld",
-                 evg, (int)(got - domaininfos),
-                 got < gotend ? (long)got->domain : -1L);
-
-            if (!rc) {
-                domain_death_occurred(egc, &evg, "empty list");
-                continue;
-            }
-
-            if (got == gotend) {
-                LOG(DEBUG, " got==gotend");
-                break;
-            }
-
-            if (got->domain > evg->domid) {
-                /* ie, the list doesn't contain evg->domid any more so
-                 * the domain has been destroyed */
-                domain_death_occurred(egc, &evg, "missing from list");
-                continue;
-            }
-
-            if (got->domain < evg->domid) {
-                got++;
-                continue;
-            }
-
-            assert(evg->domid == got->domain);
-            LOGD(DEBUG, evg->domid, "Exists shutdown_reported=%d"" 
dominf.flags=%x",
-                 evg->shutdown_reported, got->flags);
-
-            if (got->flags & XEN_DOMINF_dying) {
-                domain_death_occurred(egc, &evg, "dying");
-                continue;
-            }
-
-            if (!evg->shutdown_reported &&
-                (got->flags & XEN_DOMINF_shutdown)) {
-                libxl_event *ev = NEW_EVENT(egc, DOMAIN_SHUTDOWN,
-                                            got->domain, evg->user);
-
-                LOG(DEBUG, " shutdown reporting");
-
-                ev->u.domain_shutdown.shutdown_reason =
-                    (got->flags >> XEN_DOMINF_shutdownshift) &
-                    XEN_DOMINF_shutdownmask;
-                libxl__event_occurred(egc, ev);
-
-                evg->shutdown_reported = 1;
-            }
-            evg = LIBXL_TAILQ_NEXT(evg, entry);
-        }
-
-        assert(rc); /* rc==0 results in us eating all evgs and quitting */
-    }
- all_reported:
- out:
-
-    LOG(DEBUG, "domain death search done");
-
-    CTX_UNLOCK;
-}
-
-int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid,
-                libxl_ev_user user, libxl_evgen_domain_death **evgen_out) {
-    GC_INIT(ctx);
-    libxl_evgen_domain_death *evg, *evg_search;
-    int rc;
-
-    CTX_LOCK;
-
-    evg = malloc(sizeof(*evg));  if (!evg) { rc = ERROR_NOMEM; goto out; }
-    memset(evg, 0, sizeof(*evg));
-    evg->domid = domid;
-    evg->user = user;
-
-    LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, ,
-                              evg->domid > evg_search->domid);
-
-    if (!libxl__ev_xswatch_isregistered(&ctx->death_watch)) {
-        rc = libxl__ev_xswatch_register(gc, &ctx->death_watch,
-                        domain_death_xswatch_callback, "@releaseDomain");
-        if (rc) { libxl__evdisable_domain_death(gc, evg); goto out; }
-    }
-
-    *evgen_out = evg;
-    rc = 0;
-
- out:
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-};
-
-void libxl__evdisable_domain_death(libxl__gc *gc,
-                                   libxl_evgen_domain_death *evg) {
-    CTX_LOCK;
-
-    if (!evg->death_reported)
-        LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
-    else
-        LIBXL_TAILQ_REMOVE(&CTX->death_reported, evg, entry);
-
-    free(evg);
-
-    if (!LIBXL_TAILQ_FIRST(&CTX->death_list) &&
-        libxl__ev_xswatch_isregistered(&CTX->death_watch))
-        libxl__ev_xswatch_deregister(gc, &CTX->death_watch);
-
-    CTX_UNLOCK;
-}
-
-void libxl_evdisable_domain_death(libxl_ctx *ctx,
-                                  libxl_evgen_domain_death *evg) {
-    GC_INIT(ctx);
-    libxl__evdisable_domain_death(gc, evg);
-    GC_FREE;
-}
-
-/* Callbacks for libxl_domain_destroy */
-
-static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state 
*dds,
-                              int rc);
-
-int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__domain_destroy_state *dds;
-
-    GCNEW(dds);
-    dds->ao = ao;
-    dds->domid = domid;
-    dds->callback = domain_destroy_cb;
-    libxl__domain_destroy(egc, dds);
-
-    return AO_INPROGRESS;
-}
-
-static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state 
*dds,
-                              int rc)
-{
-    STATE_AO_GC(dds->ao);
-
-    if (rc)
-        LOGD(ERROR, dds->domid, "Destruction of domain failed");
-
-    libxl__ao_complete(egc, ao, rc);
-}
-
-/* Callbacks for libxl__domain_destroy */
-
-static void stubdom_destroy_callback(libxl__egc *egc,
-                                     libxl__destroy_domid_state *dis,
-                                     int rc);
-
-static void domain_destroy_callback(libxl__egc *egc,
-                                    libxl__destroy_domid_state *dis,
-                                    int rc);
-
-static void destroy_finish_check(libxl__egc *egc,
-                                 libxl__domain_destroy_state *dds);
-
-void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds)
-{
-    STATE_AO_GC(dds->ao);
-    uint32_t stubdomid = libxl_get_stubdom_id(CTX, dds->domid);
-
-    if (stubdomid) {
-        dds->stubdom.ao = ao;
-        dds->stubdom.domid = stubdomid;
-        dds->stubdom.callback = stubdom_destroy_callback;
-        dds->stubdom.soft_reset = false;
-        libxl__destroy_domid(egc, &dds->stubdom);
-    } else {
-        dds->stubdom_finished = 1;
-    }
-
-    dds->domain.ao = ao;
-    dds->domain.domid = dds->domid;
-    dds->domain.callback = domain_destroy_callback;
-    dds->domain.soft_reset = dds->soft_reset;
-    libxl__destroy_domid(egc, &dds->domain);
-}
-
-static void stubdom_destroy_callback(libxl__egc *egc,
-                                     libxl__destroy_domid_state *dis,
-                                     int rc)
-{
-    STATE_AO_GC(dis->ao);
-    libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, stubdom);
-    const char *savefile;
-
-    if (rc) {
-        LOGD(ERROR, dds->domain.domid, "Unable to destroy stubdom with domid 
%u",
-             dis->domid);
-        dds->rc = rc;
-    }
-
-    dds->stubdom_finished = 1;
-    savefile = libxl__device_model_savefile(gc, dis->domid);
-    rc = libxl__remove_file(gc, savefile);
-    if (rc) {
-        LOGD(ERROR, dds->domain.domid, "Failed to remove device-model savefile 
%s",
-             savefile);
-    }
-
-    destroy_finish_check(egc, dds);
-}
-
-static void domain_destroy_callback(libxl__egc *egc,
-                                    libxl__destroy_domid_state *dis,
-                                    int rc)
-{
-    STATE_AO_GC(dis->ao);
-    libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, domain);
-
-    if (rc) {
-        LOGD(ERROR, dis->domid, "Unable to destroy guest");
-        dds->rc = rc;
-    }
-
-    dds->domain_finished = 1;
-    destroy_finish_check(egc, dds);
-}
-
-static void destroy_finish_check(libxl__egc *egc,
-                                 libxl__domain_destroy_state *dds)
-{
-    if (!(dds->domain_finished && dds->stubdom_finished))
-        return;
-
-    dds->callback(egc, dds, dds->rc);
-}
-
-/* Callbacks for libxl__destroy_domid */
-static void devices_destroy_cb(libxl__egc *egc,
-                               libxl__devices_remove_state *drs,
-                               int rc);
-
-static void domain_destroy_domid_cb(libxl__egc *egc,
-                                    libxl__ev_child *destroyer,
-                                    pid_t pid, int status);
-
-void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
-{
-    STATE_AO_GC(dis->ao);
-    libxl_ctx *ctx = CTX;
-    uint32_t domid = dis->domid;
-    char *dom_path;
-    int rc, dm_present;
-
-    libxl__ev_child_init(&dis->destroyer);
-
-    rc = libxl_domain_info(ctx, NULL, domid);
-    switch(rc) {
-    case 0:
-        break;
-    case ERROR_DOMAIN_NOTFOUND:
-        LOGD(ERROR, domid, "Non-existant domain");
-    default:
-        goto out;
-    }
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        if (libxl_get_stubdom_id(CTX, domid)) {
-            dm_present = 0;
-            break;
-        }
-        /* fall through */
-    case LIBXL_DOMAIN_TYPE_PV:
-        dm_present = libxl__dm_active(gc, domid);
-        break;
-    case LIBXL_DOMAIN_TYPE_INVALID:
-        rc = ERROR_FAIL;
-        goto out;
-    default:
-        abort();
-    }
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (libxl__device_pci_destroy_all(gc, domid) < 0)
-        LOGD(ERROR, domid, "Pci shutdown failed");
-    rc = xc_domain_pause(ctx->xch, domid);
-    if (rc < 0) {
-        LOGEVD(ERROR, rc, domid, "xc_domain_pause failed");
-    }
-    if (dm_present) {
-        if (libxl__destroy_device_model(gc, domid) < 0)
-            LOGD(ERROR, domid, "libxl__destroy_device_model failed");
-
-        libxl__qmp_cleanup(gc, domid);
-    }
-    dis->drs.ao = ao;
-    dis->drs.domid = domid;
-    dis->drs.callback = devices_destroy_cb;
-    dis->drs.force = 1;
-    libxl__devices_destroy(egc, &dis->drs);
-    return;
-
-out:
-    assert(rc);
-    dis->callback(egc, dis, rc);
-    return;
-}
-
-static void devices_destroy_cb(libxl__egc *egc,
-                               libxl__devices_remove_state *drs,
-                               int rc)
+void libxl_key_value_list_copy(libxl_ctx *ctx,
+                               libxl_key_value_list *dst,
+                               const libxl_key_value_list *src)
 {
-    STATE_AO_GC(drs->ao);
-    libxl__destroy_domid_state *dis = CONTAINER_OF(drs, *dis, drs);
-    libxl_ctx *ctx = CTX;
-    uint32_t domid = dis->domid;
-    char *dom_path;
-    char *vm_path;
-    libxl__domain_userdata_lock *lock;
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        rc = ERROR_FAIL;
+    GC_INIT(ctx);
+    int i, len;
+
+    if (*src == NULL) {
+        *dst = NULL;
         goto out;
     }
 
-    if (rc < 0)
-        LOGD(ERROR, domid, "libxl__devices_destroy failed");
-
-    vm_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vm", dom_path));
-    if (vm_path)
-        if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
-            LOGED(ERROR, domid, "xs_rm failed for %s", vm_path);
-
-    if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
-        LOGED(ERROR, domid, "xs_rm failed for %s", dom_path);
-
-    xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid));
-    xs_rm(ctx->xsh, XBT_NULL, GCSPRINTF( "/local/domain/%d/hvmloader", domid));
+    len = libxl_key_value_list_length(src);
+    /* one extra slot for sentinel */
+    *dst = libxl__calloc(NOGC, len * 2 + 1, sizeof(char *));
 
-    /* This is async operation, we already hold CTX lock */
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out;
-    }
-    libxl__userdata_destroyall(gc, domid);
-
-    libxl__unlock_domain_userdata(lock);
-
-    /* Clean up qemu-save and qemu-resume files. They are
-     * intermediate files created by libxc. Unfortunately they
-     * don't fit in existing userdata scheme very well. In soft reset
-     * case we need to keep the file.
-     */
-    if (!dis->soft_reset) {
-        rc = libxl__remove_file(gc,
-                                libxl__device_model_savefile(gc, domid));
-        if (rc < 0) goto out;
-    }
-    rc = libxl__remove_file(gc,
-             GCSPRINTF(LIBXL_DEVICE_MODEL_RESTORE_FILE".%u", domid));
-    if (rc < 0) goto out;
-
-    rc = libxl__ev_child_fork(gc, &dis->destroyer, domain_destroy_domid_cb);
-    if (rc < 0) goto out;
-    if (!rc) { /* child */
-        ctx->xch = xc_interface_open(ctx->lg,0,0);
-        if (!ctx->xch) goto badchild;
-
-        if (!dis->soft_reset) {
-            rc = xc_domain_destroy(ctx->xch, domid);
-        } else {
-            rc = xc_domain_pause(ctx->xch, domid);
-            if (rc < 0) goto badchild;
-            rc = xc_domain_soft_reset(ctx->xch, domid);
-            if (rc < 0) goto badchild;
-            rc = xc_domain_unpause(ctx->xch, domid);
-        }
-        if (rc < 0) goto badchild;
-        _exit(0);
-
-    badchild:
-        if (errno > 0  && errno < 126) {
-            _exit(errno);
-        } else {
-            LOGED(ERROR, domid,
- "xc_domain_destroy failed (with difficult errno value %d)",
-                  errno);
-            _exit(-1);
-        }
+    for (i = 0; i < len * 2; i += 2) {
+        (*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
+        if ((*src)[i+1])
+            (*dst)[i+1] = libxl__strdup(NOGC, (*src)[i+1]);
+        else
+            (*dst)[i+1] = NULL;
     }
-    LOGD(DEBUG, domid, "Forked pid %ld for destroy of domain", (long)rc);
-
-    return;
 
 out:
-    dis->callback(egc, dis, rc);
-    return;
+    GC_FREE;
 }
 
-static void domain_destroy_domid_cb(libxl__egc *egc,
-                                    libxl__ev_child *destroyer,
-                                    pid_t pid, int status)
+void libxl_defbool_set(libxl_defbool *db, bool b)
 {
-    libxl__destroy_domid_state *dis = CONTAINER_OF(destroyer, *dis, destroyer);
-    STATE_AO_GC(dis->ao);
-    int rc;
-
-    if (status) {
-        if (WIFEXITED(status) && WEXITSTATUS(status)<126) {
-            LOGEVD(ERROR, WEXITSTATUS(status), dis->domid,
-                   "xc_domain_destroy failed");
-        } else {
-            libxl_report_child_exitstatus(CTX, XTL_ERROR,
-                                          "async domain destroy", pid, status);
-        }
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    rc = 0;
-
- out:
-    dis->callback(egc, dis, rc);
+    db->val = b ? LIBXL__DEFBOOL_TRUE : LIBXL__DEFBOOL_FALSE;
 }
 
-int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
+void libxl_defbool_unset(libxl_defbool *db)
 {
-    int rc;
-    const char *xs_domid;
-
-    rc = libxl__xs_read_checked(gc, XBT_NULL, DOMID_XS_PATH, &xs_domid);
-    if (rc) goto out;
-    if (!xs_domid) {
-        LOG(ERROR, "failed to get own domid (%s)", DOMID_XS_PATH);
-        rc = ERROR_FAIL;
-        goto out;
-    }
+    db->val = LIBXL__DEFBOOL_DEFAULT;
+}
 
-    *domid = atoi(xs_domid);
+bool libxl_defbool_is_default(libxl_defbool db)
+{
+    return !db.val;
+}
 
-out:
-    return rc;
+void libxl_defbool_setdefault(libxl_defbool *db, bool b)
+{
+    if (libxl_defbool_is_default(*db))
+        libxl_defbool_set(db, b);
 }
 
-/******************************************************************************/
+bool libxl_defbool_val(libxl_defbool db)
+{
+    assert(!libxl_defbool_is_default(db));
+    return db.val > 0;
+}
 
-int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
+const char *libxl_defbool_to_string(libxl_defbool b)
 {
-    if (!name)
-        return 0;
-    return libxl_domain_qualifier_to_domid(CTX, name, domid);
+    if (b.val < 0)
+        return LIBXL__DEFBOOL_STR_FALSE;
+    else if (b.val > 0)
+        return LIBXL__DEFBOOL_STR_TRUE;
+    else
+        return LIBXL__DEFBOOL_STR_DEFAULT;
 }
 
 
/******************************************************************************/
@@ -1810,254 +626,6 @@ const libxl_version_info* 
libxl_get_version_info(libxl_ctx *ctx)
     return info;
 }
 
-libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
-                                       int *nr_vcpus_out, int *nr_cpus_out)
-{
-    GC_INIT(ctx);
-    libxl_vcpuinfo *ptr, *ret;
-    xc_domaininfo_t domaininfo;
-    xc_vcpuinfo_t vcpuinfo;
-
-    if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
-        LOGED(ERROR, domid, "Getting infolist");
-        GC_FREE;
-        return NULL;
-    }
-
-    if (domaininfo.max_vcpu_id == XEN_INVALID_MAX_VCPU_ID) {
-        GC_FREE;
-        return NULL;
-    }
-
-    *nr_cpus_out = libxl_get_max_cpus(ctx);
-    ret = ptr = libxl__calloc(NOGC, domaininfo.max_vcpu_id + 1,
-                              sizeof(libxl_vcpuinfo));
-
-    for (*nr_vcpus_out = 0;
-         *nr_vcpus_out <= domaininfo.max_vcpu_id;
-         ++*nr_vcpus_out, ++ptr) {
-        libxl_bitmap_init(&ptr->cpumap);
-        if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap, 0))
-            goto err;
-        libxl_bitmap_init(&ptr->cpumap_soft);
-        if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap_soft, 0))
-            goto err;
-        if (xc_vcpu_getinfo(ctx->xch, domid, *nr_vcpus_out, &vcpuinfo) == -1) {
-            LOGED(ERROR, domid, "Getting vcpu info");
-            goto err;
-        }
-
-        if (xc_vcpu_getaffinity(ctx->xch, domid, *nr_vcpus_out,
-                                ptr->cpumap.map, ptr->cpumap_soft.map,
-                                XEN_VCPUAFFINITY_SOFT|XEN_VCPUAFFINITY_HARD) 
== -1) {
-            LOGED(ERROR, domid, "Getting vcpu affinity");
-            goto err;
-        }
-        ptr->vcpuid = *nr_vcpus_out;
-        ptr->cpu = vcpuinfo.cpu;
-        ptr->online = !!vcpuinfo.online;
-        ptr->blocked = !!vcpuinfo.blocked;
-        ptr->running = !!vcpuinfo.running;
-        ptr->vcpu_time = vcpuinfo.cpu_time;
-    }
-    GC_FREE;
-    return ret;
-
-err:
-    libxl_bitmap_dispose(&ptr->cpumap);
-    libxl_bitmap_dispose(&ptr->cpumap_soft);
-    free(ret);
-    GC_FREE;
-    return NULL;
-}
-
-static int libxl__set_vcpuonline_xenstore(libxl__gc *gc, uint32_t domid,
-                                         libxl_bitmap *cpumap,
-                                         const libxl_dominfo *info)
-{
-    char *dompath;
-    xs_transaction_t t;
-    int i, rc = ERROR_FAIL;
-
-    if (!(dompath = libxl__xs_get_dompath(gc, domid)))
-        goto out;
-
-retry_transaction:
-    t = xs_transaction_start(CTX->xsh);
-    for (i = 0; i <= info->vcpu_max_id; i++)
-        libxl__xs_printf(gc, t,
-                         GCSPRINTF("%s/cpu/%u/availability", dompath, i),
-                         "%s", libxl_bitmap_test(cpumap, i) ? "online" : 
"offline");
-    if (!xs_transaction_end(CTX->xsh, t, 0)) {
-        if (errno == EAGAIN)
-            goto retry_transaction;
-    } else
-        rc = 0;
-out:
-    return rc;
-}
-
-static int libxl__set_vcpuonline_qmp(libxl__gc *gc, uint32_t domid,
-                                     libxl_bitmap *cpumap,
-                                     const libxl_dominfo *info)
-{
-    int i, rc;
-    libxl_bitmap current_map, final_map;
-
-    libxl_bitmap_init(&current_map);
-    libxl_bitmap_init(&final_map);
-
-    libxl_bitmap_alloc(CTX, &current_map, info->vcpu_max_id + 1);
-    libxl_bitmap_set_none(&current_map);
-    rc = libxl__qmp_query_cpus(gc, domid, &current_map);
-    if (rc) {
-        LOGD(ERROR, domid, "Failed to query cpus");
-        goto out;
-    }
-
-    libxl_bitmap_copy_alloc(CTX, &final_map, cpumap);
-
-    libxl_for_each_set_bit(i, current_map)
-        libxl_bitmap_reset(&final_map, i);
-
-    libxl_for_each_set_bit(i, final_map) {
-        rc = libxl__qmp_cpu_add(gc, domid, i);
-        if (rc) {
-            LOGD(ERROR, domid, "Failed to add cpu %d", i);
-            goto out;
-        }
-    }
-
-    rc = 0;
-out:
-    libxl_bitmap_dispose(&current_map);
-    libxl_bitmap_dispose(&final_map);
-    return rc;
-}
-
-int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *cpumap)
-{
-    GC_INIT(ctx);
-    int rc, maxcpus;
-    libxl_dominfo info;
-
-    libxl_dominfo_init(&info);
-
-    rc = libxl_domain_info(CTX, &info, domid);
-    if (rc < 0) {
-        LOGED(ERROR, domid, "Getting domain info list");
-        goto out;
-    }
-
-    maxcpus = libxl_bitmap_count_set(cpumap);
-    if (maxcpus > info.vcpu_max_id + 1)
-    {
-        LOGED(ERROR, domid, "Requested %d VCPUs, however maxcpus is %d!",
-              maxcpus, info.vcpu_max_id + 1);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        switch (libxl__device_model_version_running(gc, domid)) {
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-        case LIBXL_DEVICE_MODEL_VERSION_NONE:
-            break;
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-            rc = libxl__set_vcpuonline_qmp(gc, domid, cpumap, &info);
-            break;
-        default:
-            rc = ERROR_INVAL;
-        }
-        break;
-    case LIBXL_DOMAIN_TYPE_PV:
-        break;
-    default:
-        rc = ERROR_INVAL;
-    }
-
-    if (!rc)
-        rc = libxl__set_vcpuonline_xenstore(gc, domid, cpumap, &info);
-
-out:
-    libxl_dominfo_dispose(&info);
-    GC_FREE;
-    return rc;
-}
-
-static int libxl__domain_s3_resume(libxl__gc *gc, int domid)
-{
-    int rc = 0;
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        switch (libxl__device_model_version_running(gc, domid)) {
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-            rc = xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_ACPI_S_STATE, 0);
-            break;
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-            rc = libxl__qmp_system_wakeup(gc, domid);
-            break;
-        default:
-            rc = ERROR_INVAL;
-            break;
-        }
-        break;
-    default:
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    return rc;
-}
-
-int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid,
-                       libxl_trigger trigger, uint32_t vcpuid)
-{
-    int rc;
-    GC_INIT(ctx);
-
-    switch (trigger) {
-    case LIBXL_TRIGGER_POWER:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_POWER, vcpuid);
-        break;
-    case LIBXL_TRIGGER_SLEEP:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_SLEEP, vcpuid);
-        break;
-    case LIBXL_TRIGGER_NMI:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_NMI, vcpuid);
-        break;
-    case LIBXL_TRIGGER_INIT:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_INIT, vcpuid);
-        break;
-    case LIBXL_TRIGGER_RESET:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_RESET, vcpuid);
-        break;
-    case LIBXL_TRIGGER_S3RESUME:
-        rc = libxl__domain_s3_resume(gc, domid);
-        break;
-    default:
-        rc = -1;
-        errno = EINVAL;
-        break;
-    }
-
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Send trigger '%s' failed",
-              libxl_trigger_to_string(trigger));
-        rc = ERROR_FAIL;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
 {
     GC_INIT(ctx);
@@ -2084,27 +652,6 @@ int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
     return 0;
 }
 
-uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    char *dompath = libxl__xs_get_dompath(gc, domid);
-    char *vm_path, *start_time;
-    uint32_t ret;
-
-    vm_path = libxl__xs_read(
-        gc, XBT_NULL, GCSPRINTF("%s/vm", dompath));
-    start_time = libxl__xs_read(
-        gc, XBT_NULL, GCSPRINTF("%s/start_time", vm_path));
-    if (start_time == NULL) {
-        LOGEVD(ERROR, -1, domid, "Can't get start time of domain");
-        ret = -1;
-    }else{
-        ret = strtoul(start_time, NULL, 10);
-    }
-    GC_FREE;
-    return ret;
-}
-
 static int fd_set_flags(libxl_ctx *ctx, int fd,
                         int fcntlgetop, int fcntlsetop, const char *fl,
                         int flagmask, int set_p)
@@ -2212,275 +759,6 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, 
const libxl_mac *src)
         (*dst)[i] = (*src)[i];
 }
 
-/* For QEMU upstream we always need to provide the number of cpus present to
- * QEMU whether they are online or not; otherwise QEMU won't accept the saved
- * state. See implementation of libxl__qmp_query_cpus.
- */
-static int libxl__update_avail_vcpus_qmp(libxl__gc *gc, uint32_t domid,
-                                         unsigned int max_vcpus,
-                                         libxl_bitmap *map)
-{
-    int rc;
-
-    rc = libxl__qmp_query_cpus(gc, domid, map);
-    if (rc) {
-        LOGD(ERROR, domid, "Fail to get number of cpus");
-        goto out;
-    }
-
-    rc = 0;
-out:
-    return rc;
-}
-
-static int libxl__update_avail_vcpus_xenstore(libxl__gc *gc, uint32_t domid,
-                                              unsigned int max_vcpus,
-                                              libxl_bitmap *map)
-{
-    int rc;
-    unsigned int i;
-    const char *dompath;
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    if (!dompath) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    for (i = 0; i < max_vcpus; i++) {
-        const char *path = GCSPRINTF("%s/cpu/%u/availability", dompath, i);
-        const char *content;
-        rc = libxl__xs_read_checked(gc, XBT_NULL, path, &content);
-        if (rc) goto out;
-        if (content && !strcmp(content, "online"))
-            libxl_bitmap_set(map, i);
-    }
-
-    rc = 0;
-out:
-    return rc;
-}
-
-int libxl_retrieve_domain_configuration(libxl_ctx *ctx, uint32_t domid,
-                                        libxl_domain_config *d_config)
-{
-    GC_INIT(ctx);
-    int rc;
-    libxl__domain_userdata_lock *lock = NULL;
-
-    CTX_LOCK;
-
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out;
-    }
-
-    rc = libxl__get_domain_configuration(gc, domid, d_config);
-    if (rc) {
-        LOGD(ERROR, domid, "Fail to get domain configuration");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /* Domain name */
-    {
-        char *domname;
-        domname = libxl_domid_to_name(ctx, domid);
-        if (!domname) {
-            LOGD(ERROR, domid, "Fail to get domain name");
-            goto out;
-        }
-        free(d_config->c_info.name);
-        d_config->c_info.name = domname; /* steals allocation */
-    }
-
-    /* Domain UUID */
-    {
-        libxl_dominfo info;
-        libxl_dominfo_init(&info);
-        rc = libxl_domain_info(ctx, &info, domid);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get domain info");
-            libxl_dominfo_dispose(&info);
-            goto out;
-        }
-        libxl_uuid_copy(ctx, &d_config->c_info.uuid, &info.uuid);
-        libxl_dominfo_dispose(&info);
-    }
-
-    /* VCPUs */
-    {
-        libxl_bitmap *map = &d_config->b_info.avail_vcpus;
-        unsigned int max_vcpus = d_config->b_info.max_vcpus;
-        libxl_device_model_version version;
-
-        libxl_bitmap_dispose(map);
-        libxl_bitmap_init(map);
-        libxl_bitmap_alloc(CTX, map, max_vcpus);
-        libxl_bitmap_set_none(map);
-
-        switch (d_config->b_info.type) {
-        case LIBXL_DOMAIN_TYPE_HVM:
-            version = libxl__device_model_version_running(gc, domid);
-            assert(version != LIBXL_DEVICE_MODEL_VERSION_UNKNOWN);
-            switch (version) {
-            case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-                rc = libxl__update_avail_vcpus_qmp(gc, domid,
-                                                   max_vcpus, map);
-                break;
-            case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-            case LIBXL_DEVICE_MODEL_VERSION_NONE:
-                rc = libxl__update_avail_vcpus_xenstore(gc, domid,
-                                                        max_vcpus, map);
-                break;
-            default:
-                abort();
-            }
-            break;
-        case LIBXL_DOMAIN_TYPE_PV:
-            rc = libxl__update_avail_vcpus_xenstore(gc, domid,
-                                                    max_vcpus, map);
-            break;
-        default:
-            abort();
-        }
-
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to update available cpu map");
-            goto out;
-        }
-    }
-
-    /* Memory limits:
-     *
-     * Currently there are three memory limits:
-     *  1. "target" in xenstore (originally memory= in config file)
-     *  2. "static-max" in xenstore (originally maxmem= in config file)
-     *  3. "max_memkb" in hypervisor
-     *
-     * The third one is not visible and currently managed by
-     * toolstack. In order to rebuild a domain we only need to have
-     * "target" and "static-max".
-     */
-    {
-        uint64_t target_memkb = 0, max_memkb = 0;
-
-        /* "target" */
-        rc = libxl__get_memory_target(gc, domid, &target_memkb, &max_memkb);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get memory target");
-            goto out;
-        }
-
-        /* libxl__get_targetmem_fudge() calculates the difference from
-         * what is in xenstore to what we have in the domain build info.
-         */
-        d_config->b_info.target_memkb = target_memkb +
-            libxl__get_targetmem_fudge(gc, &d_config->b_info);
-
-        d_config->b_info.max_memkb = max_memkb;
-    }
-
-    /* Scheduler params */
-    {
-        libxl_domain_sched_params_dispose(&d_config->b_info.sched_params);
-        rc = libxl_domain_sched_params_get(ctx, domid,
-                                           &d_config->b_info.sched_params);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get scheduler parameters");
-            goto out;
-        }
-    }
-
-    /* Devices: disk, nic, vtpm, pcidev etc. */
-
-    /* The MERGE macro implements following logic:
-     * 0. retrieve JSON (done by now)
-     * 1. retrieve list of device from xenstore
-     * 2. use xenstore entries as primary reference and compare JSON
-     *    entries with them.
-     *    a. if a device is present in xenstore and in JSON, merge the
-     *       two views.
-     *    b. if a device is not present in xenstore but in JSON, delete
-     *       it from the result.
-     *    c. it's impossible to have an entry present in xenstore but
-     *       not in JSON, because we maintain an invariant that every
-     *       entry in xenstore must have a corresponding entry in JSON.
-     * 3. "merge" operates on "src" and "dst". "src" points to the
-     *    entry retrieved from xenstore while "dst" points to the entry
-     *    retrieve from JSON.
-     */
-    {
-        const struct libxl_device_type *dt;
-        int idx;
-
-        for (idx = 0;; idx++) {
-            void *p = NULL;
-            void **devs;
-            int i, j, num;
-            int *num_dev;
-
-            dt = device_type_tbl[idx];
-            if (!dt)
-                break;
-
-            if (!dt->list || !dt->compare)
-                continue;
-
-            num_dev = libxl__device_type_get_num(dt, d_config);
-            p = dt->list(CTX, domid, &num);
-            if (p == NULL) {
-                LOGD(DEBUG, domid, "No %s from xenstore",
-                     dt->type);
-            }
-            devs = libxl__device_type_get_ptr(dt, d_config);
-
-            for (i = 0; i < *num_dev; i++) {
-                void *q;
-
-                q = libxl__device_type_get_elem(dt, d_config, i);
-                for (j = 0; j < num; j++) {
-                    if (dt->compare(p + dt->dev_elem_size * j, q))
-                        break;
-                }
-
-                if (j < num) {         /* found in xenstore */
-                    if (dt->merge)
-                        dt->merge(ctx, p + dt->dev_elem_size * j, q);
-                } else {                /* not found in xenstore */
-                    LOGD(WARN, domid,
-                         "Device present in JSON but not in xenstore, 
ignored");
-
-                    dt->dispose(q);
-
-                    for (j = i; j < *num_dev - 1; j++)
-                        memcpy(libxl__device_type_get_elem(dt, d_config, j),
-                               libxl__device_type_get_elem(dt, d_config, j+1),
-                               dt->dev_elem_size);
-
-                    /* rewind counters */
-                    (*num_dev)--;
-                    i--;
-
-                    *devs = libxl__realloc(NOGC, *devs,
-                                           dt->dev_elem_size * *num_dev);
-                }
-            }
-
-            for (i = 0; i < num; i++)
-                dt->dispose(p + dt->dev_elem_size * i);
-            free(p);
-        }
-    }
-
-out:
-    if (lock) libxl__unlock_domain_userdata(lock);
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-}
-
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_domain.c b/tools/libxl/libxl_domain.c
new file mode 100644
index 0000000..08eccd0
--- /dev/null
+++ b/tools/libxl/libxl_domain.c
@@ -0,0 +1,1744 @@
+/*
+ * Copyright 2009-2017 Citrix Ltd and other contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h"
+
+#include "libxl_internal.h"
+
+#define PAGE_TO_MEMKB(pages) ((pages) * 4)
+
+int libxl__domain_rename(libxl__gc *gc, uint32_t domid,
+                         const char *old_name, const char *new_name,
+                         xs_transaction_t trans)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    char *dom_path = 0;
+    const char *name_path;
+    char *got_old_name;
+    unsigned int got_old_len;
+    xs_transaction_t our_trans = 0;
+    uint32_t stub_dm_domid;
+    const char *stub_dm_old_name = NULL, *stub_dm_new_name = NULL;
+    int rc;
+    libxl_dominfo info;
+    char *uuid;
+    const char *vm_name_path;
+
+    libxl_dominfo_init(&info);
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) goto x_nomem;
+
+    name_path= GCSPRINTF("%s/name", dom_path);
+    if (!name_path) goto x_nomem;
+
+    stub_dm_domid = libxl_get_stubdom_id(CTX, domid);
+    if (stub_dm_domid) {
+        stub_dm_old_name = libxl__stub_dm_name(gc, old_name);
+        stub_dm_new_name = libxl__stub_dm_name(gc, new_name);
+    }
+
+ retry_transaction:
+    if (!trans) {
+        trans = our_trans = xs_transaction_start(ctx->xsh);
+        if (!our_trans) {
+            LOGEVD(ERROR, errno, domid, "Create xs transaction for domain 
(re)name");
+            goto x_fail;
+        }
+    }
+
+    if (!new_name) {
+        LOGD(ERROR, domid, "New domain name not specified");
+        rc = ERROR_INVAL;
+        goto x_rc;
+    }
+
+    if (new_name[0]) {
+        /* nonempty names must be unique */
+        uint32_t domid_e;
+        rc = libxl_name_to_domid(ctx, new_name, &domid_e);
+        if (rc == ERROR_INVAL) {
+            /* no such domain, good */
+        } else if (rc != 0) {
+            LOGD(ERROR, domid, "Unexpected error checking for existing 
domain");
+            goto x_rc;
+        } else if (domid_e == domid) {
+            /* domain already has this name, ok (but we do still
+             * need the rest of the code as we may need to check
+             * old_name, for example). */
+        } else {
+            LOGD(ERROR, domid, "Domain with name \"%s\" already exists.", 
new_name);
+            rc = ERROR_INVAL;
+            goto x_rc;
+        }
+    }
+
+    if (old_name) {
+        got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
+        if (!got_old_name) {
+            LOGEVD(ERROR, errno, domid,
+                   "Check old name for domain allegedly named `%s'",
+                   old_name);
+            goto x_fail;
+        }
+        if (strcmp(old_name, got_old_name)) {
+            LOGD(ERROR, domid,
+                 "Allegedly named `%s' is actually named `%s' - racing ?",
+                 old_name,
+                 got_old_name);
+            free(got_old_name);
+            goto x_fail;
+        }
+        free(got_old_name);
+    }
+    if (!xs_write(ctx->xsh, trans, name_path,
+                  new_name, strlen(new_name))) {
+        LOGD(ERROR, domid,
+             "Failed to write new name `%s'"
+             " for domain previously named `%s'",
+             new_name,
+             old_name);
+        goto x_fail;
+    }
+
+    /* update /vm/<uuid>/name */
+    rc = libxl_domain_info(ctx, &info, domid);
+    if (rc)
+        goto x_rc;
+
+    uuid = GCSPRINTF(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid));
+    vm_name_path = GCSPRINTF("/vm/%s/name", uuid);
+    if (libxl__xs_write_checked(gc, trans, vm_name_path, new_name))
+        goto x_fail;
+
+    if (stub_dm_domid) {
+        rc = libxl__domain_rename(gc, stub_dm_domid,
+                                  stub_dm_old_name,
+                                  stub_dm_new_name,
+                                  trans);
+        if (rc) {
+            LOGED(ERROR, domid, "Unable to rename stub-domain");
+            goto x_rc;
+        }
+    }
+
+    if (our_trans) {
+        if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
+            trans = our_trans = 0;
+            if (errno != EAGAIN) {
+                LOGD(ERROR, domid,
+                     "Failed to commit new name `%s'"
+                     " for domain previously named `%s'",
+                     new_name,
+                     old_name);
+                goto x_fail;
+            }
+            LOGD(DEBUG, domid,
+                 "Need to retry rename transaction"
+                 " for domain (name_path=\"%s\", new_name=\"%s\")",
+                 name_path,
+                 new_name);
+            goto retry_transaction;
+        }
+        our_trans = 0;
+    }
+
+    rc = 0;
+ x_rc:
+    if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
+    libxl_dominfo_dispose(&info);
+    return rc;
+
+ x_fail:  rc = ERROR_FAIL;  goto x_rc;
+ x_nomem: rc = ERROR_NOMEM; goto x_rc;
+}
+
+int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
+                        const char *old_name, const char *new_name)
+{
+    GC_INIT(ctx);
+    int rc;
+    rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL);
+    GC_FREE;
+    return rc;
+}
+
+int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel,
+                        const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc = libxl__domain_resume(gc, domid, suspend_cancel);
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+/*
+ * Preserves a domain but rewrites xenstore etc to make it unique so
+ * that the domain can be restarted.
+ *
+ * Does not modify info so that it may be reused.
+ */
+int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
+                          libxl_domain_create_info *info, const char 
*name_suffix, libxl_uuid new_uuid)
+{
+    GC_INIT(ctx);
+    struct xs_permissions roperm[2];
+    xs_transaction_t t;
+    char *preserved_name;
+    char *uuid_string;
+    char *vm_path;
+    char *dom_path;
+
+    int rc;
+
+    preserved_name = GCSPRINTF("%s%s", info->name, name_suffix);
+    if (!preserved_name) {
+        GC_FREE;
+        return ERROR_NOMEM;
+    }
+
+    uuid_string = libxl__uuid2string(gc, new_uuid);
+    if (!uuid_string) {
+        GC_FREE;
+        return ERROR_NOMEM;
+    }
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+
+    vm_path = GCSPRINTF("/vm/%s", uuid_string);
+    if (!vm_path) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+
+    roperm[0].id = 0;
+    roperm[0].perms = XS_PERM_NONE;
+    roperm[1].id = domid;
+    roperm[1].perms = XS_PERM_READ;
+
+ retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+
+    xs_rm(ctx->xsh, t, vm_path);
+    xs_mkdir(ctx->xsh, t, vm_path);
+    xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
+
+    xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, 
strlen(vm_path));
+    rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t);
+    if (rc) {
+        GC_FREE;
+        return rc;
+    }
+
+    xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, 
strlen(uuid_string));
+
+    if (!xs_transaction_end(ctx->xsh, t, 0))
+        if (errno == EAGAIN)
+            goto retry_transaction;
+
+    GC_FREE;
+    return 0;
+}
+
+void libxl__xcinfo2xlinfo(libxl_ctx *ctx,
+                          const xc_domaininfo_t *xcinfo,
+                          libxl_dominfo *xlinfo)
+{
+    size_t size;
+
+    memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
+    xlinfo->domid = xcinfo->domain;
+    xlinfo->ssidref = xcinfo->ssidref;
+    if (libxl_flask_sid_to_context(ctx, xlinfo->ssidref,
+                                   &xlinfo->ssid_label, &size) < 0)
+        xlinfo->ssid_label = NULL;
+
+    xlinfo->dying      = !!(xcinfo->flags&XEN_DOMINF_dying);
+    xlinfo->shutdown   = !!(xcinfo->flags&XEN_DOMINF_shutdown);
+    xlinfo->paused     = !!(xcinfo->flags&XEN_DOMINF_paused);
+    xlinfo->blocked    = !!(xcinfo->flags&XEN_DOMINF_blocked);
+    xlinfo->running    = !!(xcinfo->flags&XEN_DOMINF_running);
+    xlinfo->never_stop = !!(xcinfo->flags&XEN_DOMINF_xs_domain);
+
+    if (xlinfo->shutdown)
+        xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask;
+    else
+        xlinfo->shutdown_reason = LIBXL_SHUTDOWN_REASON_UNKNOWN;
+
+    xlinfo->outstanding_memkb = PAGE_TO_MEMKB(xcinfo->outstanding_pages);
+    xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
+    xlinfo->shared_memkb = PAGE_TO_MEMKB(xcinfo->shr_pages);
+    xlinfo->paged_memkb = PAGE_TO_MEMKB(xcinfo->paged_pages);
+    xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->max_pages);
+    xlinfo->cpu_time = xcinfo->cpu_time;
+    xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
+    xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
+    xlinfo->cpupool = xcinfo->cpupool;
+    xlinfo->domain_type = (xcinfo->flags & XEN_DOMINF_hvm_guest) ?
+        LIBXL_DOMAIN_TYPE_HVM : LIBXL_DOMAIN_TYPE_PV;
+}
+
+libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain_out)
+{
+    libxl_dominfo *ptr = NULL;
+    int i, ret;
+    xc_domaininfo_t info[1024];
+    int size = 0;
+    uint32_t domid = 0;
+    GC_INIT(ctx);
+
+    while ((ret = xc_domain_getinfolist(ctx->xch, domid, 1024, info)) > 0) {
+        ptr = libxl__realloc(NOGC, ptr, (size + ret) * sizeof(libxl_dominfo));
+        for (i = 0; i < ret; i++) {
+            libxl__xcinfo2xlinfo(ctx, &info[i], &ptr[size + i]);
+        }
+        domid = info[ret - 1].domain + 1;
+        size += ret;
+    }
+
+    if (ret < 0) {
+        LOGE(ERROR, "getting domain info list");
+        free(ptr);
+        GC_FREE;
+        return NULL;
+    }
+
+    *nb_domain_out = size;
+    GC_FREE;
+    return ptr;
+}
+
+int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
+                      uint32_t domid) {
+    xc_domaininfo_t xcinfo;
+    int ret;
+    GC_INIT(ctx);
+
+    ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
+    if (ret<0) {
+        LOGED(ERROR, domid, "Getting domain info list");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    if (ret==0 || xcinfo.domain != domid) {
+        GC_FREE;
+        return ERROR_DOMAIN_NOTFOUND;
+    }
+
+    if (info_r)
+        libxl__xcinfo2xlinfo(ctx, &xcinfo, info_r);
+    GC_FREE;
+    return 0;
+}
+
+/* this API call only list VM running on this host. A VM can
+ * be an aggregate of multiple domains. */
+libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm_out)
+{
+    GC_INIT(ctx);
+    libxl_dominfo *info;
+    libxl_vminfo *ptr = NULL;
+    int idx, i, n_doms;
+
+    info = libxl_list_domain(ctx, &n_doms);
+    if (!info)
+        goto out;
+
+    /*
+     * Always make sure to allocate at least one element; if we don't and we
+     * request zero, libxl__calloc (might) think its internal call to calloc
+     * has failed (if it returns null), if so it would kill our process.
+     */
+    ptr = libxl__calloc(NOGC, n_doms ? n_doms : 1, sizeof(libxl_vminfo));
+
+    for (idx = i = 0; i < n_doms; i++) {
+        if (libxl_is_stubdom(ctx, info[i].domid, NULL))
+            continue;
+        ptr[idx].uuid = info[i].uuid;
+        ptr[idx].domid = info[i].domid;
+
+        idx++;
+    }
+    *nb_vm_out = idx;
+    libxl_dominfo_list_free(info, n_doms);
+
+out:
+    GC_FREE;
+    return ptr;
+}
+
+static void remus_failover_cb(libxl__egc *egc,
+                              libxl__domain_save_state *dss, int rc);
+
+int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info,
+                             uint32_t domid, int send_fd, int recv_fd,
+                             const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__domain_save_state *dss;
+    int rc;
+
+    libxl_domain_type type = libxl__domain_type(gc, domid);
+    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    /* The caller must set this defbool */
+    if (libxl_defbool_is_default(info->colo)) {
+        LOGD(ERROR, domid, "Colo mode must be enabled/disabled");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    libxl_defbool_setdefault(&info->allow_unsafe, false);
+    libxl_defbool_setdefault(&info->blackhole, false);
+    libxl_defbool_setdefault(&info->compression,
+                             !libxl_defbool_val(info->colo));
+    libxl_defbool_setdefault(&info->netbuf, true);
+    libxl_defbool_setdefault(&info->diskbuf, true);
+
+    if (libxl_defbool_val(info->colo) &&
+        libxl_defbool_val(info->compression)) {
+            LOGD(ERROR, domid, "Cannot use memory checkpoint "
+                        "compression in COLO mode");
+            rc = ERROR_FAIL;
+            goto out;
+    }
+
+    if (!libxl_defbool_val(info->allow_unsafe) &&
+        (libxl_defbool_val(info->blackhole) ||
+         !libxl_defbool_val(info->netbuf) ||
+         !libxl_defbool_val(info->diskbuf))) {
+        LOGD(ERROR, domid, "Unsafe mode must be enabled to replicate to 
/dev/null,"
+                    "disable network buffering and disk replication");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+
+    GCNEW(dss);
+    dss->ao = ao;
+    dss->callback = remus_failover_cb;
+    dss->domid = domid;
+    dss->fd = send_fd;
+    dss->recv_fd = recv_fd;
+    dss->type = type;
+    dss->live = 1;
+    dss->debug = 0;
+    dss->remus = info;
+    if (libxl_defbool_val(info->colo))
+        dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_COLO;
+    else
+        dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_REMUS;
+
+    assert(info);
+
+    /* Point of no return */
+    if (libxl_defbool_val(info->colo))
+        libxl__colo_save_setup(egc, &dss->css);
+    else
+        libxl__remus_setup(egc, &dss->rs);
+    return AO_INPROGRESS;
+
+ out:
+    return AO_CREATE_FAIL(rc);
+}
+
+static void remus_failover_cb(libxl__egc *egc,
+                              libxl__domain_save_state *dss, int rc)
+{
+    STATE_AO_GC(dss->ao);
+    /*
+     * With Remus, if we reach this point, it means either
+     * backup died or some network error occurred preventing us
+     * from sending checkpoints.
+     */
+    libxl__ao_complete(egc, ao, rc);
+}
+
+static void domain_suspend_cb(libxl__egc *egc,
+                              libxl__domain_save_state *dss, int rc)
+{
+    STATE_AO_GC(dss->ao);
+    int flrc;
+
+    flrc = libxl__fd_flags_restore(gc, dss->fd, dss->fdfl);
+    /* If suspend has failed already then report that error not this one. */
+    if (flrc && !rc) rc = flrc;
+
+    libxl__ao_complete(egc,ao,rc);
+
+}
+
+int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, int flags,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    libxl_domain_type type = libxl__domain_type(gc, domid);
+    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
+        rc = ERROR_FAIL;
+        goto out_err;
+    }
+
+    libxl__domain_save_state *dss;
+    GCNEW(dss);
+
+    dss->ao = ao;
+    dss->callback = domain_suspend_cb;
+
+    dss->domid = domid;
+    dss->fd = fd;
+    dss->type = type;
+    dss->live = flags & LIBXL_SUSPEND_LIVE;
+    dss->debug = flags & LIBXL_SUSPEND_DEBUG;
+    dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_NONE;
+
+    rc = libxl__fd_flags_modify_save(gc, dss->fd,
+                                     ~(O_NONBLOCK|O_NDELAY), 0,
+                                     &dss->fdfl);
+    if (rc < 0) goto out_err;
+
+    libxl__domain_save(egc, dss);
+    return AO_INPROGRESS;
+
+ out_err:
+    return AO_CREATE_FAIL(rc);
+}
+
+int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
+{
+    int ret;
+    GC_INIT(ctx);
+    ret = xc_domain_pause(ctx->xch, domid);
+    if (ret<0) {
+        LOGED(ERROR, domid, "Pausing domain");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    GC_FREE;
+    return 0;
+}
+
+int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid,
+                           const char *filename,
+                           const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int ret, rc;
+
+    ret = xc_domain_dumpcore(ctx->xch, domid, filename);
+    if (ret<0) {
+        LOGED(ERROR, domid, "Core dumping domain to %s", filename);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+
+    libxl__ao_complete(egc, ao, rc);
+
+    return AO_INPROGRESS;
+}
+
+int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid)
+{
+    GC_INIT(ctx);
+    int ret, rc = 0;
+
+    libxl_domain_type type = libxl__domain_type(gc, domid);
+    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (type == LIBXL_DOMAIN_TYPE_HVM) {
+        if (libxl__device_model_version_running(gc, domid) !=
+            LIBXL_DEVICE_MODEL_VERSION_NONE) {
+            rc = libxl__domain_resume_device_model(gc, domid);
+            if (rc < 0) {
+                LOGD(ERROR, domid, "Failed to unpause device model for 
domain:%d",
+                     rc);
+                goto out;
+            }
+        }
+    }
+    ret = xc_domain_unpause(ctx->xch, domid);
+    if (ret<0) {
+        LOGED(ERROR, domid, "Unpausing domain");
+        rc = ERROR_FAIL;
+    }
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl__domain_pvcontrol_available(libxl__gc *gc, uint32_t domid)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+
+    uint64_t pvdriver = 0;
+    int ret;
+
+    libxl_domain_type domtype = libxl__domain_type(gc, domid);
+    if (domtype == LIBXL_DOMAIN_TYPE_INVALID)
+        return ERROR_FAIL;
+
+    if (domtype == LIBXL_DOMAIN_TYPE_PV)
+        return 1;
+
+    ret = xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
+    if (ret<0) {
+        LOGED(ERROR, domid, "Getting HVM callback IRQ");
+        return ERROR_FAIL;
+    }
+    return !!pvdriver;
+}
+
+const char *libxl__domain_pvcontrol_xspath(libxl__gc *gc, uint32_t domid)
+{
+    const char *dom_path;
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path)
+        return NULL;
+
+    return GCSPRINTF("%s/control/shutdown", dom_path);
+}
+
+char * libxl__domain_pvcontrol_read(libxl__gc *gc, xs_transaction_t t,
+                                    uint32_t domid)
+{
+    const char *shutdown_path;
+
+    shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
+    if (!shutdown_path)
+        return NULL;
+
+    return libxl__xs_read(gc, t, shutdown_path);
+}
+
+int libxl__domain_pvcontrol_write(libxl__gc *gc, xs_transaction_t t,
+                                  uint32_t domid, const char *cmd)
+{
+    const char *shutdown_path;
+
+    shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
+    if (!shutdown_path)
+        return ERROR_FAIL;
+
+    return libxl__xs_printf(gc, t, shutdown_path, "%s", cmd);
+}
+
+static int libxl__domain_pvcontrol(libxl__gc *gc, uint32_t domid,
+                                   const char *cmd)
+{
+    int ret;
+
+    ret = libxl__domain_pvcontrol_available(gc, domid);
+    if (ret < 0)
+        return ret;
+
+    if (!ret)
+        return ERROR_NOPARAVIRT;
+
+    return libxl__domain_pvcontrol_write(gc, XBT_NULL, domid, cmd);
+}
+
+int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid)
+{
+    GC_INIT(ctx);
+    int ret;
+    ret = libxl__domain_pvcontrol(gc, domid, "poweroff");
+    GC_FREE;
+    return ret;
+}
+
+int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid)
+{
+    GC_INIT(ctx);
+    int ret;
+    ret = libxl__domain_pvcontrol(gc, domid, "reboot");
+    GC_FREE;
+    return ret;
+}
+
+static void domain_death_occurred(libxl__egc *egc,
+                                  libxl_evgen_domain_death **evg_upd,
+                                  const char *why) {
+    /* Removes **evg_upd from death_list and puts it on death_reported
+     * and advances *evg_upd to the next entry.
+     * Call sites in domain_death_xswatch_callback must use "continue". */
+    EGC_GC;
+    libxl_evgen_domain_death *const evg = *evg_upd;
+
+    LOGD(DEBUG, evg->domid, "%s", why);
+
+    libxl_evgen_domain_death *evg_next = LIBXL_TAILQ_NEXT(evg, entry);
+    *evg_upd = evg_next;
+
+    libxl_event *ev = NEW_EVENT(egc, DOMAIN_DEATH, evg->domid, evg->user);
+
+    libxl__event_occurred(egc, ev);
+
+    evg->death_reported = 1;
+    LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
+    LIBXL_TAILQ_INSERT_HEAD(&CTX->death_reported, evg, entry);
+}
+
+static void domain_death_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch 
*w,
+                                        const char *wpath, const char *epath) {
+    EGC_GC;
+    libxl_evgen_domain_death *evg;
+    int rc;
+
+    CTX_LOCK;
+
+    evg = LIBXL_TAILQ_FIRST(&CTX->death_list);
+
+    for (;;) {
+        if (!evg) goto out;
+
+        int nentries = LIBXL_TAILQ_NEXT(evg, entry) ? 200 : 1;
+        xc_domaininfo_t domaininfos[nentries];
+        const xc_domaininfo_t *got = domaininfos, *gotend;
+
+        rc = xc_domain_getinfolist(CTX->xch, evg->domid, nentries, 
domaininfos);
+        if (rc == -1) {
+            LIBXL__EVENT_DISASTER(egc, "xc_domain_getinfolist failed while"
+                                  " processing @releaseDomain watch event",
+                                  errno, 0);
+            goto out;
+        }
+        gotend = &domaininfos[rc];
+
+        LOGD(DEBUG, evg->domid, "[evg=%p] nentries=%d rc=%d %ld..%ld",
+             evg, nentries, rc,
+             rc>0 ? (long)domaininfos[0].domain : 0,
+             rc>0 ? (long)domaininfos[rc-1].domain : 0);
+
+        for (;;) {
+            if (!evg) {
+                LOG(DEBUG, "[evg=0] all reported");
+                goto all_reported;
+            }
+
+            LOGD(DEBUG, evg->domid, "[evg=%p]"
+                 "   got=domaininfos[%d] got->domain=%ld",
+                 evg, (int)(got - domaininfos),
+                 got < gotend ? (long)got->domain : -1L);
+
+            if (!rc) {
+                domain_death_occurred(egc, &evg, "empty list");
+                continue;
+            }
+
+            if (got == gotend) {
+                LOG(DEBUG, " got==gotend");
+                break;
+            }
+
+            if (got->domain > evg->domid) {
+                /* ie, the list doesn't contain evg->domid any more so
+                 * the domain has been destroyed */
+                domain_death_occurred(egc, &evg, "missing from list");
+                continue;
+            }
+
+            if (got->domain < evg->domid) {
+                got++;
+                continue;
+            }
+
+            assert(evg->domid == got->domain);
+            LOGD(DEBUG, evg->domid, "Exists shutdown_reported=%d"" 
dominf.flags=%x",
+                 evg->shutdown_reported, got->flags);
+
+            if (got->flags & XEN_DOMINF_dying) {
+                domain_death_occurred(egc, &evg, "dying");
+                continue;
+            }
+
+            if (!evg->shutdown_reported &&
+                (got->flags & XEN_DOMINF_shutdown)) {
+                libxl_event *ev = NEW_EVENT(egc, DOMAIN_SHUTDOWN,
+                                            got->domain, evg->user);
+
+                LOG(DEBUG, " shutdown reporting");
+
+                ev->u.domain_shutdown.shutdown_reason =
+                    (got->flags >> XEN_DOMINF_shutdownshift) &
+                    XEN_DOMINF_shutdownmask;
+                libxl__event_occurred(egc, ev);
+
+                evg->shutdown_reported = 1;
+            }
+            evg = LIBXL_TAILQ_NEXT(evg, entry);
+        }
+
+        assert(rc); /* rc==0 results in us eating all evgs and quitting */
+    }
+ all_reported:
+ out:
+
+    LOG(DEBUG, "domain death search done");
+
+    CTX_UNLOCK;
+}
+
+int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid,
+                libxl_ev_user user, libxl_evgen_domain_death **evgen_out) {
+    GC_INIT(ctx);
+    libxl_evgen_domain_death *evg, *evg_search;
+    int rc;
+
+    CTX_LOCK;
+
+    evg = malloc(sizeof(*evg));  if (!evg) { rc = ERROR_NOMEM; goto out; }
+    memset(evg, 0, sizeof(*evg));
+    evg->domid = domid;
+    evg->user = user;
+
+    LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, ,
+                              evg->domid > evg_search->domid);
+
+    if (!libxl__ev_xswatch_isregistered(&ctx->death_watch)) {
+        rc = libxl__ev_xswatch_register(gc, &ctx->death_watch,
+                        domain_death_xswatch_callback, "@releaseDomain");
+        if (rc) { libxl__evdisable_domain_death(gc, evg); goto out; }
+    }
+
+    *evgen_out = evg;
+    rc = 0;
+
+ out:
+    CTX_UNLOCK;
+    GC_FREE;
+    return rc;
+};
+
+void libxl__evdisable_domain_death(libxl__gc *gc,
+                                   libxl_evgen_domain_death *evg) {
+    CTX_LOCK;
+
+    if (!evg->death_reported)
+        LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
+    else
+        LIBXL_TAILQ_REMOVE(&CTX->death_reported, evg, entry);
+
+    free(evg);
+
+    if (!LIBXL_TAILQ_FIRST(&CTX->death_list) &&
+        libxl__ev_xswatch_isregistered(&CTX->death_watch))
+        libxl__ev_xswatch_deregister(gc, &CTX->death_watch);
+
+    CTX_UNLOCK;
+}
+
+void libxl_evdisable_domain_death(libxl_ctx *ctx,
+                                  libxl_evgen_domain_death *evg) {
+    GC_INIT(ctx);
+    libxl__evdisable_domain_death(gc, evg);
+    GC_FREE;
+}
+
+/* Callbacks for libxl_domain_destroy */
+
+static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state 
*dds,
+                              int rc);
+
+int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__domain_destroy_state *dds;
+
+    GCNEW(dds);
+    dds->ao = ao;
+    dds->domid = domid;
+    dds->callback = domain_destroy_cb;
+    libxl__domain_destroy(egc, dds);
+
+    return AO_INPROGRESS;
+}
+
+static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state 
*dds,
+                              int rc)
+{
+    STATE_AO_GC(dds->ao);
+
+    if (rc)
+        LOGD(ERROR, dds->domid, "Destruction of domain failed");
+
+    libxl__ao_complete(egc, ao, rc);
+}
+
+/* Callbacks for libxl__domain_destroy */
+
+static void stubdom_destroy_callback(libxl__egc *egc,
+                                     libxl__destroy_domid_state *dis,
+                                     int rc);
+
+static void domain_destroy_callback(libxl__egc *egc,
+                                    libxl__destroy_domid_state *dis,
+                                    int rc);
+
+static void destroy_finish_check(libxl__egc *egc,
+                                 libxl__domain_destroy_state *dds);
+
+void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds)
+{
+    STATE_AO_GC(dds->ao);
+    uint32_t stubdomid = libxl_get_stubdom_id(CTX, dds->domid);
+
+    if (stubdomid) {
+        dds->stubdom.ao = ao;
+        dds->stubdom.domid = stubdomid;
+        dds->stubdom.callback = stubdom_destroy_callback;
+        dds->stubdom.soft_reset = false;
+        libxl__destroy_domid(egc, &dds->stubdom);
+    } else {
+        dds->stubdom_finished = 1;
+    }
+
+    dds->domain.ao = ao;
+    dds->domain.domid = dds->domid;
+    dds->domain.callback = domain_destroy_callback;
+    dds->domain.soft_reset = dds->soft_reset;
+    libxl__destroy_domid(egc, &dds->domain);
+}
+
+static void stubdom_destroy_callback(libxl__egc *egc,
+                                     libxl__destroy_domid_state *dis,
+                                     int rc)
+{
+    STATE_AO_GC(dis->ao);
+    libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, stubdom);
+    const char *savefile;
+
+    if (rc) {
+        LOGD(ERROR, dds->domain.domid, "Unable to destroy stubdom with domid 
%u",
+             dis->domid);
+        dds->rc = rc;
+    }
+
+    dds->stubdom_finished = 1;
+    savefile = libxl__device_model_savefile(gc, dis->domid);
+    rc = libxl__remove_file(gc, savefile);
+    if (rc) {
+        LOGD(ERROR, dds->domain.domid, "Failed to remove device-model savefile 
%s",
+             savefile);
+    }
+
+    destroy_finish_check(egc, dds);
+}
+
+static void domain_destroy_callback(libxl__egc *egc,
+                                    libxl__destroy_domid_state *dis,
+                                    int rc)
+{
+    STATE_AO_GC(dis->ao);
+    libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, domain);
+
+    if (rc) {
+        LOGD(ERROR, dis->domid, "Unable to destroy guest");
+        dds->rc = rc;
+    }
+
+    dds->domain_finished = 1;
+    destroy_finish_check(egc, dds);
+}
+
+static void destroy_finish_check(libxl__egc *egc,
+                                 libxl__domain_destroy_state *dds)
+{
+    if (!(dds->domain_finished && dds->stubdom_finished))
+        return;
+
+    dds->callback(egc, dds, dds->rc);
+}
+
+/* Callbacks for libxl__destroy_domid */
+static void devices_destroy_cb(libxl__egc *egc,
+                               libxl__devices_remove_state *drs,
+                               int rc);
+
+static void domain_destroy_domid_cb(libxl__egc *egc,
+                                    libxl__ev_child *destroyer,
+                                    pid_t pid, int status);
+
+void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
+{
+    STATE_AO_GC(dis->ao);
+    libxl_ctx *ctx = CTX;
+    uint32_t domid = dis->domid;
+    char *dom_path;
+    int rc, dm_present;
+
+    libxl__ev_child_init(&dis->destroyer);
+
+    rc = libxl_domain_info(ctx, NULL, domid);
+    switch(rc) {
+    case 0:
+        break;
+    case ERROR_DOMAIN_NOTFOUND:
+        LOGD(ERROR, domid, "Non-existant domain");
+    default:
+        goto out;
+    }
+
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        if (libxl_get_stubdom_id(CTX, domid)) {
+            dm_present = 0;
+            break;
+        }
+        /* fall through */
+    case LIBXL_DOMAIN_TYPE_PV:
+        dm_present = libxl__dm_active(gc, domid);
+        break;
+    case LIBXL_DOMAIN_TYPE_INVALID:
+        rc = ERROR_FAIL;
+        goto out;
+    default:
+        abort();
+    }
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl__device_pci_destroy_all(gc, domid) < 0)
+        LOGD(ERROR, domid, "Pci shutdown failed");
+    rc = xc_domain_pause(ctx->xch, domid);
+    if (rc < 0) {
+        LOGEVD(ERROR, rc, domid, "xc_domain_pause failed");
+    }
+    if (dm_present) {
+        if (libxl__destroy_device_model(gc, domid) < 0)
+            LOGD(ERROR, domid, "libxl__destroy_device_model failed");
+
+        libxl__qmp_cleanup(gc, domid);
+    }
+    dis->drs.ao = ao;
+    dis->drs.domid = domid;
+    dis->drs.callback = devices_destroy_cb;
+    dis->drs.force = 1;
+    libxl__devices_destroy(egc, &dis->drs);
+    return;
+
+out:
+    assert(rc);
+    dis->callback(egc, dis, rc);
+    return;
+}
+
+static void devices_destroy_cb(libxl__egc *egc,
+                               libxl__devices_remove_state *drs,
+                               int rc)
+{
+    STATE_AO_GC(drs->ao);
+    libxl__destroy_domid_state *dis = CONTAINER_OF(drs, *dis, drs);
+    libxl_ctx *ctx = CTX;
+    uint32_t domid = dis->domid;
+    char *dom_path;
+    char *vm_path;
+    libxl__domain_userdata_lock *lock;
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (rc < 0)
+        LOGD(ERROR, domid, "libxl__devices_destroy failed");
+
+    vm_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vm", dom_path));
+    if (vm_path)
+        if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
+            LOGED(ERROR, domid, "xs_rm failed for %s", vm_path);
+
+    if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
+        LOGED(ERROR, domid, "xs_rm failed for %s", dom_path);
+
+    xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid));
+    xs_rm(ctx->xsh, XBT_NULL, GCSPRINTF( "/local/domain/%d/hvmloader", domid));
+
+    /* This is async operation, we already hold CTX lock */
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.