All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] libxl: spolit up libxl.c
@ 2017-02-08 13:13 Juergen Gross
  2017-02-08 13:13 ` [PATCH 1/9] libxl: adjust copyright comment of libxl.c Juergen Gross
                   ` (10 more replies)
  0 siblings, 11 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has become rather large. Split it up into multiple files.

Code movement only. No functional change intended.

Juergen Gross (9):
  libxl: adjust copyright comment of libxl.c
  libxl: carve out cpupool specific functions from libxl.c
  libxl: carve out scheduler specific functions from libxl.c
  libxl: carve out disk specific functions from libxl.c
  libxl: carve out console specific functions from libxl.c
  libxl: carve out memory specific functions from libxl.c
  libxl: move device specific functions out of libxl.c
  libxl: carve out tmem specific functions from libxl.c
  libxl: carve out domain specific functions from libxl.c

 tools/libxl/Makefile         |    4 +-
 tools/libxl/libxl.c          | 6252 +-----------------------------------------
 tools/libxl/libxl_console.c  |  862 ++++++
 tools/libxl/libxl_cpupool.c  |  443 +++
 tools/libxl/libxl_device.c   |  435 ++-
 tools/libxl/libxl_disk.c     | 1258 +++++++++
 tools/libxl/libxl_domain.c   | 1744 ++++++++++++
 tools/libxl/libxl_internal.h |    8 +-
 tools/libxl/libxl_mem.c      |  601 ++++
 tools/libxl/libxl_sched.c    |  915 +++++++
 tools/libxl/libxl_tmem.c     |  167 ++
 11 files changed, 6424 insertions(+), 6265 deletions(-)
 create mode 100644 tools/libxl/libxl_console.c
 create mode 100644 tools/libxl/libxl_cpupool.c
 create mode 100644 tools/libxl/libxl_disk.c
 create mode 100644 tools/libxl/libxl_domain.c
 create mode 100644 tools/libxl/libxl_mem.c
 create mode 100644 tools/libxl/libxl_sched.c
 create mode 100644 tools/libxl/libxl_tmem.c

-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/9] libxl: adjust copyright comment of libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 2/9] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

The copyright of libxl.c is a little bit outdated.

Adjust it to reality.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/libxl.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index d400fa2..0641a8a 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1,7 +1,5 @@
 /*
- * Copyright (C) 2009      Citrix Ltd.
- * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
- * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ * 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
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/9] libxl: carve out cpupool specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
  2017-02-08 13:13 ` [PATCH 1/9] libxl: adjust copyright comment of libxl.c Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 3/9] libxl: carve out scheduler " Juergen Gross
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the cpupool
related functions to libxl_cpupool.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile        |   1 +
 tools/libxl/libxl.c         | 418 -----------------------------------------
 tools/libxl/libxl_cpupool.c | 443 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 444 insertions(+), 418 deletions(-)
 create mode 100644 tools/libxl/libxl_cpupool.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 91e2f97..0125871 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -137,6 +137,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_qmp.o libxl_event.o libxl_fork.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
 			libxl_vtpm.o libxl_nic.o \
+			libxl_cpupool.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 0641a8a..53ad081 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -685,100 +685,6 @@ int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
     return 0;
 }
 
-/* Returns:
- *   0 - success
- *   ERROR_FAIL + errno == ENOENT - no entry found
- *   ERROR_$FOO + errno != ENOENT - other failure
- */
-static int cpupool_info(libxl__gc *gc,
-                        libxl_cpupoolinfo *info,
-                        uint32_t poolid,
-                        bool exact /* exactly poolid or >= poolid */)
-{
-    xc_cpupoolinfo_t *xcinfo;
-    int rc = ERROR_FAIL;
-
-    xcinfo = xc_cpupool_getinfo(CTX->xch, poolid);
-    if (xcinfo == NULL)
-    {
-        if (exact || errno != ENOENT)
-            LOGE(ERROR, "failed to get info for cpupool%d", poolid);
-        return ERROR_FAIL;
-    }
-
-    if (exact && xcinfo->cpupool_id != poolid)
-    {
-        LOG(ERROR, "got info for cpupool%d, wanted cpupool%d\n",
-            xcinfo->cpupool_id, poolid);
-        goto out;
-    }
-
-    info->poolid = xcinfo->cpupool_id;
-    info->pool_name = libxl_cpupoolid_to_name(CTX, info->poolid);
-    if (!info->pool_name) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    info->sched = xcinfo->sched_id;
-    info->n_dom = xcinfo->n_dom;
-    rc = libxl_cpu_bitmap_alloc(CTX, &info->cpumap, 0);
-    if (rc)
-        goto out;
-
-    memcpy(info->cpumap.map, xcinfo->cpumap, info->cpumap.size);
-
-    rc = 0;
-out:
-    xc_cpupool_infofree(CTX->xch, xcinfo);
-    return rc;
-}
-
-int libxl_cpupool_info(libxl_ctx *ctx,
-                       libxl_cpupoolinfo *info, uint32_t poolid)
-{
-    GC_INIT(ctx);
-    int rc = cpupool_info(gc, info, poolid, true);
-    GC_FREE;
-    return rc;
-}
-
-libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx *ctx, int *nb_pool_out)
-{
-    GC_INIT(ctx);
-    libxl_cpupoolinfo info, *ptr;
-
-    int i;
-    uint32_t poolid;
-
-    ptr = NULL;
-
-    poolid = 0;
-    for (i = 0;; i++) {
-        libxl_cpupoolinfo_init(&info);
-        if (cpupool_info(gc, &info, poolid, false)) {
-            libxl_cpupoolinfo_dispose(&info);
-            if (errno != ENOENT) goto out;
-            break;
-        }
-
-        ptr = libxl__realloc(NOGC, ptr, (i+1) * sizeof(libxl_cpupoolinfo));
-        ptr[i] = info;
-        poolid = info.poolid + 1;
-        /* Don't dispose of info because it will be returned to caller */
-    }
-
-    *nb_pool_out = i;
-
-    GC_FREE;
-    return ptr;
-
-out:
-    libxl_cpupoolinfo_list_free(ptr, i);
-    *nb_pool_out = 0;
-    GC_FREE;
-    return NULL;
-}
-
 /* 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)
@@ -6256,330 +6162,6 @@ out:
     return rc;
 }
 
-int libxl_get_freecpus(libxl_ctx *ctx, libxl_bitmap *cpumap)
-{
-    int ncpus;
-
-    ncpus = libxl_get_max_cpus(ctx);
-    if (ncpus < 0)
-        return ncpus;
-
-    cpumap->map = xc_cpupool_freeinfo(ctx->xch);
-    if (cpumap->map == NULL)
-        return ERROR_FAIL;
-
-    cpumap->size = (ncpus + 7) / 8;
-
-    return 0;
-}
-
-int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
-                         libxl_scheduler sched,
-                         libxl_bitmap cpumap, libxl_uuid *uuid,
-                         uint32_t *poolid)
-{
-    GC_INIT(ctx);
-    int rc;
-    int i;
-    xs_transaction_t t;
-    char *uuid_string;
-
-    uuid_string = libxl__uuid2string(gc, *uuid);
-    if (!uuid_string) {
-        GC_FREE;
-        return ERROR_NOMEM;
-    }
-
-    rc = xc_cpupool_create(ctx->xch, poolid, sched);
-    if (rc) {
-        LOGEV(ERROR, rc, "Could not create cpupool");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-
-    libxl_for_each_bit(i, cpumap)
-        if (libxl_bitmap_test(&cpumap, i)) {
-            rc = xc_cpupool_addcpu(ctx->xch, *poolid, i);
-            if (rc) {
-                LOGEV(ERROR, rc, "Error moving cpu to cpupool");
-                libxl_cpupool_destroy(ctx, *poolid);
-                GC_FREE;
-                return ERROR_FAIL;
-            }
-        }
-
-    for (;;) {
-        t = xs_transaction_start(ctx->xsh);
-
-        xs_mkdir(ctx->xsh, t, GCSPRINTF("/local/pool/%d", *poolid));
-        libxl__xs_printf(gc, t,
-                         GCSPRINTF("/local/pool/%d/uuid", *poolid),
-                         "%s", uuid_string);
-        libxl__xs_printf(gc, t,
-                         GCSPRINTF("/local/pool/%d/name", *poolid),
-                         "%s", name);
-
-        if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) {
-            GC_FREE;
-            return 0;
-        }
-    }
-}
-
-int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid)
-{
-    GC_INIT(ctx);
-    int rc, i;
-    xc_cpupoolinfo_t *info;
-    xs_transaction_t t;
-    libxl_bitmap cpumap;
-
-    info = xc_cpupool_getinfo(ctx->xch, poolid);
-    if (info == NULL) {
-        GC_FREE;
-        return ERROR_NOMEM;
-    }
-
-    rc = ERROR_INVAL;
-    if ((info->cpupool_id != poolid) || (info->n_dom))
-        goto out;
-
-    rc = libxl_cpu_bitmap_alloc(ctx, &cpumap, 0);
-    if (rc)
-        goto out;
-
-    memcpy(cpumap.map, info->cpumap, cpumap.size);
-    libxl_for_each_bit(i, cpumap)
-        if (libxl_bitmap_test(&cpumap, i)) {
-            rc = xc_cpupool_removecpu(ctx->xch, poolid, i);
-            if (rc) {
-                LOGEV(ERROR, rc, "Error removing cpu from cpupool");
-                rc = ERROR_FAIL;
-                goto out1;
-            }
-        }
-
-    rc = xc_cpupool_destroy(ctx->xch, poolid);
-    if (rc) {
-        LOGEV(ERROR, rc, "Could not destroy cpupool");
-        rc = ERROR_FAIL;
-        goto out1;
-    }
-
-    for (;;) {
-        t = xs_transaction_start(ctx->xsh);
-
-        xs_rm(ctx->xsh, XBT_NULL, GCSPRINTF("/local/pool/%d", poolid));
-
-        if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
-            break;
-    }
-
-    rc = 0;
-
-out1:
-    libxl_bitmap_dispose(&cpumap);
-out:
-    xc_cpupool_infofree(ctx->xch, info);
-    GC_FREE;
-
-    return rc;
-}
-
-int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid)
-{
-    GC_INIT(ctx);
-    xs_transaction_t t;
-    xc_cpupoolinfo_t *info;
-    int rc;
-
-    info = xc_cpupool_getinfo(ctx->xch, poolid);
-    if (info == NULL) {
-        GC_FREE;
-        return ERROR_NOMEM;
-    }
-
-    rc = ERROR_INVAL;
-    if (info->cpupool_id != poolid)
-        goto out;
-
-    rc = 0;
-
-    for (;;) {
-        t = xs_transaction_start(ctx->xsh);
-
-        libxl__xs_printf(gc, t,
-                         GCSPRINTF("/local/pool/%d/name", poolid),
-                         "%s", name);
-
-        if (xs_transaction_end(ctx->xsh, t, 0))
-            break;
-
-        if (errno == EAGAIN)
-            continue;
-
-        rc = ERROR_FAIL;
-        break;
-    }
-
-out:
-    xc_cpupool_infofree(ctx->xch, info);
-    GC_FREE;
-
-    return rc;
-}
-
-int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu)
-{
-    GC_INIT(ctx);
-    int rc = 0;
-
-    rc = xc_cpupool_addcpu(ctx->xch, poolid, cpu);
-    if (rc) {
-        LOGE(ERROR, "Error moving cpu %d to cpupool", cpu);
-        rc = ERROR_FAIL;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
-                                const libxl_bitmap *cpumap)
-{
-    int c, ncpus = 0, rc = 0;
-
-    libxl_for_each_set_bit(c, *cpumap) {
-        if (!libxl_cpupool_cpuadd(ctx, poolid, c))
-            ncpus++;
-    }
-
-    if (ncpus != libxl_bitmap_count_set(cpumap))
-        rc = ERROR_FAIL;
-
-    return rc;
-}
-
-int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
-{
-    int rc = 0;
-    int cpu, nr;
-    libxl_bitmap freemap;
-    libxl_cputopology *topology;
-
-    if (libxl_get_freecpus(ctx, &freemap)) {
-        return ERROR_FAIL;
-    }
-
-    topology = libxl_get_cpu_topology(ctx, &nr);
-    if (!topology) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    *cpus = 0;
-    for (cpu = 0; cpu < nr; cpu++) {
-        if (libxl_bitmap_test(&freemap, cpu) && (topology[cpu].node == node) &&
-            !libxl_cpupool_cpuadd(ctx, poolid, cpu)) {
-                (*cpus)++;
-        }
-        libxl_cputopology_dispose(&topology[cpu]);
-    }
-
-    free(topology);
-out:
-    libxl_bitmap_dispose(&freemap);
-    return rc;
-}
-
-int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu)
-{
-    GC_INIT(ctx);
-    int rc = 0;
-
-    rc = xc_cpupool_removecpu(ctx->xch, poolid, cpu);
-    if (rc) {
-        LOGE(ERROR, "Error removing cpu %d from cpupool", cpu);
-        rc = ERROR_FAIL;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
-                                   const libxl_bitmap *cpumap)
-{
-    int c, ncpus = 0, rc = 0;
-
-    libxl_for_each_set_bit(c, *cpumap) {
-        if (!libxl_cpupool_cpuremove(ctx, poolid, c))
-            ncpus++;
-    }
-
-    if (ncpus != libxl_bitmap_count_set(cpumap))
-        rc = ERROR_FAIL;
-
-    return rc;
-}
-
-int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
-{
-    int ret = 0;
-    int n_pools;
-    int p;
-    int cpu, nr_cpus;
-    libxl_cputopology *topology;
-    libxl_cpupoolinfo *poolinfo;
-
-    poolinfo = libxl_list_cpupool(ctx, &n_pools);
-    if (!poolinfo) {
-        return ERROR_NOMEM;
-    }
-
-    topology = libxl_get_cpu_topology(ctx, &nr_cpus);
-    if (!topology) {
-        ret = ERROR_FAIL;
-        goto out;
-    }
-
-    *cpus = 0;
-    for (p = 0; p < n_pools; p++) {
-        if (poolinfo[p].poolid == poolid) {
-            for (cpu = 0; cpu < nr_cpus; cpu++) {
-                if ((topology[cpu].node == node) &&
-                    libxl_bitmap_test(&poolinfo[p].cpumap, cpu) &&
-                    !libxl_cpupool_cpuremove(ctx, poolid, cpu)) {
-                        (*cpus)++;
-                }
-            }
-        }
-    }
-
-    libxl_cputopology_list_free(topology, nr_cpus);
-
-out:
-    libxl_cpupoolinfo_list_free(poolinfo, n_pools);
-
-    return ret;
-}
-
-int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid)
-{
-    GC_INIT(ctx);
-    int rc;
-
-    rc = xc_cpupool_movedomain(ctx->xch, poolid, domid);
-    if (rc) {
-        LOGEVD(ERROR, rc, domid, "Error moving domain to cpupool");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-
-    GC_FREE;
-    return 0;
-}
-
 static int fd_set_flags(libxl_ctx *ctx, int fd,
                         int fcntlgetop, int fcntlsetop, const char *fl,
                         int flagmask, int set_p)
diff --git a/tools/libxl/libxl_cpupool.c b/tools/libxl/libxl_cpupool.c
new file mode 100644
index 0000000..f3d22b1
--- /dev/null
+++ b/tools/libxl/libxl_cpupool.c
@@ -0,0 +1,443 @@
+/*
+ * 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"
+
+/* Returns:
+ *   0 - success
+ *   ERROR_FAIL + errno == ENOENT - no entry found
+ *   ERROR_$FOO + errno != ENOENT - other failure
+ */
+static int cpupool_info(libxl__gc *gc,
+                        libxl_cpupoolinfo *info,
+                        uint32_t poolid,
+                        bool exact /* exactly poolid or >= poolid */)
+{
+    xc_cpupoolinfo_t *xcinfo;
+    int rc = ERROR_FAIL;
+
+    xcinfo = xc_cpupool_getinfo(CTX->xch, poolid);
+    if (xcinfo == NULL)
+    {
+        if (exact || errno != ENOENT)
+            LOGE(ERROR, "failed to get info for cpupool%d", poolid);
+        return ERROR_FAIL;
+    }
+
+    if (exact && xcinfo->cpupool_id != poolid)
+    {
+        LOG(ERROR, "got info for cpupool%d, wanted cpupool%d\n",
+            xcinfo->cpupool_id, poolid);
+        goto out;
+    }
+
+    info->poolid = xcinfo->cpupool_id;
+    info->pool_name = libxl_cpupoolid_to_name(CTX, info->poolid);
+    if (!info->pool_name) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    info->sched = xcinfo->sched_id;
+    info->n_dom = xcinfo->n_dom;
+    rc = libxl_cpu_bitmap_alloc(CTX, &info->cpumap, 0);
+    if (rc)
+        goto out;
+
+    memcpy(info->cpumap.map, xcinfo->cpumap, info->cpumap.size);
+
+    rc = 0;
+out:
+    xc_cpupool_infofree(CTX->xch, xcinfo);
+    return rc;
+}
+
+int libxl_cpupool_info(libxl_ctx *ctx,
+                       libxl_cpupoolinfo *info, uint32_t poolid)
+{
+    GC_INIT(ctx);
+    int rc = cpupool_info(gc, info, poolid, true);
+    GC_FREE;
+    return rc;
+}
+
+libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx *ctx, int *nb_pool_out)
+{
+    GC_INIT(ctx);
+    libxl_cpupoolinfo info, *ptr;
+
+    int i;
+    uint32_t poolid;
+
+    ptr = NULL;
+
+    poolid = 0;
+    for (i = 0;; i++) {
+        libxl_cpupoolinfo_init(&info);
+        if (cpupool_info(gc, &info, poolid, false)) {
+            libxl_cpupoolinfo_dispose(&info);
+            if (errno != ENOENT) goto out;
+            break;
+        }
+
+        ptr = libxl__realloc(NOGC, ptr, (i+1) * sizeof(libxl_cpupoolinfo));
+        ptr[i] = info;
+        poolid = info.poolid + 1;
+        /* Don't dispose of info because it will be returned to caller */
+    }
+
+    *nb_pool_out = i;
+
+    GC_FREE;
+    return ptr;
+
+out:
+    libxl_cpupoolinfo_list_free(ptr, i);
+    *nb_pool_out = 0;
+    GC_FREE;
+    return NULL;
+}
+
+int libxl_get_freecpus(libxl_ctx *ctx, libxl_bitmap *cpumap)
+{
+    int ncpus;
+
+    ncpus = libxl_get_max_cpus(ctx);
+    if (ncpus < 0)
+        return ncpus;
+
+    cpumap->map = xc_cpupool_freeinfo(ctx->xch);
+    if (cpumap->map == NULL)
+        return ERROR_FAIL;
+
+    cpumap->size = (ncpus + 7) / 8;
+
+    return 0;
+}
+
+int libxl_cpupool_create(libxl_ctx *ctx, const char *name,
+                         libxl_scheduler sched,
+                         libxl_bitmap cpumap, libxl_uuid *uuid,
+                         uint32_t *poolid)
+{
+    GC_INIT(ctx);
+    int rc;
+    int i;
+    xs_transaction_t t;
+    char *uuid_string;
+
+    uuid_string = libxl__uuid2string(gc, *uuid);
+    if (!uuid_string) {
+        GC_FREE;
+        return ERROR_NOMEM;
+    }
+
+    rc = xc_cpupool_create(ctx->xch, poolid, sched);
+    if (rc) {
+        LOGEV(ERROR, rc, "Could not create cpupool");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+
+    libxl_for_each_bit(i, cpumap)
+        if (libxl_bitmap_test(&cpumap, i)) {
+            rc = xc_cpupool_addcpu(ctx->xch, *poolid, i);
+            if (rc) {
+                LOGEV(ERROR, rc, "Error moving cpu to cpupool");
+                libxl_cpupool_destroy(ctx, *poolid);
+                GC_FREE;
+                return ERROR_FAIL;
+            }
+        }
+
+    for (;;) {
+        t = xs_transaction_start(ctx->xsh);
+
+        xs_mkdir(ctx->xsh, t, GCSPRINTF("/local/pool/%d", *poolid));
+        libxl__xs_printf(gc, t,
+                         GCSPRINTF("/local/pool/%d/uuid", *poolid),
+                         "%s", uuid_string);
+        libxl__xs_printf(gc, t,
+                         GCSPRINTF("/local/pool/%d/name", *poolid),
+                         "%s", name);
+
+        if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN)) {
+            GC_FREE;
+            return 0;
+        }
+    }
+}
+
+int libxl_cpupool_destroy(libxl_ctx *ctx, uint32_t poolid)
+{
+    GC_INIT(ctx);
+    int rc, i;
+    xc_cpupoolinfo_t *info;
+    xs_transaction_t t;
+    libxl_bitmap cpumap;
+
+    info = xc_cpupool_getinfo(ctx->xch, poolid);
+    if (info == NULL) {
+        GC_FREE;
+        return ERROR_NOMEM;
+    }
+
+    rc = ERROR_INVAL;
+    if ((info->cpupool_id != poolid) || (info->n_dom))
+        goto out;
+
+    rc = libxl_cpu_bitmap_alloc(ctx, &cpumap, 0);
+    if (rc)
+        goto out;
+
+    memcpy(cpumap.map, info->cpumap, cpumap.size);
+    libxl_for_each_bit(i, cpumap)
+        if (libxl_bitmap_test(&cpumap, i)) {
+            rc = xc_cpupool_removecpu(ctx->xch, poolid, i);
+            if (rc) {
+                LOGEV(ERROR, rc, "Error removing cpu from cpupool");
+                rc = ERROR_FAIL;
+                goto out1;
+            }
+        }
+
+    rc = xc_cpupool_destroy(ctx->xch, poolid);
+    if (rc) {
+        LOGEV(ERROR, rc, "Could not destroy cpupool");
+        rc = ERROR_FAIL;
+        goto out1;
+    }
+
+    for (;;) {
+        t = xs_transaction_start(ctx->xsh);
+
+        xs_rm(ctx->xsh, XBT_NULL, GCSPRINTF("/local/pool/%d", poolid));
+
+        if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
+            break;
+    }
+
+    rc = 0;
+
+out1:
+    libxl_bitmap_dispose(&cpumap);
+out:
+    xc_cpupool_infofree(ctx->xch, info);
+    GC_FREE;
+
+    return rc;
+}
+
+int libxl_cpupool_rename(libxl_ctx *ctx, const char *name, uint32_t poolid)
+{
+    GC_INIT(ctx);
+    xs_transaction_t t;
+    xc_cpupoolinfo_t *info;
+    int rc;
+
+    info = xc_cpupool_getinfo(ctx->xch, poolid);
+    if (info == NULL) {
+        GC_FREE;
+        return ERROR_NOMEM;
+    }
+
+    rc = ERROR_INVAL;
+    if (info->cpupool_id != poolid)
+        goto out;
+
+    rc = 0;
+
+    for (;;) {
+        t = xs_transaction_start(ctx->xsh);
+
+        libxl__xs_printf(gc, t,
+                         GCSPRINTF("/local/pool/%d/name", poolid),
+                         "%s", name);
+
+        if (xs_transaction_end(ctx->xsh, t, 0))
+            break;
+
+        if (errno == EAGAIN)
+            continue;
+
+        rc = ERROR_FAIL;
+        break;
+    }
+
+out:
+    xc_cpupool_infofree(ctx->xch, info);
+    GC_FREE;
+
+    return rc;
+}
+
+int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu)
+{
+    GC_INIT(ctx);
+    int rc = 0;
+
+    rc = xc_cpupool_addcpu(ctx->xch, poolid, cpu);
+    if (rc) {
+        LOGE(ERROR, "Error moving cpu %d to cpupool", cpu);
+        rc = ERROR_FAIL;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_cpupool_cpuadd_cpumap(libxl_ctx *ctx, uint32_t poolid,
+                                const libxl_bitmap *cpumap)
+{
+    int c, ncpus = 0, rc = 0;
+
+    libxl_for_each_set_bit(c, *cpumap) {
+        if (!libxl_cpupool_cpuadd(ctx, poolid, c))
+            ncpus++;
+    }
+
+    if (ncpus != libxl_bitmap_count_set(cpumap))
+        rc = ERROR_FAIL;
+
+    return rc;
+}
+
+int libxl_cpupool_cpuadd_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
+{
+    int rc = 0;
+    int cpu, nr;
+    libxl_bitmap freemap;
+    libxl_cputopology *topology;
+
+    if (libxl_get_freecpus(ctx, &freemap)) {
+        return ERROR_FAIL;
+    }
+
+    topology = libxl_get_cpu_topology(ctx, &nr);
+    if (!topology) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    *cpus = 0;
+    for (cpu = 0; cpu < nr; cpu++) {
+        if (libxl_bitmap_test(&freemap, cpu) && (topology[cpu].node == node) &&
+            !libxl_cpupool_cpuadd(ctx, poolid, cpu)) {
+                (*cpus)++;
+        }
+        libxl_cputopology_dispose(&topology[cpu]);
+    }
+
+    free(topology);
+out:
+    libxl_bitmap_dispose(&freemap);
+    return rc;
+}
+
+int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu)
+{
+    GC_INIT(ctx);
+    int rc = 0;
+
+    rc = xc_cpupool_removecpu(ctx->xch, poolid, cpu);
+    if (rc) {
+        LOGE(ERROR, "Error removing cpu %d from cpupool", cpu);
+        rc = ERROR_FAIL;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_cpupool_cpuremove_cpumap(libxl_ctx *ctx, uint32_t poolid,
+                                   const libxl_bitmap *cpumap)
+{
+    int c, ncpus = 0, rc = 0;
+
+    libxl_for_each_set_bit(c, *cpumap) {
+        if (!libxl_cpupool_cpuremove(ctx, poolid, c))
+            ncpus++;
+    }
+
+    if (ncpus != libxl_bitmap_count_set(cpumap))
+        rc = ERROR_FAIL;
+
+    return rc;
+}
+
+int libxl_cpupool_cpuremove_node(libxl_ctx *ctx, uint32_t poolid, int node, int *cpus)
+{
+    int ret = 0;
+    int n_pools;
+    int p;
+    int cpu, nr_cpus;
+    libxl_cputopology *topology;
+    libxl_cpupoolinfo *poolinfo;
+
+    poolinfo = libxl_list_cpupool(ctx, &n_pools);
+    if (!poolinfo) {
+        return ERROR_NOMEM;
+    }
+
+    topology = libxl_get_cpu_topology(ctx, &nr_cpus);
+    if (!topology) {
+        ret = ERROR_FAIL;
+        goto out;
+    }
+
+    *cpus = 0;
+    for (p = 0; p < n_pools; p++) {
+        if (poolinfo[p].poolid == poolid) {
+            for (cpu = 0; cpu < nr_cpus; cpu++) {
+                if ((topology[cpu].node == node) &&
+                    libxl_bitmap_test(&poolinfo[p].cpumap, cpu) &&
+                    !libxl_cpupool_cpuremove(ctx, poolid, cpu)) {
+                        (*cpus)++;
+                }
+            }
+        }
+    }
+
+    libxl_cputopology_list_free(topology, nr_cpus);
+
+out:
+    libxl_cpupoolinfo_list_free(poolinfo, n_pools);
+
+    return ret;
+}
+
+int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid)
+{
+    GC_INIT(ctx);
+    int rc;
+
+    rc = xc_cpupool_movedomain(ctx->xch, poolid, domid);
+    if (rc) {
+        LOGEVD(ERROR, rc, domid, "Error moving domain to cpupool");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+
+    GC_FREE;
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/9] libxl: carve out scheduler specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
  2017-02-08 13:13 ` [PATCH 1/9] libxl: adjust copyright comment of libxl.c Juergen Gross
  2017-02-08 13:13 ` [PATCH 2/9] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 4/9] libxl: carve out disk " Juergen Gross
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the scheduler
related functions to libxl_sched.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile      |   2 +-
 tools/libxl/libxl.c       | 891 --------------------------------------------
 tools/libxl/libxl_sched.c | 915 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 916 insertions(+), 892 deletions(-)
 create mode 100644 tools/libxl/libxl_sched.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 0125871..7514cc2 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -137,7 +137,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_qmp.o libxl_event.o libxl_fork.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
 			libxl_vtpm.o libxl_nic.o \
-			libxl_cpupool.o \
+			libxl_cpupool.o libxl_sched.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 53ad081..3f7aa52 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -4833,146 +4833,6 @@ err:
     return NULL;
 }
 
-static int libxl__set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid,
-                                   uint32_t vcpuid,
-                                   const libxl_bitmap *cpumap_hard,
-                                   const libxl_bitmap *cpumap_soft,
-                                   unsigned flags)
-{
-    GC_INIT(ctx);
-    libxl_bitmap hard, soft;
-    int rc;
-
-    libxl_bitmap_init(&hard);
-    libxl_bitmap_init(&soft);
-
-    if (!cpumap_hard && !cpumap_soft && !flags) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    /*
-     * Xen wants writable hard and/or soft cpumaps, to put back in them
-     * the effective hard and/or soft affinity that will be used.
-     */
-    if (cpumap_hard) {
-        rc = libxl_cpu_bitmap_alloc(ctx, &hard, 0);
-        if (rc)
-            goto out;
-
-        libxl__bitmap_copy_best_effort(gc, &hard, cpumap_hard);
-        flags |= XEN_VCPUAFFINITY_HARD;
-    }
-    if (cpumap_soft) {
-        rc = libxl_cpu_bitmap_alloc(ctx, &soft, 0);
-        if (rc)
-            goto out;
-
-        libxl__bitmap_copy_best_effort(gc, &soft, cpumap_soft);
-        flags |= XEN_VCPUAFFINITY_SOFT;
-    }
-
-    if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid,
-                            cpumap_hard ? hard.map : NULL,
-                            cpumap_soft ? soft.map : NULL,
-                            flags)) {
-        LOGED(ERROR, domid, "Setting vcpu affinity");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /*
-     * Let's check the results. Hard affinity will never be empty, but it
-     * is possible that Xen will use something different from what we asked
-     * for various reasons. If that's the case, report it.
-     */
-    if (cpumap_hard &&
-        !libxl_bitmap_equal(cpumap_hard, &hard, 0))
-        LOGD(DEBUG, domid, "New hard affinity for vcpu %d has unreachable cpus", vcpuid);
-    /*
-     * Soft affinity can both be different from what asked and empty. Check
-     * for (and report) both.
-     */
-    if (cpumap_soft) {
-        if (!libxl_bitmap_equal(cpumap_soft, &soft, 0))
-            LOGD(DEBUG, domid, "New soft affinity for vcpu %d has unreachable cpus",
-                 vcpuid);
-        if (libxl_bitmap_is_empty(&soft))
-            LOGD(WARN, domid, "All cpus in soft affinity of vcpu %d are unreachable."
-                 " Only hard affinity will be considered for scheduling",
-                 vcpuid);
-    }
-
-    rc = 0;
- out:
-    libxl_bitmap_dispose(&hard);
-    libxl_bitmap_dispose(&soft);
-    GC_FREE;
-    return rc;
-}
-
-int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
-                           const libxl_bitmap *cpumap_hard,
-                           const libxl_bitmap *cpumap_soft)
-{
-    return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
-                                   cpumap_soft, 0);
-}
-
-int libxl_set_vcpuaffinity_force(libxl_ctx *ctx, uint32_t domid,
-                                 uint32_t vcpuid,
-                                 const libxl_bitmap *cpumap_hard,
-                                 const libxl_bitmap *cpumap_soft)
-{
-    return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
-                                   cpumap_soft, XEN_VCPUAFFINITY_FORCE);
-}
-
-int libxl_set_vcpuaffinity_all(libxl_ctx *ctx, uint32_t domid,
-                               unsigned int max_vcpus,
-                               const libxl_bitmap *cpumap_hard,
-                               const libxl_bitmap *cpumap_soft)
-{
-    GC_INIT(ctx);
-    int i, rc = 0;
-
-    for (i = 0; i < max_vcpus; i++) {
-        if (libxl_set_vcpuaffinity(ctx, domid, i, cpumap_hard, cpumap_soft)) {
-            LOGD(WARN, domid, "Failed to set affinity for %d", i);
-            rc = ERROR_FAIL;
-        }
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_domain_set_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_bitmap *nodemap)
-{
-    GC_INIT(ctx);
-    if (xc_domain_node_setaffinity(ctx->xch, domid, nodemap->map)) {
-        LOGED(ERROR, domid, "Setting node affinity");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    GC_FREE;
-    return 0;
-}
-
-int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_bitmap *nodemap)
-{
-    GC_INIT(ctx);
-    if (xc_domain_node_getaffinity(ctx->xch, domid, nodemap->map)) {
-        LOGED(ERROR, domid, "Getting node affinity");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    GC_FREE;
-    return 0;
-}
-
 static int libxl__set_vcpuonline_xenstore(libxl__gc *gc, uint32_t domid,
                                          libxl_bitmap *cpumap,
                                          const libxl_dominfo *info)
@@ -5088,757 +4948,6 @@ out:
     return rc;
 }
 
-int libxl_get_scheduler(libxl_ctx *ctx)
-{
-    int r, sched;
-
-    GC_INIT(ctx);
-    r = xc_sched_id(ctx->xch, &sched);
-    if (r != 0) {
-        LOGE(ERROR, "getting current scheduler id");
-        sched = ERROR_FAIL;
-    }
-    GC_FREE;
-    return sched;
-}
-
-static int sched_arinc653_domain_set(libxl__gc *gc, uint32_t domid,
-                                     const libxl_domain_sched_params *scinfo)
-{
-    /* Currently, the ARINC 653 scheduler does not take any domain-specific
-         configuration, so we simply return success. */
-    return 0;
-}
-
-static int sched_credit_domain_get(libxl__gc *gc, uint32_t domid,
-                                   libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_credit sdom;
-    int rc;
-
-    rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched credit");
-        return ERROR_FAIL;
-    }
-
-    libxl_domain_sched_params_init(scinfo);
-    scinfo->sched = LIBXL_SCHEDULER_CREDIT;
-    scinfo->weight = sdom.weight;
-    scinfo->cap = sdom.cap;
-
-    return 0;
-}
-
-static int sched_credit_domain_set(libxl__gc *gc, uint32_t domid,
-                                   const libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_credit sdom;
-    xc_domaininfo_t domaininfo;
-    int rc;
-
-    rc = xc_domain_getinfolist(CTX->xch, domid, 1, &domaininfo);
-    if (rc < 0) {
-        LOGED(ERROR, domid, "Getting domain info list");
-        return ERROR_FAIL;
-    }
-    if (rc != 1 || domaininfo.domain != domid)
-        return ERROR_INVAL;
-
-    rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched credit");
-        return ERROR_FAIL;
-    }
-
-    if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
-        if (scinfo->weight < 1 || scinfo->weight > 65535) {
-            LOGD(ERROR, domid, "Cpu weight out of range, "
-                 "valid values are within range from 1 to 65535");
-            return ERROR_INVAL;
-        }
-        sdom.weight = scinfo->weight;
-    }
-
-    if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
-        if (scinfo->cap < 0
-            || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
-            LOGD(ERROR, domid, "Cpu cap out of range, "
-                 "valid range is from 0 to %d for specified number of vcpus",
-                 ((domaininfo.max_vcpu_id + 1) * 100));
-            return ERROR_INVAL;
-        }
-        sdom.cap = scinfo->cap;
-    }
-
-    rc = xc_sched_credit_domain_set(CTX->xch, domid, &sdom);
-    if ( rc < 0 ) {
-        LOGED(ERROR, domid, "Setting domain sched credit");
-        return ERROR_FAIL;
-    }
-
-    return 0;
-}
-
-static int sched_ratelimit_check(libxl__gc *gc, int ratelimit)
-{
-    if (ratelimit != 0 &&
-        (ratelimit <  XEN_SYSCTL_SCHED_RATELIMIT_MIN ||
-         ratelimit > XEN_SYSCTL_SCHED_RATELIMIT_MAX)) {
-        LOG(ERROR, "Ratelimit out of range, valid range is from %d to %d",
-            XEN_SYSCTL_SCHED_RATELIMIT_MIN, XEN_SYSCTL_SCHED_RATELIMIT_MAX);
-        return ERROR_INVAL;
-    }
-
-    return 0;
-}
-
-int libxl_sched_credit_params_get(libxl_ctx *ctx, uint32_t poolid,
-                                  libxl_sched_credit_params *scinfo)
-{
-    struct xen_sysctl_credit_schedule sparam;
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_sched_credit_params_get(ctx->xch, poolid, &sparam);
-    if (r < 0) {
-        LOGE(ERROR, "getting Credit scheduler parameters");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    scinfo->tslice_ms = sparam.tslice_ms;
-    scinfo->ratelimit_us = sparam.ratelimit_us;
-
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
-                                  libxl_sched_credit_params *scinfo)
-{
-    struct xen_sysctl_credit_schedule sparam;
-    int r, rc;
-    GC_INIT(ctx);
-
-    if (scinfo->tslice_ms <  XEN_SYSCTL_CSCHED_TSLICE_MIN
-        || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
-        LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
-            XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
-    if (rc) {
-        goto out;
-    }
-    if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
-        LOG(ERROR, "Ratelimit cannot be greater than timeslice");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    sparam.tslice_ms = scinfo->tslice_ms;
-    sparam.ratelimit_us = scinfo->ratelimit_us;
-
-    r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
-    if ( r < 0 ) {
-        LOGE(ERROR, "Setting Credit scheduler parameters");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    scinfo->tslice_ms = sparam.tslice_ms;
-    scinfo->ratelimit_us = sparam.ratelimit_us;
-
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
-                                   libxl_sched_credit2_params *scinfo)
-{
-    struct xen_sysctl_credit2_schedule sparam;
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
-    if (r < 0) {
-        LOGE(ERROR, "getting Credit2 scheduler parameters");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    scinfo->ratelimit_us = sparam.ratelimit_us;
-
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-
-int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
-                                   libxl_sched_credit2_params *scinfo)
-{
-    struct xen_sysctl_credit2_schedule sparam;
-    int r, rc;
-    GC_INIT(ctx);
-
-    rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
-    if (rc) goto out;
-
-    sparam.ratelimit_us = scinfo->ratelimit_us;
-
-    r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
-    if (r < 0) {
-        LOGE(ERROR, "Setting Credit2 scheduler parameters");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    scinfo->ratelimit_us = sparam.ratelimit_us;
-
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
-                                    libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_credit2 sdom;
-    int rc;
-
-    rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched credit2");
-        return ERROR_FAIL;
-    }
-
-    libxl_domain_sched_params_init(scinfo);
-    scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
-    scinfo->weight = sdom.weight;
-
-    return 0;
-}
-
-static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
-                                    const libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_credit2 sdom;
-    int rc;
-
-    rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched credit2");
-        return ERROR_FAIL;
-    }
-
-    if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
-        if (scinfo->weight < 1 || scinfo->weight > 65535) {
-            LOGD(ERROR, domid, "Cpu weight out of range, "
-                        "valid values are within range from 1 to 65535");
-            return ERROR_INVAL;
-        }
-        sdom.weight = scinfo->weight;
-    }
-
-    rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
-    if ( rc < 0 ) {
-        LOGED(ERROR, domid, "Setting domain sched credit2");
-        return ERROR_FAIL;
-    }
-
-    return 0;
-}
-
-static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
-{
-    int rc;
-
-    if (period < 1) {
-        LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    if (budget < 1) {
-        LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    if (budget > period) {
-        LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
-                   "but %d > %d", budget, period);
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    rc = 0;
-out:
-    return rc;
-}
-
-/* Get the RTDS scheduling parameters of vcpu(s) */
-static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
-                               libxl_vcpu_sched_params *scinfo)
-{
-    uint32_t num_vcpus;
-    int i, r, rc;
-    xc_dominfo_t info;
-    struct xen_domctl_schedparam_vcpu *vcpus;
-
-    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Getting domain info");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (scinfo->num_vcpus <= 0) {
-        rc = ERROR_INVAL;
-        goto out;
-    } else {
-        num_vcpus = scinfo->num_vcpus;
-        GCNEW_ARRAY(vcpus, num_vcpus);
-        for (i = 0; i < num_vcpus; i++) {
-            if (scinfo->vcpus[i].vcpuid < 0 ||
-                scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
-                LOGD(ERROR, domid, "VCPU index is out of range, "
-                            "valid values are within range from 0 to %d",
-                            info.max_vcpu_id);
-                rc = ERROR_INVAL;
-                goto out;
-            }
-            vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
-        }
-    }
-
-    r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
-    if (r != 0) {
-        LOGED(ERROR, domid, "Getting vcpu sched rtds");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    scinfo->sched = LIBXL_SCHEDULER_RTDS;
-    for (i = 0; i < num_vcpus; i++) {
-        scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
-        scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
-        scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
-    }
-    rc = 0;
-out:
-    return rc;
-}
-
-/* Get the RTDS scheduling parameters of all vcpus of a domain */
-static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
-                                   libxl_vcpu_sched_params *scinfo)
-{
-    uint32_t num_vcpus;
-    int i, r, rc;
-    xc_dominfo_t info;
-    struct xen_domctl_schedparam_vcpu *vcpus;
-
-    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Getting domain info");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (scinfo->num_vcpus > 0) {
-        rc = ERROR_INVAL;
-        goto out;
-    } else {
-        num_vcpus = info.max_vcpu_id + 1;
-        GCNEW_ARRAY(vcpus, num_vcpus);
-        for (i = 0; i < num_vcpus; i++)
-            vcpus[i].vcpuid = i;
-    }
-
-    r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
-    if (r != 0) {
-        LOGED(ERROR, domid, "Getting vcpu sched rtds");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    scinfo->sched = LIBXL_SCHEDULER_RTDS;
-    scinfo->num_vcpus = num_vcpus;
-    scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
-                                  sizeof(libxl_sched_params));
-
-    for (i = 0; i < num_vcpus; i++) {
-        scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
-        scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
-        scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
-    }
-    rc = 0;
-out:
-    return rc;
-}
-
-/* Set the RTDS scheduling parameters of vcpu(s) */
-static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
-                               const libxl_vcpu_sched_params *scinfo)
-{
-    int r, rc;
-    int i;
-    uint16_t max_vcpuid;
-    xc_dominfo_t info;
-    struct xen_domctl_schedparam_vcpu *vcpus;
-
-    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Getting domain info");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    max_vcpuid = info.max_vcpu_id;
-
-    if (scinfo->num_vcpus <= 0) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    for (i = 0; i < scinfo->num_vcpus; i++) {
-        if (scinfo->vcpus[i].vcpuid < 0 ||
-            scinfo->vcpus[i].vcpuid > max_vcpuid) {
-            LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
-                        scinfo->vcpus[i].vcpuid, max_vcpuid);
-            rc = ERROR_INVAL;
-            goto out;
-        }
-        rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
-                                        scinfo->vcpus[i].budget);
-        if (rc) {
-            rc = ERROR_INVAL;
-            goto out;
-        }
-    }
-    GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
-    for (i = 0; i < scinfo->num_vcpus; i++) {
-        vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
-        vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
-        vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
-    }
-
-    r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
-                               vcpus, scinfo->num_vcpus);
-    if (r != 0) {
-        LOGED(ERROR, domid, "Setting vcpu sched rtds");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    rc = 0;
-out:
-    return rc;
-}
-
-/* Set the RTDS scheduling parameters of all vcpus of a domain */
-static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
-                                   const libxl_vcpu_sched_params *scinfo)
-{
-    int r, rc;
-    int i;
-    uint16_t max_vcpuid;
-    xc_dominfo_t info;
-    struct xen_domctl_schedparam_vcpu *vcpus;
-    uint32_t num_vcpus;
-
-    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Getting domain info");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    max_vcpuid = info.max_vcpu_id;
-
-    if (scinfo->num_vcpus != 1) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
-                                   scinfo->vcpus[0].budget)) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    num_vcpus = max_vcpuid + 1;
-    GCNEW_ARRAY(vcpus, num_vcpus);
-    for (i = 0; i < num_vcpus; i++) {
-        vcpus[i].vcpuid = i;
-        vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
-        vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
-    }
-
-    r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
-                               vcpus, num_vcpus);
-    if (r != 0) {
-        LOGED(ERROR, domid, "Setting vcpu sched rtds");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    rc = 0;
-out:
-    return rc;
-}
-
-static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
-                               libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_rtds sdom;
-    int rc;
-
-    rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched rtds");
-        return ERROR_FAIL;
-    }
-
-    libxl_domain_sched_params_init(scinfo);
-
-    scinfo->sched = LIBXL_SCHEDULER_RTDS;
-    scinfo->period = sdom.period;
-    scinfo->budget = sdom.budget;
-
-    return 0;
-}
-
-static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
-                               const libxl_domain_sched_params *scinfo)
-{
-    struct xen_domctl_sched_rtds sdom;
-    int rc;
-
-    rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Getting domain sched rtds");
-        return ERROR_FAIL;
-    }
-    if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
-        sdom.period = scinfo->period;
-    if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
-        sdom.budget = scinfo->budget;
-    if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
-        return ERROR_INVAL;
-
-    rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
-    if (rc < 0) {
-        LOGED(ERROR, domid, "Setting domain sched rtds");
-        return ERROR_FAIL;
-    }
-
-    return 0;
-}
-
-int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
-                                  const libxl_domain_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    libxl_scheduler sched = scinfo->sched;
-    int ret;
-
-    if (sched == LIBXL_SCHEDULER_UNKNOWN)
-        sched = libxl__domain_scheduler(gc, domid);
-
-    switch (sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler no longer available");
-        ret=ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-        ret=sched_credit_domain_set(gc, domid, scinfo);
-        break;
-    case LIBXL_SCHEDULER_CREDIT2:
-        ret=sched_credit2_domain_set(gc, domid, scinfo);
-        break;
-    case LIBXL_SCHEDULER_ARINC653:
-        ret=sched_arinc653_domain_set(gc, domid, scinfo);
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        ret=sched_rtds_domain_set(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        ret=ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return ret;
-}
-
-int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
-                                const libxl_vcpu_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    libxl_scheduler sched = scinfo->sched;
-    int rc;
-
-    if (sched == LIBXL_SCHEDULER_UNKNOWN)
-        sched = libxl__domain_scheduler(gc, domid);
-
-    switch (sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler no longer available");
-        rc = ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-    case LIBXL_SCHEDULER_CREDIT2:
-    case LIBXL_SCHEDULER_ARINC653:
-        LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
-        rc = ERROR_INVAL;
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        rc = sched_rtds_vcpu_set(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
-                                    const libxl_vcpu_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    libxl_scheduler sched = scinfo->sched;
-    int rc;
-
-    if (sched == LIBXL_SCHEDULER_UNKNOWN)
-        sched = libxl__domain_scheduler(gc, domid);
-
-    switch (sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler no longer available");
-        rc = ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-    case LIBXL_SCHEDULER_CREDIT2:
-    case LIBXL_SCHEDULER_ARINC653:
-        LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
-        rc = ERROR_INVAL;
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_domain_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    int ret;
-
-    libxl_domain_sched_params_init(scinfo);
-
-    scinfo->sched = libxl__domain_scheduler(gc, domid);
-
-    switch (scinfo->sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler no longer available");
-        ret=ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-        ret=sched_credit_domain_get(gc, domid, scinfo);
-        break;
-    case LIBXL_SCHEDULER_CREDIT2:
-        ret=sched_credit2_domain_get(gc, domid, scinfo);
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        ret=sched_rtds_domain_get(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        ret=ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return ret;
-}
-
-int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
-                                libxl_vcpu_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    int rc;
-
-    scinfo->sched = libxl__domain_scheduler(gc, domid);
-
-    switch (scinfo->sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler is no longer available");
-        rc = ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-    case LIBXL_SCHEDULER_CREDIT2:
-    case LIBXL_SCHEDULER_ARINC653:
-        LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
-        rc = ERROR_INVAL;
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        rc = sched_rtds_vcpu_get(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
-                                    libxl_vcpu_sched_params *scinfo)
-{
-    GC_INIT(ctx);
-    int rc;
-
-    scinfo->sched = libxl__domain_scheduler(gc, domid);
-
-    switch (scinfo->sched) {
-    case LIBXL_SCHEDULER_SEDF:
-        LOGD(ERROR, domid, "SEDF scheduler is no longer available");
-        rc = ERROR_FEATURE_REMOVED;
-        break;
-    case LIBXL_SCHEDULER_CREDIT:
-    case LIBXL_SCHEDULER_CREDIT2:
-    case LIBXL_SCHEDULER_ARINC653:
-        LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
-        rc = ERROR_INVAL;
-        break;
-    case LIBXL_SCHEDULER_RTDS:
-        rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
-        break;
-    default:
-        LOGD(ERROR, domid, "Unknown scheduler");
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
 static int libxl__domain_s3_resume(libxl__gc *gc, int domid)
 {
     int rc = 0;
diff --git a/tools/libxl/libxl_sched.c b/tools/libxl/libxl_sched.c
new file mode 100644
index 0000000..84d3837
--- /dev/null
+++ b/tools/libxl/libxl_sched.c
@@ -0,0 +1,915 @@
+/*
+ * 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"
+
+static int libxl__set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid,
+                                   uint32_t vcpuid,
+                                   const libxl_bitmap *cpumap_hard,
+                                   const libxl_bitmap *cpumap_soft,
+                                   unsigned flags)
+{
+    GC_INIT(ctx);
+    libxl_bitmap hard, soft;
+    int rc;
+
+    libxl_bitmap_init(&hard);
+    libxl_bitmap_init(&soft);
+
+    if (!cpumap_hard && !cpumap_soft && !flags) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    /*
+     * Xen wants writable hard and/or soft cpumaps, to put back in them
+     * the effective hard and/or soft affinity that will be used.
+     */
+    if (cpumap_hard) {
+        rc = libxl_cpu_bitmap_alloc(ctx, &hard, 0);
+        if (rc)
+            goto out;
+
+        libxl__bitmap_copy_best_effort(gc, &hard, cpumap_hard);
+        flags |= XEN_VCPUAFFINITY_HARD;
+    }
+    if (cpumap_soft) {
+        rc = libxl_cpu_bitmap_alloc(ctx, &soft, 0);
+        if (rc)
+            goto out;
+
+        libxl__bitmap_copy_best_effort(gc, &soft, cpumap_soft);
+        flags |= XEN_VCPUAFFINITY_SOFT;
+    }
+
+    if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid,
+                            cpumap_hard ? hard.map : NULL,
+                            cpumap_soft ? soft.map : NULL,
+                            flags)) {
+        LOGED(ERROR, domid, "Setting vcpu affinity");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    /*
+     * Let's check the results. Hard affinity will never be empty, but it
+     * is possible that Xen will use something different from what we asked
+     * for various reasons. If that's the case, report it.
+     */
+    if (cpumap_hard &&
+        !libxl_bitmap_equal(cpumap_hard, &hard, 0))
+        LOGD(DEBUG, domid, "New hard affinity for vcpu %d has unreachable cpus", vcpuid);
+    /*
+     * Soft affinity can both be different from what asked and empty. Check
+     * for (and report) both.
+     */
+    if (cpumap_soft) {
+        if (!libxl_bitmap_equal(cpumap_soft, &soft, 0))
+            LOGD(DEBUG, domid, "New soft affinity for vcpu %d has unreachable cpus",
+                 vcpuid);
+        if (libxl_bitmap_is_empty(&soft))
+            LOGD(WARN, domid, "All cpus in soft affinity of vcpu %d are unreachable."
+                 " Only hard affinity will be considered for scheduling",
+                 vcpuid);
+    }
+
+    rc = 0;
+ out:
+    libxl_bitmap_dispose(&hard);
+    libxl_bitmap_dispose(&soft);
+    GC_FREE;
+    return rc;
+}
+
+int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
+                           const libxl_bitmap *cpumap_hard,
+                           const libxl_bitmap *cpumap_soft)
+{
+    return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
+                                   cpumap_soft, 0);
+}
+
+int libxl_set_vcpuaffinity_force(libxl_ctx *ctx, uint32_t domid,
+                                 uint32_t vcpuid,
+                                 const libxl_bitmap *cpumap_hard,
+                                 const libxl_bitmap *cpumap_soft)
+{
+    return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
+                                   cpumap_soft, XEN_VCPUAFFINITY_FORCE);
+}
+
+int libxl_set_vcpuaffinity_all(libxl_ctx *ctx, uint32_t domid,
+                               unsigned int max_vcpus,
+                               const libxl_bitmap *cpumap_hard,
+                               const libxl_bitmap *cpumap_soft)
+{
+    GC_INIT(ctx);
+    int i, rc = 0;
+
+    for (i = 0; i < max_vcpus; i++) {
+        if (libxl_set_vcpuaffinity(ctx, domid, i, cpumap_hard, cpumap_soft)) {
+            LOGD(WARN, domid, "Failed to set affinity for %d", i);
+            rc = ERROR_FAIL;
+        }
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_domain_set_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
+                                  libxl_bitmap *nodemap)
+{
+    GC_INIT(ctx);
+    if (xc_domain_node_setaffinity(ctx->xch, domid, nodemap->map)) {
+        LOGED(ERROR, domid, "Setting node affinity");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    GC_FREE;
+    return 0;
+}
+
+int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
+                                  libxl_bitmap *nodemap)
+{
+    GC_INIT(ctx);
+    if (xc_domain_node_getaffinity(ctx->xch, domid, nodemap->map)) {
+        LOGED(ERROR, domid, "Getting node affinity");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    GC_FREE;
+    return 0;
+}
+
+int libxl_get_scheduler(libxl_ctx *ctx)
+{
+    int r, sched;
+
+    GC_INIT(ctx);
+    r = xc_sched_id(ctx->xch, &sched);
+    if (r != 0) {
+        LOGE(ERROR, "getting current scheduler id");
+        sched = ERROR_FAIL;
+    }
+    GC_FREE;
+    return sched;
+}
+
+static int sched_arinc653_domain_set(libxl__gc *gc, uint32_t domid,
+                                     const libxl_domain_sched_params *scinfo)
+{
+    /* Currently, the ARINC 653 scheduler does not take any domain-specific
+         configuration, so we simply return success. */
+    return 0;
+}
+
+static int sched_credit_domain_get(libxl__gc *gc, uint32_t domid,
+                                   libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_credit sdom;
+    int rc;
+
+    rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched credit");
+        return ERROR_FAIL;
+    }
+
+    libxl_domain_sched_params_init(scinfo);
+    scinfo->sched = LIBXL_SCHEDULER_CREDIT;
+    scinfo->weight = sdom.weight;
+    scinfo->cap = sdom.cap;
+
+    return 0;
+}
+
+static int sched_credit_domain_set(libxl__gc *gc, uint32_t domid,
+                                   const libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_credit sdom;
+    xc_domaininfo_t domaininfo;
+    int rc;
+
+    rc = xc_domain_getinfolist(CTX->xch, domid, 1, &domaininfo);
+    if (rc < 0) {
+        LOGED(ERROR, domid, "Getting domain info list");
+        return ERROR_FAIL;
+    }
+    if (rc != 1 || domaininfo.domain != domid)
+        return ERROR_INVAL;
+
+    rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched credit");
+        return ERROR_FAIL;
+    }
+
+    if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
+        if (scinfo->weight < 1 || scinfo->weight > 65535) {
+            LOGD(ERROR, domid, "Cpu weight out of range, "
+                 "valid values are within range from 1 to 65535");
+            return ERROR_INVAL;
+        }
+        sdom.weight = scinfo->weight;
+    }
+
+    if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
+        if (scinfo->cap < 0
+            || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
+            LOGD(ERROR, domid, "Cpu cap out of range, "
+                 "valid range is from 0 to %d for specified number of vcpus",
+                 ((domaininfo.max_vcpu_id + 1) * 100));
+            return ERROR_INVAL;
+        }
+        sdom.cap = scinfo->cap;
+    }
+
+    rc = xc_sched_credit_domain_set(CTX->xch, domid, &sdom);
+    if ( rc < 0 ) {
+        LOGED(ERROR, domid, "Setting domain sched credit");
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+static int sched_ratelimit_check(libxl__gc *gc, int ratelimit)
+{
+    if (ratelimit != 0 &&
+        (ratelimit <  XEN_SYSCTL_SCHED_RATELIMIT_MIN ||
+         ratelimit > XEN_SYSCTL_SCHED_RATELIMIT_MAX)) {
+        LOG(ERROR, "Ratelimit out of range, valid range is from %d to %d",
+            XEN_SYSCTL_SCHED_RATELIMIT_MIN, XEN_SYSCTL_SCHED_RATELIMIT_MAX);
+        return ERROR_INVAL;
+    }
+
+    return 0;
+}
+
+int libxl_sched_credit_params_get(libxl_ctx *ctx, uint32_t poolid,
+                                  libxl_sched_credit_params *scinfo)
+{
+    struct xen_sysctl_credit_schedule sparam;
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_sched_credit_params_get(ctx->xch, poolid, &sparam);
+    if (r < 0) {
+        LOGE(ERROR, "getting Credit scheduler parameters");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    scinfo->tslice_ms = sparam.tslice_ms;
+    scinfo->ratelimit_us = sparam.ratelimit_us;
+
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
+                                  libxl_sched_credit_params *scinfo)
+{
+    struct xen_sysctl_credit_schedule sparam;
+    int r, rc;
+    GC_INIT(ctx);
+
+    if (scinfo->tslice_ms <  XEN_SYSCTL_CSCHED_TSLICE_MIN
+        || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
+        LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
+            XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
+    if (rc) {
+        goto out;
+    }
+    if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
+        LOG(ERROR, "Ratelimit cannot be greater than timeslice");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    sparam.tslice_ms = scinfo->tslice_ms;
+    sparam.ratelimit_us = scinfo->ratelimit_us;
+
+    r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
+    if ( r < 0 ) {
+        LOGE(ERROR, "Setting Credit scheduler parameters");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    scinfo->tslice_ms = sparam.tslice_ms;
+    scinfo->ratelimit_us = sparam.ratelimit_us;
+
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
+                                   libxl_sched_credit2_params *scinfo)
+{
+    struct xen_sysctl_credit2_schedule sparam;
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
+    if (r < 0) {
+        LOGE(ERROR, "getting Credit2 scheduler parameters");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    scinfo->ratelimit_us = sparam.ratelimit_us;
+
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
+                                   libxl_sched_credit2_params *scinfo)
+{
+    struct xen_sysctl_credit2_schedule sparam;
+    int r, rc;
+    GC_INIT(ctx);
+
+    rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
+    if (rc) goto out;
+
+    sparam.ratelimit_us = scinfo->ratelimit_us;
+
+    r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
+    if (r < 0) {
+        LOGE(ERROR, "Setting Credit2 scheduler parameters");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    scinfo->ratelimit_us = sparam.ratelimit_us;
+
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
+                                    libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_credit2 sdom;
+    int rc;
+
+    rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched credit2");
+        return ERROR_FAIL;
+    }
+
+    libxl_domain_sched_params_init(scinfo);
+    scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
+    scinfo->weight = sdom.weight;
+
+    return 0;
+}
+
+static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
+                                    const libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_credit2 sdom;
+    int rc;
+
+    rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched credit2");
+        return ERROR_FAIL;
+    }
+
+    if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
+        if (scinfo->weight < 1 || scinfo->weight > 65535) {
+            LOGD(ERROR, domid, "Cpu weight out of range, "
+                        "valid values are within range from 1 to 65535");
+            return ERROR_INVAL;
+        }
+        sdom.weight = scinfo->weight;
+    }
+
+    rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
+    if ( rc < 0 ) {
+        LOGED(ERROR, domid, "Setting domain sched credit2");
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
+{
+    int rc;
+
+    if (period < 1) {
+        LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (budget < 1) {
+        LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (budget > period) {
+        LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
+                   "but %d > %d", budget, period);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    rc = 0;
+out:
+    return rc;
+}
+
+/* Get the RTDS scheduling parameters of vcpu(s) */
+static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
+                               libxl_vcpu_sched_params *scinfo)
+{
+    uint32_t num_vcpus;
+    int i, r, rc;
+    xc_dominfo_t info;
+    struct xen_domctl_schedparam_vcpu *vcpus;
+
+    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Getting domain info");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (scinfo->num_vcpus <= 0) {
+        rc = ERROR_INVAL;
+        goto out;
+    } else {
+        num_vcpus = scinfo->num_vcpus;
+        GCNEW_ARRAY(vcpus, num_vcpus);
+        for (i = 0; i < num_vcpus; i++) {
+            if (scinfo->vcpus[i].vcpuid < 0 ||
+                scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
+                LOGD(ERROR, domid, "VCPU index is out of range, "
+                            "valid values are within range from 0 to %d",
+                            info.max_vcpu_id);
+                rc = ERROR_INVAL;
+                goto out;
+            }
+            vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
+        }
+    }
+
+    r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
+    if (r != 0) {
+        LOGED(ERROR, domid, "Getting vcpu sched rtds");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    scinfo->sched = LIBXL_SCHEDULER_RTDS;
+    for (i = 0; i < num_vcpus; i++) {
+        scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
+        scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
+        scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
+    }
+    rc = 0;
+out:
+    return rc;
+}
+
+/* Get the RTDS scheduling parameters of all vcpus of a domain */
+static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
+                                   libxl_vcpu_sched_params *scinfo)
+{
+    uint32_t num_vcpus;
+    int i, r, rc;
+    xc_dominfo_t info;
+    struct xen_domctl_schedparam_vcpu *vcpus;
+
+    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Getting domain info");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (scinfo->num_vcpus > 0) {
+        rc = ERROR_INVAL;
+        goto out;
+    } else {
+        num_vcpus = info.max_vcpu_id + 1;
+        GCNEW_ARRAY(vcpus, num_vcpus);
+        for (i = 0; i < num_vcpus; i++)
+            vcpus[i].vcpuid = i;
+    }
+
+    r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
+    if (r != 0) {
+        LOGED(ERROR, domid, "Getting vcpu sched rtds");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    scinfo->sched = LIBXL_SCHEDULER_RTDS;
+    scinfo->num_vcpus = num_vcpus;
+    scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
+                                  sizeof(libxl_sched_params));
+
+    for (i = 0; i < num_vcpus; i++) {
+        scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
+        scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
+        scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
+    }
+    rc = 0;
+out:
+    return rc;
+}
+
+/* Set the RTDS scheduling parameters of vcpu(s) */
+static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
+                               const libxl_vcpu_sched_params *scinfo)
+{
+    int r, rc;
+    int i;
+    uint16_t max_vcpuid;
+    xc_dominfo_t info;
+    struct xen_domctl_schedparam_vcpu *vcpus;
+
+    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Getting domain info");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    max_vcpuid = info.max_vcpu_id;
+
+    if (scinfo->num_vcpus <= 0) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    for (i = 0; i < scinfo->num_vcpus; i++) {
+        if (scinfo->vcpus[i].vcpuid < 0 ||
+            scinfo->vcpus[i].vcpuid > max_vcpuid) {
+            LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
+                        scinfo->vcpus[i].vcpuid, max_vcpuid);
+            rc = ERROR_INVAL;
+            goto out;
+        }
+        rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
+                                        scinfo->vcpus[i].budget);
+        if (rc) {
+            rc = ERROR_INVAL;
+            goto out;
+        }
+    }
+    GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
+    for (i = 0; i < scinfo->num_vcpus; i++) {
+        vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
+        vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
+        vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
+    }
+
+    r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
+                               vcpus, scinfo->num_vcpus);
+    if (r != 0) {
+        LOGED(ERROR, domid, "Setting vcpu sched rtds");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = 0;
+out:
+    return rc;
+}
+
+/* Set the RTDS scheduling parameters of all vcpus of a domain */
+static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
+                                   const libxl_vcpu_sched_params *scinfo)
+{
+    int r, rc;
+    int i;
+    uint16_t max_vcpuid;
+    xc_dominfo_t info;
+    struct xen_domctl_schedparam_vcpu *vcpus;
+    uint32_t num_vcpus;
+
+    r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Getting domain info");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    max_vcpuid = info.max_vcpu_id;
+
+    if (scinfo->num_vcpus != 1) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
+                                   scinfo->vcpus[0].budget)) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    num_vcpus = max_vcpuid + 1;
+    GCNEW_ARRAY(vcpus, num_vcpus);
+    for (i = 0; i < num_vcpus; i++) {
+        vcpus[i].vcpuid = i;
+        vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
+        vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
+    }
+
+    r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
+                               vcpus, num_vcpus);
+    if (r != 0) {
+        LOGED(ERROR, domid, "Setting vcpu sched rtds");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = 0;
+out:
+    return rc;
+}
+
+static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
+                               libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_rtds sdom;
+    int rc;
+
+    rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched rtds");
+        return ERROR_FAIL;
+    }
+
+    libxl_domain_sched_params_init(scinfo);
+
+    scinfo->sched = LIBXL_SCHEDULER_RTDS;
+    scinfo->period = sdom.period;
+    scinfo->budget = sdom.budget;
+
+    return 0;
+}
+
+static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
+                               const libxl_domain_sched_params *scinfo)
+{
+    struct xen_domctl_sched_rtds sdom;
+    int rc;
+
+    rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
+    if (rc != 0) {
+        LOGED(ERROR, domid, "Getting domain sched rtds");
+        return ERROR_FAIL;
+    }
+    if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
+        sdom.period = scinfo->period;
+    if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
+        sdom.budget = scinfo->budget;
+    if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
+        return ERROR_INVAL;
+
+    rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
+    if (rc < 0) {
+        LOGED(ERROR, domid, "Setting domain sched rtds");
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
+                                  const libxl_domain_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    libxl_scheduler sched = scinfo->sched;
+    int ret;
+
+    if (sched == LIBXL_SCHEDULER_UNKNOWN)
+        sched = libxl__domain_scheduler(gc, domid);
+
+    switch (sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler no longer available");
+        ret=ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+        ret=sched_credit_domain_set(gc, domid, scinfo);
+        break;
+    case LIBXL_SCHEDULER_CREDIT2:
+        ret=sched_credit2_domain_set(gc, domid, scinfo);
+        break;
+    case LIBXL_SCHEDULER_ARINC653:
+        ret=sched_arinc653_domain_set(gc, domid, scinfo);
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        ret=sched_rtds_domain_set(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        ret=ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return ret;
+}
+
+int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
+                                const libxl_vcpu_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    libxl_scheduler sched = scinfo->sched;
+    int rc;
+
+    if (sched == LIBXL_SCHEDULER_UNKNOWN)
+        sched = libxl__domain_scheduler(gc, domid);
+
+    switch (sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler no longer available");
+        rc = ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+    case LIBXL_SCHEDULER_CREDIT2:
+    case LIBXL_SCHEDULER_ARINC653:
+        LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
+        rc = ERROR_INVAL;
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        rc = sched_rtds_vcpu_set(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        rc = ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
+                                    const libxl_vcpu_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    libxl_scheduler sched = scinfo->sched;
+    int rc;
+
+    if (sched == LIBXL_SCHEDULER_UNKNOWN)
+        sched = libxl__domain_scheduler(gc, domid);
+
+    switch (sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler no longer available");
+        rc = ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+    case LIBXL_SCHEDULER_CREDIT2:
+    case LIBXL_SCHEDULER_ARINC653:
+        LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
+        rc = ERROR_INVAL;
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        rc = ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
+                                  libxl_domain_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    int ret;
+
+    libxl_domain_sched_params_init(scinfo);
+
+    scinfo->sched = libxl__domain_scheduler(gc, domid);
+
+    switch (scinfo->sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler no longer available");
+        ret=ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+        ret=sched_credit_domain_get(gc, domid, scinfo);
+        break;
+    case LIBXL_SCHEDULER_CREDIT2:
+        ret=sched_credit2_domain_get(gc, domid, scinfo);
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        ret=sched_rtds_domain_get(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        ret=ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return ret;
+}
+
+int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
+                                libxl_vcpu_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    int rc;
+
+    scinfo->sched = libxl__domain_scheduler(gc, domid);
+
+    switch (scinfo->sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler is no longer available");
+        rc = ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+    case LIBXL_SCHEDULER_CREDIT2:
+    case LIBXL_SCHEDULER_ARINC653:
+        LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
+        rc = ERROR_INVAL;
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        rc = sched_rtds_vcpu_get(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        rc = ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
+                                    libxl_vcpu_sched_params *scinfo)
+{
+    GC_INIT(ctx);
+    int rc;
+
+    scinfo->sched = libxl__domain_scheduler(gc, domid);
+
+    switch (scinfo->sched) {
+    case LIBXL_SCHEDULER_SEDF:
+        LOGD(ERROR, domid, "SEDF scheduler is no longer available");
+        rc = ERROR_FEATURE_REMOVED;
+        break;
+    case LIBXL_SCHEDULER_CREDIT:
+    case LIBXL_SCHEDULER_CREDIT2:
+    case LIBXL_SCHEDULER_ARINC653:
+        LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
+        rc = ERROR_INVAL;
+        break;
+    case LIBXL_SCHEDULER_RTDS:
+        rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
+        break;
+    default:
+        LOGD(ERROR, domid, "Unknown scheduler");
+        rc = ERROR_INVAL;
+        break;
+    }
+
+    GC_FREE;
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/9] libxl: carve out disk specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (2 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 3/9] libxl: carve out scheduler " Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 5/9] libxl: carve out console " Juergen Gross
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the disk
related functions to libxl_disk.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile     |    2 +-
 tools/libxl/libxl.c      | 1234 ---------------------------------------------
 tools/libxl/libxl_disk.c | 1258 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1259 insertions(+), 1235 deletions(-)
 create mode 100644 tools/libxl/libxl_disk.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 7514cc2..baf591d 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -136,7 +136,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_save_callout.o _libxl_save_msgs_callout.o \
 			libxl_qmp.o libxl_event.o libxl_fork.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
-			libxl_vtpm.o libxl_nic.o \
+			libxl_vtpm.o libxl_nic.o libxl_disk.o \
 			libxl_cpupool.o libxl_sched.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 3f7aa52..043c3d6 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -18,7 +18,6 @@
 #include "libxl_arch.h"
 
 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
-#define BACKEND_STRING_SIZE 5
 
 int libxl_ctx_alloc(libxl_ctx **pctx, int version,
                     unsigned flags, xentoollog_logger * lg)
@@ -1199,140 +1198,6 @@ void libxl_evdisable_domain_death(libxl_ctx *ctx,
     GC_FREE;
 }
 
-static void disk_eject_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch *w,
-                                        const char *wpath, const char *epath) {
-    EGC_GC;
-    libxl_evgen_disk_eject *evg = (void*)w;
-    const char *backend;
-    char *value;
-    char backend_type[BACKEND_STRING_SIZE+1];
-    int rc;
-
-    value = libxl__xs_read(gc, XBT_NULL, wpath);
-
-    if (!value || strcmp(value,  "eject"))
-        return;
-
-    if (libxl__xs_printf(gc, XBT_NULL, wpath, "")) {
-        LIBXL__EVENT_DISASTER(egc, "xs_write failed acknowledging eject",
-                              errno, LIBXL_EVENT_TYPE_DISK_EJECT);
-        return;
-    }
-
-    libxl_event *ev = NEW_EVENT(egc, DISK_EJECT, evg->domid, evg->user);
-    libxl_device_disk *disk = &ev->u.disk_eject.disk;
-    
-    rc = libxl__xs_read_checked(gc, XBT_NULL, evg->be_ptr_path, &backend);
-    if (rc) {
-        LIBXL__EVENT_DISASTER(egc, "xs_read failed reading be_ptr_path",
-                              errno, LIBXL_EVENT_TYPE_DISK_EJECT);
-        return;
-    }
-    if (!backend) {
-        /* device has been removed, not simply ejected */
-        return;
-    }
-
-    sscanf(backend,
-            "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE)
-           "[a-z]/%*d/%*d",
-           &disk->backend_domid, backend_type);
-    if (!strcmp(backend_type, "tap") || !strcmp(backend_type, "vbd")) {
-        disk->backend = LIBXL_DISK_BACKEND_TAP;
-    } else if (!strcmp(backend_type, "qdisk")) {
-        disk->backend = LIBXL_DISK_BACKEND_QDISK;
-    } else {
-        disk->backend = LIBXL_DISK_BACKEND_UNKNOWN;
-    }
-
-    disk->pdev_path = strdup(""); /* xxx fixme malloc failure */
-    disk->format = LIBXL_DISK_FORMAT_EMPTY;
-    /* this value is returned to the user: do not free right away */
-    disk->vdev = libxl__strdup(NOGC, evg->vdev);
-    disk->removable = 1;
-    disk->readwrite = 0;
-    disk->is_cdrom = 1;
-
-    libxl__event_occurred(egc, ev);
-}
-
-int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t guest_domid,
-                              const char *vdev, libxl_ev_user user,
-                              libxl_evgen_disk_eject **evgen_out) {
-    GC_INIT(ctx);
-    CTX_LOCK;
-    int rc;
-    char *path;
-    libxl_evgen_disk_eject *evg = NULL;
-
-    evg = malloc(sizeof(*evg));  if (!evg) { rc = ERROR_NOMEM; goto out; }
-    memset(evg, 0, sizeof(*evg));
-    evg->user = user;
-    evg->domid = guest_domid;
-    LIBXL_LIST_INSERT_HEAD(&CTX->disk_eject_evgens, evg, entry);
-
-    uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
-
-    if (!domid)
-        domid = guest_domid;
-
-    int devid = libxl__device_disk_dev_number(vdev, NULL, NULL);
-
-    path = GCSPRINTF("%s/device/vbd/%d/eject",
-                 libxl__xs_get_dompath(gc, domid),
-                 devid);
-    if (!path) { rc = ERROR_NOMEM; goto out; }
-
-    const char *libxl_path = GCSPRINTF("%s/device/vbd/%d",
-                                 libxl__xs_libxl_path(gc, domid),
-                                 devid);
-    evg->be_ptr_path = libxl__sprintf(NOGC, "%s/backend", libxl_path);
-
-    const char *configured_vdev;
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-            GCSPRINTF("%s/dev", libxl_path), &configured_vdev);
-    if (rc) goto out;
-
-    evg->vdev = libxl__strdup(NOGC, configured_vdev);
-
-    rc = libxl__ev_xswatch_register(gc, &evg->watch,
-                                    disk_eject_xswatch_callback, path);
-    if (rc) goto out;
-
-    *evgen_out = evg;
-    CTX_UNLOCK;
-    GC_FREE;
-    return 0;
-
- out:
-    if (evg)
-        libxl__evdisable_disk_eject(gc, evg);
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-}
-
-void libxl__evdisable_disk_eject(libxl__gc *gc, libxl_evgen_disk_eject *evg) {
-    CTX_LOCK;
-
-    LIBXL_LIST_REMOVE(evg, entry);
-
-    if (libxl__ev_xswatch_isregistered(&evg->watch))
-        libxl__ev_xswatch_deregister(gc, &evg->watch);
-
-    free(evg->vdev);
-    free(evg->be_ptr_path);
-    free(evg);
-
-    CTX_UNLOCK;
-}
-
-void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject *evg) {
-    GC_INIT(ctx);
-    libxl__evdisable_disk_eject(gc, evg);
-    GC_FREE;
-}    
-
 /* Callbacks for libxl_domain_destroy */
 
 static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state *dds,
@@ -1950,1045 +1815,6 @@ int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
 }
 
 /******************************************************************************/
-
-int libxl__device_disk_setdefault(libxl__gc *gc, libxl_device_disk *disk,
-                                  uint32_t domid)
-{
-    int rc;
-
-    libxl_defbool_setdefault(&disk->discard_enable, !!disk->readwrite);
-    libxl_defbool_setdefault(&disk->colo_enable, false);
-    libxl_defbool_setdefault(&disk->colo_restore_enable, false);
-
-    rc = libxl__resolve_domid(gc, disk->backend_domname, &disk->backend_domid);
-    if (rc < 0) return rc;
-
-    /* Force Qdisk backend for CDROM devices of guests with a device model. */
-    if (disk->is_cdrom != 0 &&
-        libxl__domain_type(gc, domid) == LIBXL_DOMAIN_TYPE_HVM &&
-        libxl__device_model_version_running(gc, domid) !=
-        LIBXL_DEVICE_MODEL_VERSION_NONE) {
-        if (!(disk->backend == LIBXL_DISK_BACKEND_QDISK ||
-              disk->backend == LIBXL_DISK_BACKEND_UNKNOWN)) {
-            LOGD(ERROR, domid, "Backend for CD devices on HVM guests must be Qdisk");
-            return ERROR_FAIL;
-        }
-        disk->backend = LIBXL_DISK_BACKEND_QDISK;
-    }
-
-    rc = libxl__device_disk_set_backend(gc, disk);
-    return rc;
-}
-
-int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
-                                   const libxl_device_disk *disk,
-                                   libxl__device *device)
-{
-    int devid;
-
-    devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL);
-    if (devid==-1) {
-        LOGD(ERROR, domid, "Invalid or unsupported"" virtual disk identifier %s",
-             disk->vdev);
-        return ERROR_INVAL;
-    }
-
-    device->backend_domid = disk->backend_domid;
-    device->backend_devid = devid;
-
-    switch (disk->backend) {
-        case LIBXL_DISK_BACKEND_PHY:
-            device->backend_kind = LIBXL__DEVICE_KIND_VBD;
-            break;
-        case LIBXL_DISK_BACKEND_TAP:
-            device->backend_kind = LIBXL__DEVICE_KIND_VBD;
-            break;
-        case LIBXL_DISK_BACKEND_QDISK:
-            device->backend_kind = LIBXL__DEVICE_KIND_QDISK;
-            break;
-        default:
-            LOGD(ERROR, domid, "Unrecognized disk backend type: %d",
-                 disk->backend);
-            return ERROR_INVAL;
-    }
-
-    device->domid = domid;
-    device->devid = devid;
-    device->kind  = LIBXL__DEVICE_KIND_VBD;
-
-    return 0;
-}
-
-/* Specific function called directly only by local disk attach,
- * all other users should instead use the regular
- * libxl__device_disk_add wrapper
- *
- * The (optionally) passed function get_vdev will be used to
- * set the vdev the disk should be attached to. When it is set the caller
- * must also pass get_vdev_user, which will be passed to get_vdev.
- *
- * The passed get_vdev function is also in charge of printing
- * the corresponding error message when appropiate.
- */
-static void device_disk_add(libxl__egc *egc, uint32_t domid,
-                           libxl_device_disk *disk,
-                           libxl__ao_device *aodev,
-                           char *get_vdev(libxl__gc *, void *,
-                                          xs_transaction_t),
-                           void *get_vdev_user)
-{
-    STATE_AO_GC(aodev->ao);
-    flexarray_t *front = NULL;
-    flexarray_t *back = NULL;
-    char *dev = NULL, *script;
-    libxl__device *device;
-    int rc;
-    libxl_ctx *ctx = gc->owner;
-    xs_transaction_t t = XBT_NULL;
-    libxl_domain_config d_config;
-    libxl_device_disk disk_saved;
-    libxl__domain_userdata_lock *lock = NULL;
-
-    libxl_domain_config_init(&d_config);
-    libxl_device_disk_init(&disk_saved);
-    libxl_device_disk_copy(ctx, &disk_saved, disk);
-
-    libxl_domain_type type = libxl__domain_type(gc, domid);
-    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /*
-     * get_vdev != NULL -> local attach
-     * get_vdev == NULL -> block attach
-     *
-     * We don't care about local attach state because it's only
-     * intermediate state.
-     */
-    if (!get_vdev && aodev->update_json) {
-        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) goto out;
-
-        DEVICE_ADD(disk, disks, domid, &disk_saved, COMPARE_DISK, &d_config);
-
-        rc = libxl__dm_check_start(gc, &d_config, domid);
-        if (rc) goto out;
-    }
-
-    for (;;) {
-        rc = libxl__xs_transaction_start(gc, &t);
-        if (rc) goto out;
-
-        if (get_vdev) {
-            assert(get_vdev_user);
-            disk->vdev = get_vdev(gc, get_vdev_user, t);
-            if (disk->vdev == NULL) {
-                rc = ERROR_FAIL;
-                goto out;
-            }
-        }
-
-        rc = libxl__device_disk_setdefault(gc, disk, domid);
-        if (rc) goto out;
-
-        front = flexarray_make(gc, 16, 1);
-        back = flexarray_make(gc, 16, 1);
-
-        GCNEW(device);
-        rc = libxl__device_from_disk(gc, domid, disk, device);
-        if (rc != 0) {
-            LOGD(ERROR, domid, "Invalid or unsupported"" virtual disk identifier %s",
-                 disk->vdev);
-            goto out;
-        }
-
-        rc = libxl__device_exists(gc, t, device);
-        if (rc < 0) goto out;
-        if (rc == 1) {              /* already exists in xenstore */
-            LOGD(ERROR, domid, "device already exists in xenstore");
-            aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */
-            rc = ERROR_DEVICE_EXISTS;
-            goto out;
-        }
-
-        switch (disk->backend) {
-            case LIBXL_DISK_BACKEND_PHY:
-                dev = disk->pdev_path;
-
-        do_backend_phy:
-                flexarray_append(back, "params");
-                flexarray_append(back, dev);
-
-                script = libxl__abs_path(gc, disk->script?: "block",
-                                         libxl__xen_script_dir_path());
-                flexarray_append_pair(back, "script", script);
-
-                assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
-                break;
-
-            case LIBXL_DISK_BACKEND_TAP:
-                if (dev == NULL) {
-                    dev = libxl__blktap_devpath(gc, disk->pdev_path,
-                                                disk->format);
-                    if (!dev) {
-                        LOGD(ERROR, domid, "Failed to get blktap devpath for %p",
-                             disk->pdev_path);
-                        rc = ERROR_FAIL;
-                        goto out;
-                    }
-                }
-                flexarray_append(back, "tapdisk-params");
-                flexarray_append(back, GCSPRINTF("%s:%s",
-                    libxl__device_disk_string_of_format(disk->format),
-                    disk->pdev_path));
-
-                /* tap backends with scripts are rejected by
-                 * libxl__device_disk_set_backend */
-                assert(!disk->script);
-
-                /* now create a phy device to export the device to the guest */
-                goto do_backend_phy;
-            case LIBXL_DISK_BACKEND_QDISK:
-                flexarray_append(back, "params");
-                flexarray_append(back, GCSPRINTF("%s:%s",
-                              libxl__device_disk_string_of_format(disk->format), disk->pdev_path));
-                if (libxl_defbool_val(disk->colo_enable)) {
-                    flexarray_append(back, "colo-host");
-                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->colo_host));
-                    flexarray_append(back, "colo-port");
-                    flexarray_append(back, libxl__sprintf(gc, "%d", disk->colo_port));
-                    flexarray_append(back, "colo-export");
-                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->colo_export));
-                    flexarray_append(back, "active-disk");
-                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->active_disk));
-                    flexarray_append(back, "hidden-disk");
-                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->hidden_disk));
-                }
-                assert(device->backend_kind == LIBXL__DEVICE_KIND_QDISK);
-                break;
-            default:
-                LOGD(ERROR, domid, "Unrecognized disk backend type: %d",
-                     disk->backend);
-                rc = ERROR_INVAL;
-                goto out;
-        }
-
-        flexarray_append(back, "frontend-id");
-        flexarray_append(back, GCSPRINTF("%d", domid));
-        flexarray_append(back, "online");
-        flexarray_append(back, "1");
-        flexarray_append(back, "removable");
-        flexarray_append(back, GCSPRINTF("%d", (disk->removable) ? 1 : 0));
-        flexarray_append(back, "bootable");
-        flexarray_append(back, GCSPRINTF("%d", 1));
-        flexarray_append(back, "state");
-        flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
-        flexarray_append(back, "dev");
-        flexarray_append(back, disk->vdev);
-        flexarray_append(back, "type");
-        flexarray_append(back, libxl__device_disk_string_of_backend(disk->backend));
-        flexarray_append(back, "mode");
-        flexarray_append(back, disk->readwrite ? "w" : "r");
-        flexarray_append(back, "device-type");
-        flexarray_append(back, disk->is_cdrom ? "cdrom" : "disk");
-        if (disk->direct_io_safe) {
-            flexarray_append(back, "direct-io-safe");
-            flexarray_append(back, "1");
-        }
-        flexarray_append_pair(back, "discard-enable",
-                              libxl_defbool_val(disk->discard_enable) ?
-                              "1" : "0");
-
-        flexarray_append(front, "backend-id");
-        flexarray_append(front, GCSPRINTF("%d", disk->backend_domid));
-        flexarray_append(front, "state");
-        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
-        flexarray_append(front, "virtual-device");
-        flexarray_append(front, GCSPRINTF("%d", device->devid));
-        flexarray_append(front, "device-type");
-        flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk");
-
-        /*
-         * Old PV kernel disk frontends before 2.6.26 rely on tool stack to
-         * write disk native protocol to frontend node. Xend does this, port
-         * this behaviour to xl.
-         *
-         * New kernels write this node themselves. In that case it just
-         * overwrites an existing node which is OK.
-         */
-        if (type == LIBXL_DOMAIN_TYPE_PV) {
-            const char *protocol =
-                xc_domain_get_native_protocol(ctx->xch, domid);
-            if (protocol) {
-                flexarray_append(front, "protocol");
-                flexarray_append(front, libxl__strdup(gc, protocol));
-            }
-        }
-
-        if (!get_vdev && aodev->update_json) {
-            rc = libxl__set_domain_configuration(gc, domid, &d_config);
-            if (rc) goto out;
-        }
-
-        libxl__device_generic_add(gc, t, device,
-                                  libxl__xs_kvs_of_flexarray(gc, back),
-                                  libxl__xs_kvs_of_flexarray(gc, front),
-                                  NULL);
-
-        rc = libxl__xs_transaction_commit(gc, &t);
-        if (!rc) break;
-        if (rc < 0) goto out;
-    }
-
-    aodev->dev = device;
-    aodev->action = LIBXL__DEVICE_ACTION_ADD;
-    libxl__wait_device_connection(egc, aodev);
-
-    rc = 0;
-
-out:
-    libxl__xs_transaction_abort(gc, &t);
-    if (lock) libxl__unlock_domain_userdata(lock);
-    libxl_device_disk_dispose(&disk_saved);
-    libxl_domain_config_dispose(&d_config);
-    aodev->rc = rc;
-    if (rc) aodev->callback(egc, aodev);
-    return;
-}
-
-static void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
-                                   libxl_device_disk *disk,
-                                   libxl__ao_device *aodev)
-{
-    device_disk_add(egc, domid, disk, aodev, NULL, NULL);
-}
-
-static int libxl__device_disk_from_xenstore(libxl__gc *gc,
-                                         const char *libxl_path,
-                                         libxl_device_disk *disk)
-{
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-    unsigned int len;
-    char *tmp;
-    int rc;
-
-    libxl_device_disk_init(disk);
-
-    const char *backend_path;
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                GCSPRINTF("%s/backend", libxl_path),
-                                &backend_path);
-    if (rc) goto out;
-
-    if (!backend_path) {
-        LOG(ERROR, "disk %s does not exist (no backend path", libxl_path);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = libxl__backendpath_parse_domid(gc, backend_path, &disk->backend_domid);
-    if (rc) {
-        LOG(ERROR, "Unable to fetch device backend domid from %s", backend_path);
-        goto out;
-    }
-
-    /*
-     * "params" may not be present; but everything else must be.
-     * colo releated entries(colo-host, colo-port, colo-export,
-     * active-disk and hidden-disk) are present only if colo is
-     * enabled.
-     */
-    tmp = xs_read(ctx->xsh, XBT_NULL,
-                  GCSPRINTF("%s/params", libxl_path), &len);
-    if (tmp && strchr(tmp, ':')) {
-        disk->pdev_path = strdup(strchr(tmp, ':') + 1);
-        free(tmp);
-    } else {
-        disk->pdev_path = tmp;
-    }
-
-    tmp = xs_read(ctx->xsh, XBT_NULL,
-                  GCSPRINTF("%s/colo-host", libxl_path), &len);
-    if (tmp) {
-        libxl_defbool_set(&disk->colo_enable, true);
-        disk->colo_host = tmp;
-
-        tmp = xs_read(ctx->xsh, XBT_NULL,
-                      GCSPRINTF("%s/colo-port", libxl_path), &len);
-        if (!tmp) {
-            LOG(ERROR, "Missing xenstore node %s/colo-port", libxl_path);
-            goto cleanup;
-        }
-        disk->colo_port = atoi(tmp);
-
-#define XS_READ_COLO(param, item) do {                                  \
-        tmp = xs_read(ctx->xsh, XBT_NULL,                               \
-                      GCSPRINTF("%s/"#param"", libxl_path), &len);         \
-        if (!tmp) {                                                     \
-            LOG(ERROR, "Missing xenstore node %s/"#param"", libxl_path);   \
-            goto cleanup;                                               \
-        }                                                               \
-        disk->item = tmp;                                               \
-} while (0)
-        XS_READ_COLO(colo-export, colo_export);
-        XS_READ_COLO(active-disk, active_disk);
-        XS_READ_COLO(hidden-disk, hidden_disk);
-#undef XS_READ_COLO
-    } else {
-        libxl_defbool_set(&disk->colo_enable, false);
-    }
-
-    tmp = libxl__xs_read(gc, XBT_NULL,
-                         GCSPRINTF("%s/type", libxl_path));
-    if (!tmp) {
-        LOG(ERROR, "Missing xenstore node %s/type", libxl_path);
-        goto cleanup;
-    }
-    libxl_string_to_backend(ctx, tmp, &(disk->backend));
-
-    disk->vdev = xs_read(ctx->xsh, XBT_NULL,
-                         GCSPRINTF("%s/dev", libxl_path), &len);
-    if (!disk->vdev) {
-        LOG(ERROR, "Missing xenstore node %s/dev", libxl_path);
-        goto cleanup;
-    }
-
-    tmp = libxl__xs_read(gc, XBT_NULL, libxl__sprintf
-                         (gc, "%s/removable", libxl_path));
-    if (!tmp) {
-        LOG(ERROR, "Missing xenstore node %s/removable", libxl_path);
-        goto cleanup;
-    }
-    disk->removable = atoi(tmp);
-
-    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/mode", libxl_path));
-    if (!tmp) {
-        LOG(ERROR, "Missing xenstore node %s/mode", libxl_path);
-        goto cleanup;
-    }
-    if (!strcmp(tmp, "w"))
-        disk->readwrite = 1;
-    else
-        disk->readwrite = 0;
-
-    tmp = libxl__xs_read(gc, XBT_NULL,
-                         GCSPRINTF("%s/device-type", libxl_path));
-    if (!tmp) {
-        LOG(ERROR, "Missing xenstore node %s/device-type", libxl_path);
-        goto cleanup;
-    }
-    disk->is_cdrom = !strcmp(tmp, "cdrom");
-
-    disk->format = LIBXL_DISK_FORMAT_UNKNOWN;
-
-    return 0;
-cleanup:
-    rc = ERROR_FAIL;
- out:
-    libxl_device_disk_dispose(disk);
-    return rc;
-}
-
-int libxl_vdev_to_device_disk(libxl_ctx *ctx, uint32_t domid,
-                              const char *vdev, libxl_device_disk *disk)
-{
-    GC_INIT(ctx);
-    char *dom_xl_path, *libxl_path;
-    int devid = libxl__device_disk_dev_number(vdev, NULL, NULL);
-    int rc = ERROR_FAIL;
-
-    if (devid < 0)
-        return ERROR_INVAL;
-
-    libxl_device_disk_init(disk);
-
-    dom_xl_path = libxl__xs_libxl_path(gc, domid);
-    if (!dom_xl_path) {
-        goto out;
-    }
-    libxl_path = GCSPRINTF("%s/device/vbd/%d", dom_xl_path, devid);
-
-    rc = libxl__device_disk_from_xenstore(gc, libxl_path, disk);
-out:
-    GC_FREE;
-    return rc;
-}
-
-
-static int libxl__append_disk_list(libxl__gc *gc,
-                                           uint32_t domid,
-                                           libxl_device_disk **disks,
-                                           int *ndisks)
-{
-    char *libxl_dir_path = NULL;
-    char **dir = NULL;
-    unsigned int n = 0;
-    libxl_device_disk *pdisk = NULL, *pdisk_end = NULL;
-    int rc=0;
-    int initial_disks = *ndisks;
-
-    libxl_dir_path = GCSPRINTF("%s/device/vbd",
-                        libxl__xs_libxl_path(gc, domid));
-    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
-    if (dir && n) {
-        libxl_device_disk *tmp;
-        tmp = realloc(*disks, sizeof (libxl_device_disk) * (*ndisks + n));
-        if (tmp == NULL)
-            return ERROR_NOMEM;
-        *disks = tmp;
-        pdisk = *disks + initial_disks;
-        pdisk_end = *disks + initial_disks + n;
-        for (; pdisk < pdisk_end; pdisk++, dir++) {
-            const char *p;
-            p = GCSPRINTF("%s/%s", libxl_dir_path, *dir);
-            if ((rc=libxl__device_disk_from_xenstore(gc, p, pdisk)))
-                goto out;
-            *ndisks += 1;
-        }
-    }
-out:
-    return rc;
-}
-
-libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num)
-{
-    GC_INIT(ctx);
-    libxl_device_disk *disks = NULL;
-    int rc;
-
-    *num = 0;
-
-    rc = libxl__append_disk_list(gc, domid, &disks, num);
-    if (rc) goto out_err;
-
-    GC_FREE;
-    return disks;
-
-out_err:
-    LOG(ERROR, "Unable to list disks");
-    while (disks && *num) {
-        (*num)--;
-        libxl_device_disk_dispose(&disks[*num]);
-    }
-    free(disks);
-    return NULL;
-}
-
-int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
-                              libxl_device_disk *disk, libxl_diskinfo *diskinfo)
-{
-    GC_INIT(ctx);
-    char *dompath, *fe_path, *libxl_path;
-    char *val;
-    int rc;
-
-    diskinfo->backend = NULL;
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    diskinfo->devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL);
-
-    /* tap devices entries in xenstore are written as vbd devices. */
-    fe_path = GCSPRINTF("%s/device/vbd/%d", dompath, diskinfo->devid);
-    libxl_path = GCSPRINTF("%s/device/vbd/%d",
-                           libxl__xs_libxl_path(gc, domid), diskinfo->devid);
-    diskinfo->backend = xs_read(ctx->xsh, XBT_NULL,
-                                GCSPRINTF("%s/backend", libxl_path), NULL);
-    if (!diskinfo->backend) {
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    rc = libxl__backendpath_parse_domid(gc, diskinfo->backend,
-                                        &diskinfo->backend_id);
-    if (rc) goto out;
-
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
-    diskinfo->state = val ? strtoul(val, NULL, 10) : -1;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/event-channel", fe_path));
-    diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
-    diskinfo->rref = val ? strtoul(val, NULL, 10) : -1;
-    diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
-                                 GCSPRINTF("%s/frontend", libxl_path), NULL);
-    diskinfo->frontend_id = domid;
-
-    GC_FREE;
-    return 0;
-
- out:
-    free(diskinfo->backend);
-    return rc;
-}
-
-int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk,
-                       const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int num = 0, i;
-    libxl_device_disk *disks = NULL, disk_saved, disk_empty;
-    libxl_domain_config d_config;
-    int rc, dm_ver;
-    libxl__device device;
-    const char *be_path, *libxl_path;
-    char * tmp;
-    libxl__domain_userdata_lock *lock = NULL;
-    xs_transaction_t t = XBT_NULL;
-    flexarray_t *insert = NULL, *empty = NULL;
-
-    libxl_domain_config_init(&d_config);
-    libxl_device_disk_init(&disk_empty);
-    libxl_device_disk_init(&disk_saved);
-    libxl_device_disk_copy(ctx, &disk_saved, disk);
-
-    disk_empty.format = LIBXL_DISK_FORMAT_EMPTY;
-    disk_empty.vdev = libxl__strdup(NOGC, disk->vdev);
-    disk_empty.pdev_path = libxl__strdup(NOGC, "");
-    disk_empty.is_cdrom = 1;
-    libxl__device_disk_setdefault(gc, &disk_empty, domid);
-
-    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) {
-        LOGD(ERROR, domid, "cdrom-insert requires an HVM domain");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    if (libxl_get_stubdom_id(ctx, domid) != 0) {
-        LOGD(ERROR, domid, "cdrom-insert doesn't work for stub domains");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    dm_ver = libxl__device_model_version_running(gc, domid);
-    if (dm_ver == -1) {
-        LOGD(ERROR, domid, "Cannot determine device model version");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_NONE) {
-        LOGD(ERROR, domid, "Guests without a device model cannot use cd-insert");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    disks = libxl_device_disk_list(ctx, domid, &num);
-    for (i = 0; i < num; i++) {
-        if (disks[i].is_cdrom && !strcmp(disk->vdev, disks[i].vdev))
-        {
-            /* Found.  Set backend type appropriately. */
-            disk->backend=disks[i].backend;
-            break;
-        }
-    }
-    if (i == num) {
-        LOGD(ERROR, domid, "Virtual device not found");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = libxl__device_disk_setdefault(gc, disk, domid);
-    if (rc) goto out;
-
-    if (!disk->pdev_path) {
-        disk->pdev_path = libxl__strdup(NOGC, "");
-        disk->format = LIBXL_DISK_FORMAT_EMPTY;
-    }
-
-    rc = libxl__device_from_disk(gc, domid, disk, &device);
-    if (rc) goto out;
-
-    be_path = libxl__device_backend_path(gc, &device);
-    libxl_path = libxl__device_libxl_path(gc, &device);
-
-    insert = flexarray_make(gc, 4, 1);
-
-    flexarray_append_pair(insert, "type",
-                          libxl__device_disk_string_of_backend(disk->backend));
-    if (disk->format != LIBXL_DISK_FORMAT_EMPTY)
-        flexarray_append_pair(insert, "params",
-                        GCSPRINTF("%s:%s",
-                            libxl__device_disk_string_of_format(disk->format),
-                            disk->pdev_path));
-    else
-        flexarray_append_pair(insert, "params", "");
-
-    empty = flexarray_make(gc, 4, 1);
-    flexarray_append_pair(empty, "type",
-                          libxl__device_disk_string_of_backend(disk->backend));
-    flexarray_append_pair(empty, "params", "");
-
-    /* Note: CTX lock is already held at this point so lock hierarchy
-     * is maintained.
-     */
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out;
-    }
-
-    /* We need to eject the original image first. This is implemented
-     * by inserting empty media. JSON is not updated.
-     */
-    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
-        rc = libxl__qmp_insert_cdrom(gc, domid, &disk_empty);
-        if (rc) goto out;
-    }
-
-    for (;;) {
-        rc = libxl__xs_transaction_start(gc, &t);
-        if (rc) goto out;
-        /* Sanity check: make sure the device exists before writing here */
-        tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/frontend", libxl_path));
-        if (!tmp)
-        {
-            LOGD(ERROR, domid, "Internal error: %s does not exist",
-                 GCSPRINTF("%s/frontend", libxl_path));
-            rc = ERROR_FAIL;
-            goto out;
-        }
-
-        char **kvs = libxl__xs_kvs_of_flexarray(gc, empty);
-
-        rc = libxl__xs_writev(gc, t, be_path, kvs);
-        if (rc) goto out;
-
-        rc = libxl__xs_writev(gc, t, libxl_path, kvs);
-        if (rc) goto out;
-
-        rc = libxl__xs_transaction_commit(gc, &t);
-        if (!rc) break;
-        if (rc < 0) goto out;
-    }
-
-    rc = libxl__get_domain_configuration(gc, domid, &d_config);
-    if (rc) goto out;
-
-    DEVICE_ADD(disk, disks, domid, &disk_saved, COMPARE_DISK, &d_config);
-
-    rc = libxl__dm_check_start(gc, &d_config, domid);
-    if (rc) goto out;
-
-    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
-        rc = libxl__qmp_insert_cdrom(gc, domid, disk);
-        if (rc) goto out;
-    }
-
-    for (;;) {
-        rc = libxl__xs_transaction_start(gc, &t);
-        if (rc) goto out;
-        /* Sanity check: make sure the device exists before writing here */
-        tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/frontend", libxl_path));
-        if (!tmp)
-        {
-            LOGD(ERROR, domid, "Internal error: %s does not exist",
-                 GCSPRINTF("%s/frontend", libxl_path));
-            rc = ERROR_FAIL;
-            goto out;
-        }
-
-        rc = libxl__set_domain_configuration(gc, domid, &d_config);
-        if (rc) goto out;
-
-        char **kvs = libxl__xs_kvs_of_flexarray(gc, insert);
-
-        rc = libxl__xs_writev(gc, t, be_path, kvs);
-        if (rc) goto out;
-
-        rc = libxl__xs_writev(gc, t, libxl_path, kvs);
-        if (rc) goto out;
-
-        rc = libxl__xs_transaction_commit(gc, &t);
-        if (!rc) break;
-        if (rc < 0) goto out;
-    }
-
-    /* success, no actual async */
-    libxl__ao_complete(egc, ao, 0);
-
-    rc = 0;
-
-out:
-    libxl__xs_transaction_abort(gc, &t);
-    for (i = 0; i < num; i++)
-        libxl_device_disk_dispose(&disks[i]);
-    free(disks);
-    libxl_device_disk_dispose(&disk_empty);
-    libxl_device_disk_dispose(&disk_saved);
-    libxl_domain_config_dispose(&d_config);
-
-    if (lock) libxl__unlock_domain_userdata(lock);
-
-    if (rc) return AO_CREATE_FAIL(rc);
-    return AO_INPROGRESS;
-}
-
-/* libxl__alloc_vdev only works on the local domain, that is the domain
- * where the toolstack is running */
-static char * libxl__alloc_vdev(libxl__gc *gc, void *get_vdev_user,
-        xs_transaction_t t)
-{
-    const char *blkdev_start = (const char *) get_vdev_user;
-    int devid = 0, disk = 0, part = 0;
-    char *libxl_dom_path = libxl__xs_libxl_path(gc, LIBXL_TOOLSTACK_DOMID);
-
-    libxl__device_disk_dev_number(blkdev_start, &disk, &part);
-    if (part != 0) {
-        LOG(ERROR, "blkdev_start is invalid");
-        return NULL;
-    }
-
-    do {
-        devid = libxl__device_disk_dev_number(GCSPRINTF("d%dp0", disk),
-                NULL, NULL);
-        if (devid < 0)
-            return NULL;
-        if (libxl__xs_read(gc, t,
-                    GCSPRINTF("%s/device/vbd/%d/backend",
-                        libxl_dom_path, devid)) == NULL) {
-            if (errno == ENOENT)
-                return libxl__devid_to_vdev(gc, devid);
-            else
-                return NULL;
-        }
-        disk++;
-    } while (1);
-    return NULL;
-}
-
-/* Callbacks */
-
-char *libxl__device_disk_find_local_path(libxl__gc *gc, 
-                                          libxl_domid guest_domid,
-                                          const libxl_device_disk *disk,
-                                          bool qdisk_direct)
-{
-    char *path = NULL;
-
-    /* No local paths for driver domains */
-    if (disk->backend_domname != NULL) {
-        LOG(DEBUG, "Non-local backend, can't access locally.\n");
-        goto out;
-    }
-
-    /*
-     * If this is in raw format, and we're not using a script or a
-     * driver domain, we can access the target path directly.
-     */
-    if (disk->format == LIBXL_DISK_FORMAT_RAW
-        && disk->script == NULL) {
-        path = libxl__strdup(gc, disk->pdev_path);
-        LOG(DEBUG, "Directly accessing local RAW disk %s", path);
-        goto out;
-    } 
-
-    /*
-     * If we're being called for a qemu path, we can pass the target
-     * string directly as well
-     */
-    if (qdisk_direct && disk->backend == LIBXL_DISK_BACKEND_QDISK) {
-        path = libxl__strdup(gc, disk->pdev_path);
-        LOG(DEBUG, "Directly accessing local QDISK target %s", path);
-        goto out;
-    } 
-
-    /* 
-     * If the format isn't raw and / or we're using a script, then see
-     * if the script has written a path to the "cooked" node
-     */
-    if (disk->script && guest_domid != INVALID_DOMID) {
-        libxl__device device;
-        char *be_path, *pdpath;
-        int rc;
-
-        LOGD(DEBUG, guest_domid,
-             "Run from a script; checking for physical-device-path (vdev %s)",
-             disk->vdev);
-
-        rc = libxl__device_from_disk(gc, guest_domid, disk, &device);
-        if (rc < 0)
-            goto out;
-
-        be_path = libxl__device_backend_path(gc, &device);
-
-        pdpath = libxl__sprintf(gc, "%s/physical-device-path", be_path);
-
-        LOGD(DEBUG, guest_domid, "Attempting to read node %s", pdpath);
-        path = libxl__xs_read(gc, XBT_NULL, pdpath);
-
-        if (path)
-            LOGD(DEBUG, guest_domid, "Accessing cooked block device %s", path);
-        else
-            LOGD(DEBUG, guest_domid, "No physical-device-path, can't access locally.");
-
-        goto out;
-    }
-
- out:
-    return path;
-}
-
-static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev);
-
-void libxl__device_disk_local_initiate_attach(libxl__egc *egc,
-                                     libxl__disk_local_state *dls)
-{
-    STATE_AO_GC(dls->ao);
-    int rc;
-    const libxl_device_disk *in_disk = dls->in_disk;
-    libxl_device_disk *disk = &dls->disk;
-    const char *blkdev_start = dls->blkdev_start;
-
-    assert(in_disk->pdev_path);
-
-    disk->vdev = NULL;
-
-    if (dls->diskpath)
-        LOG(DEBUG, "Strange, dls->diskpath already set: %s", dls->diskpath);
-
-    LOG(DEBUG, "Trying to find local path");
-
-    dls->diskpath = libxl__device_disk_find_local_path(gc, INVALID_DOMID,
-                                                       in_disk, false);
-    if (dls->diskpath) {
-        LOG(DEBUG, "Local path found, executing callback.");
-        dls->callback(egc, dls, 0);
-    } else {
-        LOG(DEBUG, "Local path not found, initiating attach.");
-
-        memcpy(disk, in_disk, sizeof(libxl_device_disk));
-        disk->pdev_path = libxl__strdup(gc, in_disk->pdev_path);
-        if (in_disk->script != NULL)
-            disk->script = libxl__strdup(gc, in_disk->script);
-        disk->vdev = NULL;
-        
-        rc = libxl__device_disk_setdefault(gc, disk, LIBXL_TOOLSTACK_DOMID);
-        if (rc) goto out;
-
-        libxl__prepare_ao_device(ao, &dls->aodev);
-        dls->aodev.callback = local_device_attach_cb;
-        device_disk_add(egc, LIBXL_TOOLSTACK_DOMID, disk, &dls->aodev,
-                        libxl__alloc_vdev, (void *) blkdev_start);
-    }
-
-    return;
-
- out:
-    assert(rc);
-    dls->rc = rc;
-    libxl__device_disk_local_initiate_detach(egc, dls);
-    dls->callback(egc, dls, rc);
-}
-
-static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
-    char *be_path = NULL;
-    int rc;
-    libxl__device device;
-    libxl_device_disk *disk = &dls->disk;
-
-    rc = aodev->rc;
-    if (rc) {
-        LOGE(ERROR, "unable locally attach device: %s", disk->pdev_path);
-        goto out;
-    }
-
-    rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID, disk, &device);
-    if (rc < 0)
-        goto out;
-    be_path = libxl__device_backend_path(gc, &device);
-    rc = libxl__wait_for_backend(gc, be_path, GCSPRINTF("%d", XenbusStateConnected));
-    if (rc < 0)
-        goto out;
-
-    dls->diskpath = GCSPRINTF("/dev/%s",
-                              libxl__devid_to_localdev(gc, device.devid));
-    LOG(DEBUG, "locally attached disk %s", dls->diskpath);
-
-    dls->callback(egc, dls, 0);
-    return;
-
- out:
-    assert(rc);
-    dls->rc = rc;
-    libxl__device_disk_local_initiate_detach(egc, dls);
-    return;
-}
-
-/* Callbacks for local detach */
-
-static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev);
-
-void libxl__device_disk_local_initiate_detach(libxl__egc *egc,
-                                     libxl__disk_local_state *dls)
-{
-    STATE_AO_GC(dls->ao);
-    int rc = 0;
-    libxl_device_disk *disk = &dls->disk;
-    libxl__device *device;
-    libxl__ao_device *aodev = &dls->aodev;
-    libxl__prepare_ao_device(ao, aodev);
-
-    if (!dls->diskpath) goto out;
-
-    if (disk->vdev != NULL) {
-        GCNEW(device);
-        rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID,
-                                     disk, device);
-        if (rc != 0) goto out;
-        
-        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
-        aodev->dev = device;
-        aodev->callback = local_device_detach_cb;
-        aodev->force = 0;
-        libxl__initiate_device_generic_remove(egc, aodev);
-        return;
-    }
-
-out:
-    aodev->rc = rc;
-    local_device_detach_cb(egc, aodev);
-    return;
-}
-
-static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
-    int rc;
-
-    if (aodev->rc) {
-        LOGED(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
-                     libxl__device_action_to_string(aodev->action),
-                     libxl__device_kind_to_string(aodev->dev->kind),
-                     aodev->dev->devid);
-        goto out;
-    }
-
-out:
-    /*
-     * If there was an error in dls->rc, it means we have been called from
-     * a failed execution of libxl__device_disk_local_initiate_attach,
-     * so return the original error.
-     */
-    rc = dls->rc ? dls->rc : aodev->rc;
-    dls->callback(egc, dls, rc);
-    return;
-}
-
-/******************************************************************************/
 int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
                               libxl__device_console *console,
                               libxl__domain_build_state *state,
@@ -3523,10 +2349,6 @@ out:
 /******************************************************************************/
 
 /* The following functions are defined:
- * libxl_device_disk_add
- * libxl__add_disks
- * libxl_device_disk_remove
- * libxl_device_disk_destroy
  * libxl_device_vkb_remove
  * libxl_device_vkb_destroy
  * libxl_device_vfb_remove
@@ -3537,11 +2359,6 @@ out:
  * 1. add support for secondary consoles to xenconsoled
  * 2. dynamically add/remove qemu chardevs via qmp messages. */
 
-/* disk */
-LIBXL_DEFINE_DEVICE_ADD(disk)
-LIBXL_DEFINE_DEVICES_ADD(disk)
-LIBXL_DEFINE_DEVICE_REMOVE(disk)
-
 /* vkb */
 LIBXL_DEFINE_DEVICE_REMOVE(vkb)
 
@@ -5647,57 +4464,6 @@ out:
     return rc;
 }
 
-static int libxl_device_disk_compare(libxl_device_disk *d1,
-                                     libxl_device_disk *d2)
-{
-    return COMPARE_DISK(d1, d2);
-}
-
-/* Take care of removable device. We maintain invariant in the
- * insert / remove operation so that:
- * 1. if xenstore is "empty" while JSON is not, the result
- *    is "empty"
- * 2. if xenstore has a different media than JSON, use the
- *    one in JSON
- * 3. if xenstore and JSON have the same media, well, you
- *    know the answer :-)
- *
- * Currently there is only one removable device -- CDROM.
- * Look for libxl_cdrom_insert for reference.
- */
-static void libxl_device_disk_merge(libxl_ctx *ctx, void *d1, void *d2)
-{
-    GC_INIT(ctx);
-    libxl_device_disk *src = d1;
-    libxl_device_disk *dst = d2;
-
-    if (src->removable) {
-        if (!src->pdev_path || *src->pdev_path == '\0') {
-            /* 1, no media in drive */
-            free(dst->pdev_path);
-            dst->pdev_path = libxl__strdup(NOGC, "");
-            dst->format = LIBXL_DISK_FORMAT_EMPTY;
-        } else {
-            /* 2 and 3, use JSON, no need to touch anything */
-            ;
-        }
-    }
-}
-
-static int libxl_device_disk_dm_needed(void *e, unsigned domid)
-{
-    libxl_device_disk *elem = e;
-
-    return elem->backend == LIBXL_DISK_BACKEND_QDISK &&
-           elem->backend_domid == domid;
-}
-
-DEFINE_DEVICE_TYPE_STRUCT(disk,
-    .merge       = libxl_device_disk_merge,
-    .dm_needed   = libxl_device_disk_dm_needed,
-    .skip_attach = 1
-);
-
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_disk.c b/tools/libxl/libxl_disk.c
new file mode 100644
index 0000000..ac49df2
--- /dev/null
+++ b/tools/libxl/libxl_disk.c
@@ -0,0 +1,1258 @@
+/*
+ * 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 BACKEND_STRING_SIZE 5
+
+static void disk_eject_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch *w,
+                                        const char *wpath, const char *epath) {
+    EGC_GC;
+    libxl_evgen_disk_eject *evg = (void*)w;
+    const char *backend;
+    char *value;
+    char backend_type[BACKEND_STRING_SIZE+1];
+    int rc;
+
+    value = libxl__xs_read(gc, XBT_NULL, wpath);
+
+    if (!value || strcmp(value,  "eject"))
+        return;
+
+    if (libxl__xs_printf(gc, XBT_NULL, wpath, "")) {
+        LIBXL__EVENT_DISASTER(egc, "xs_write failed acknowledging eject",
+                              errno, LIBXL_EVENT_TYPE_DISK_EJECT);
+        return;
+    }
+
+    libxl_event *ev = NEW_EVENT(egc, DISK_EJECT, evg->domid, evg->user);
+    libxl_device_disk *disk = &ev->u.disk_eject.disk;
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL, evg->be_ptr_path, &backend);
+    if (rc) {
+        LIBXL__EVENT_DISASTER(egc, "xs_read failed reading be_ptr_path",
+                              errno, LIBXL_EVENT_TYPE_DISK_EJECT);
+        return;
+    }
+    if (!backend) {
+        /* device has been removed, not simply ejected */
+        return;
+    }
+
+    sscanf(backend,
+            "/local/domain/%d/backend/%" TOSTRING(BACKEND_STRING_SIZE)
+           "[a-z]/%*d/%*d",
+           &disk->backend_domid, backend_type);
+    if (!strcmp(backend_type, "tap") || !strcmp(backend_type, "vbd")) {
+        disk->backend = LIBXL_DISK_BACKEND_TAP;
+    } else if (!strcmp(backend_type, "qdisk")) {
+        disk->backend = LIBXL_DISK_BACKEND_QDISK;
+    } else {
+        disk->backend = LIBXL_DISK_BACKEND_UNKNOWN;
+    }
+
+    disk->pdev_path = strdup(""); /* xxx fixme malloc failure */
+    disk->format = LIBXL_DISK_FORMAT_EMPTY;
+    /* this value is returned to the user: do not free right away */
+    disk->vdev = libxl__strdup(NOGC, evg->vdev);
+    disk->removable = 1;
+    disk->readwrite = 0;
+    disk->is_cdrom = 1;
+
+    libxl__event_occurred(egc, ev);
+}
+
+int libxl_evenable_disk_eject(libxl_ctx *ctx, uint32_t guest_domid,
+                              const char *vdev, libxl_ev_user user,
+                              libxl_evgen_disk_eject **evgen_out) {
+    GC_INIT(ctx);
+    CTX_LOCK;
+    int rc;
+    char *path;
+    libxl_evgen_disk_eject *evg = NULL;
+
+    evg = malloc(sizeof(*evg));  if (!evg) { rc = ERROR_NOMEM; goto out; }
+    memset(evg, 0, sizeof(*evg));
+    evg->user = user;
+    evg->domid = guest_domid;
+    LIBXL_LIST_INSERT_HEAD(&CTX->disk_eject_evgens, evg, entry);
+
+    uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
+
+    if (!domid)
+        domid = guest_domid;
+
+    int devid = libxl__device_disk_dev_number(vdev, NULL, NULL);
+
+    path = GCSPRINTF("%s/device/vbd/%d/eject",
+                 libxl__xs_get_dompath(gc, domid),
+                 devid);
+    if (!path) { rc = ERROR_NOMEM; goto out; }
+
+    const char *libxl_path = GCSPRINTF("%s/device/vbd/%d",
+                                 libxl__xs_libxl_path(gc, domid),
+                                 devid);
+    evg->be_ptr_path = libxl__sprintf(NOGC, "%s/backend", libxl_path);
+
+    const char *configured_vdev;
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+            GCSPRINTF("%s/dev", libxl_path), &configured_vdev);
+    if (rc) goto out;
+
+    evg->vdev = libxl__strdup(NOGC, configured_vdev);
+
+    rc = libxl__ev_xswatch_register(gc, &evg->watch,
+                                    disk_eject_xswatch_callback, path);
+    if (rc) goto out;
+
+    *evgen_out = evg;
+    CTX_UNLOCK;
+    GC_FREE;
+    return 0;
+
+ out:
+    if (evg)
+        libxl__evdisable_disk_eject(gc, evg);
+    CTX_UNLOCK;
+    GC_FREE;
+    return rc;
+}
+
+void libxl__evdisable_disk_eject(libxl__gc *gc, libxl_evgen_disk_eject *evg) {
+    CTX_LOCK;
+
+    LIBXL_LIST_REMOVE(evg, entry);
+
+    if (libxl__ev_xswatch_isregistered(&evg->watch))
+        libxl__ev_xswatch_deregister(gc, &evg->watch);
+
+    free(evg->vdev);
+    free(evg->be_ptr_path);
+    free(evg);
+
+    CTX_UNLOCK;
+}
+
+void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject *evg) {
+    GC_INIT(ctx);
+    libxl__evdisable_disk_eject(gc, evg);
+    GC_FREE;
+}
+
+int libxl__device_disk_setdefault(libxl__gc *gc, libxl_device_disk *disk,
+                                  uint32_t domid)
+{
+    int rc;
+
+    libxl_defbool_setdefault(&disk->discard_enable, !!disk->readwrite);
+    libxl_defbool_setdefault(&disk->colo_enable, false);
+    libxl_defbool_setdefault(&disk->colo_restore_enable, false);
+
+    rc = libxl__resolve_domid(gc, disk->backend_domname, &disk->backend_domid);
+    if (rc < 0) return rc;
+
+    /* Force Qdisk backend for CDROM devices of guests with a device model. */
+    if (disk->is_cdrom != 0 &&
+        libxl__domain_type(gc, domid) == LIBXL_DOMAIN_TYPE_HVM &&
+        libxl__device_model_version_running(gc, domid) !=
+        LIBXL_DEVICE_MODEL_VERSION_NONE) {
+        if (!(disk->backend == LIBXL_DISK_BACKEND_QDISK ||
+              disk->backend == LIBXL_DISK_BACKEND_UNKNOWN)) {
+            LOGD(ERROR, domid, "Backend for CD devices on HVM guests must be Qdisk");
+            return ERROR_FAIL;
+        }
+        disk->backend = LIBXL_DISK_BACKEND_QDISK;
+    }
+
+    rc = libxl__device_disk_set_backend(gc, disk);
+    return rc;
+}
+
+int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
+                                   const libxl_device_disk *disk,
+                                   libxl__device *device)
+{
+    int devid;
+
+    devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL);
+    if (devid==-1) {
+        LOGD(ERROR, domid, "Invalid or unsupported"" virtual disk identifier %s",
+             disk->vdev);
+        return ERROR_INVAL;
+    }
+
+    device->backend_domid = disk->backend_domid;
+    device->backend_devid = devid;
+
+    switch (disk->backend) {
+        case LIBXL_DISK_BACKEND_PHY:
+            device->backend_kind = LIBXL__DEVICE_KIND_VBD;
+            break;
+        case LIBXL_DISK_BACKEND_TAP:
+            device->backend_kind = LIBXL__DEVICE_KIND_VBD;
+            break;
+        case LIBXL_DISK_BACKEND_QDISK:
+            device->backend_kind = LIBXL__DEVICE_KIND_QDISK;
+            break;
+        default:
+            LOGD(ERROR, domid, "Unrecognized disk backend type: %d",
+                 disk->backend);
+            return ERROR_INVAL;
+    }
+
+    device->domid = domid;
+    device->devid = devid;
+    device->kind  = LIBXL__DEVICE_KIND_VBD;
+
+    return 0;
+}
+
+/* Specific function called directly only by local disk attach,
+ * all other users should instead use the regular
+ * libxl__device_disk_add wrapper
+ *
+ * The (optionally) passed function get_vdev will be used to
+ * set the vdev the disk should be attached to. When it is set the caller
+ * must also pass get_vdev_user, which will be passed to get_vdev.
+ *
+ * The passed get_vdev function is also in charge of printing
+ * the corresponding error message when appropiate.
+ */
+static void device_disk_add(libxl__egc *egc, uint32_t domid,
+                           libxl_device_disk *disk,
+                           libxl__ao_device *aodev,
+                           char *get_vdev(libxl__gc *, void *,
+                                          xs_transaction_t),
+                           void *get_vdev_user)
+{
+    STATE_AO_GC(aodev->ao);
+    flexarray_t *front = NULL;
+    flexarray_t *back = NULL;
+    char *dev = NULL, *script;
+    libxl__device *device;
+    int rc;
+    libxl_ctx *ctx = gc->owner;
+    xs_transaction_t t = XBT_NULL;
+    libxl_domain_config d_config;
+    libxl_device_disk disk_saved;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_disk_init(&disk_saved);
+    libxl_device_disk_copy(ctx, &disk_saved, disk);
+
+    libxl_domain_type type = libxl__domain_type(gc, domid);
+    if (type == LIBXL_DOMAIN_TYPE_INVALID) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    /*
+     * get_vdev != NULL -> local attach
+     * get_vdev == NULL -> block attach
+     *
+     * We don't care about local attach state because it's only
+     * intermediate state.
+     */
+    if (!get_vdev && aodev->update_json) {
+        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) goto out;
+
+        DEVICE_ADD(disk, disks, domid, &disk_saved, COMPARE_DISK, &d_config);
+
+        rc = libxl__dm_check_start(gc, &d_config, domid);
+        if (rc) goto out;
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        if (get_vdev) {
+            assert(get_vdev_user);
+            disk->vdev = get_vdev(gc, get_vdev_user, t);
+            if (disk->vdev == NULL) {
+                rc = ERROR_FAIL;
+                goto out;
+            }
+        }
+
+        rc = libxl__device_disk_setdefault(gc, disk, domid);
+        if (rc) goto out;
+
+        front = flexarray_make(gc, 16, 1);
+        back = flexarray_make(gc, 16, 1);
+
+        GCNEW(device);
+        rc = libxl__device_from_disk(gc, domid, disk, device);
+        if (rc != 0) {
+            LOGD(ERROR, domid, "Invalid or unsupported"" virtual disk identifier %s",
+                 disk->vdev);
+            goto out;
+        }
+
+        rc = libxl__device_exists(gc, t, device);
+        if (rc < 0) goto out;
+        if (rc == 1) {              /* already exists in xenstore */
+            LOGD(ERROR, domid, "device already exists in xenstore");
+            aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */
+            rc = ERROR_DEVICE_EXISTS;
+            goto out;
+        }
+
+        switch (disk->backend) {
+            case LIBXL_DISK_BACKEND_PHY:
+                dev = disk->pdev_path;
+
+        do_backend_phy:
+                flexarray_append(back, "params");
+                flexarray_append(back, dev);
+
+                script = libxl__abs_path(gc, disk->script?: "block",
+                                         libxl__xen_script_dir_path());
+                flexarray_append_pair(back, "script", script);
+
+                assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
+                break;
+
+            case LIBXL_DISK_BACKEND_TAP:
+                if (dev == NULL) {
+                    dev = libxl__blktap_devpath(gc, disk->pdev_path,
+                                                disk->format);
+                    if (!dev) {
+                        LOGD(ERROR, domid, "Failed to get blktap devpath for %p",
+                             disk->pdev_path);
+                        rc = ERROR_FAIL;
+                        goto out;
+                    }
+                }
+                flexarray_append(back, "tapdisk-params");
+                flexarray_append(back, GCSPRINTF("%s:%s",
+                    libxl__device_disk_string_of_format(disk->format),
+                    disk->pdev_path));
+
+                /* tap backends with scripts are rejected by
+                 * libxl__device_disk_set_backend */
+                assert(!disk->script);
+
+                /* now create a phy device to export the device to the guest */
+                goto do_backend_phy;
+            case LIBXL_DISK_BACKEND_QDISK:
+                flexarray_append(back, "params");
+                flexarray_append(back, GCSPRINTF("%s:%s",
+                              libxl__device_disk_string_of_format(disk->format), disk->pdev_path));
+                if (libxl_defbool_val(disk->colo_enable)) {
+                    flexarray_append(back, "colo-host");
+                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->colo_host));
+                    flexarray_append(back, "colo-port");
+                    flexarray_append(back, libxl__sprintf(gc, "%d", disk->colo_port));
+                    flexarray_append(back, "colo-export");
+                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->colo_export));
+                    flexarray_append(back, "active-disk");
+                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->active_disk));
+                    flexarray_append(back, "hidden-disk");
+                    flexarray_append(back, libxl__sprintf(gc, "%s", disk->hidden_disk));
+                }
+                assert(device->backend_kind == LIBXL__DEVICE_KIND_QDISK);
+                break;
+            default:
+                LOGD(ERROR, domid, "Unrecognized disk backend type: %d",
+                     disk->backend);
+                rc = ERROR_INVAL;
+                goto out;
+        }
+
+        flexarray_append(back, "frontend-id");
+        flexarray_append(back, GCSPRINTF("%d", domid));
+        flexarray_append(back, "online");
+        flexarray_append(back, "1");
+        flexarray_append(back, "removable");
+        flexarray_append(back, GCSPRINTF("%d", (disk->removable) ? 1 : 0));
+        flexarray_append(back, "bootable");
+        flexarray_append(back, GCSPRINTF("%d", 1));
+        flexarray_append(back, "state");
+        flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+        flexarray_append(back, "dev");
+        flexarray_append(back, disk->vdev);
+        flexarray_append(back, "type");
+        flexarray_append(back, libxl__device_disk_string_of_backend(disk->backend));
+        flexarray_append(back, "mode");
+        flexarray_append(back, disk->readwrite ? "w" : "r");
+        flexarray_append(back, "device-type");
+        flexarray_append(back, disk->is_cdrom ? "cdrom" : "disk");
+        if (disk->direct_io_safe) {
+            flexarray_append(back, "direct-io-safe");
+            flexarray_append(back, "1");
+        }
+        flexarray_append_pair(back, "discard-enable",
+                              libxl_defbool_val(disk->discard_enable) ?
+                              "1" : "0");
+
+        flexarray_append(front, "backend-id");
+        flexarray_append(front, GCSPRINTF("%d", disk->backend_domid));
+        flexarray_append(front, "state");
+        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+        flexarray_append(front, "virtual-device");
+        flexarray_append(front, GCSPRINTF("%d", device->devid));
+        flexarray_append(front, "device-type");
+        flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk");
+
+        /*
+         * Old PV kernel disk frontends before 2.6.26 rely on tool stack to
+         * write disk native protocol to frontend node. Xend does this, port
+         * this behaviour to xl.
+         *
+         * New kernels write this node themselves. In that case it just
+         * overwrites an existing node which is OK.
+         */
+        if (type == LIBXL_DOMAIN_TYPE_PV) {
+            const char *protocol =
+                xc_domain_get_native_protocol(ctx->xch, domid);
+            if (protocol) {
+                flexarray_append(front, "protocol");
+                flexarray_append(front, libxl__strdup(gc, protocol));
+            }
+        }
+
+        if (!get_vdev && aodev->update_json) {
+            rc = libxl__set_domain_configuration(gc, domid, &d_config);
+            if (rc) goto out;
+        }
+
+        libxl__device_generic_add(gc, t, device,
+                                  libxl__xs_kvs_of_flexarray(gc, back),
+                                  libxl__xs_kvs_of_flexarray(gc, front),
+                                  NULL);
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    libxl__wait_device_connection(egc, aodev);
+
+    rc = 0;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_disk_dispose(&disk_saved);
+    libxl_domain_config_dispose(&d_config);
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
+}
+
+static void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
+                                   libxl_device_disk *disk,
+                                   libxl__ao_device *aodev)
+{
+    device_disk_add(egc, domid, disk, aodev, NULL, NULL);
+}
+
+static int libxl__device_disk_from_xenstore(libxl__gc *gc,
+                                         const char *libxl_path,
+                                         libxl_device_disk *disk)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    unsigned int len;
+    char *tmp;
+    int rc;
+
+    libxl_device_disk_init(disk);
+
+    const char *backend_path;
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/backend", libxl_path),
+                                &backend_path);
+    if (rc) goto out;
+
+    if (!backend_path) {
+        LOG(ERROR, "disk %s does not exist (no backend path", libxl_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__backendpath_parse_domid(gc, backend_path, &disk->backend_domid);
+    if (rc) {
+        LOG(ERROR, "Unable to fetch device backend domid from %s", backend_path);
+        goto out;
+    }
+
+    /*
+     * "params" may not be present; but everything else must be.
+     * colo releated entries(colo-host, colo-port, colo-export,
+     * active-disk and hidden-disk) are present only if colo is
+     * enabled.
+     */
+    tmp = xs_read(ctx->xsh, XBT_NULL,
+                  GCSPRINTF("%s/params", libxl_path), &len);
+    if (tmp && strchr(tmp, ':')) {
+        disk->pdev_path = strdup(strchr(tmp, ':') + 1);
+        free(tmp);
+    } else {
+        disk->pdev_path = tmp;
+    }
+
+    tmp = xs_read(ctx->xsh, XBT_NULL,
+                  GCSPRINTF("%s/colo-host", libxl_path), &len);
+    if (tmp) {
+        libxl_defbool_set(&disk->colo_enable, true);
+        disk->colo_host = tmp;
+
+        tmp = xs_read(ctx->xsh, XBT_NULL,
+                      GCSPRINTF("%s/colo-port", libxl_path), &len);
+        if (!tmp) {
+            LOG(ERROR, "Missing xenstore node %s/colo-port", libxl_path);
+            goto cleanup;
+        }
+        disk->colo_port = atoi(tmp);
+
+#define XS_READ_COLO(param, item) do {                                  \
+        tmp = xs_read(ctx->xsh, XBT_NULL,                               \
+                      GCSPRINTF("%s/"#param"", libxl_path), &len);         \
+        if (!tmp) {                                                     \
+            LOG(ERROR, "Missing xenstore node %s/"#param"", libxl_path);   \
+            goto cleanup;                                               \
+        }                                                               \
+        disk->item = tmp;                                               \
+} while (0)
+        XS_READ_COLO(colo-export, colo_export);
+        XS_READ_COLO(active-disk, active_disk);
+        XS_READ_COLO(hidden-disk, hidden_disk);
+#undef XS_READ_COLO
+    } else {
+        libxl_defbool_set(&disk->colo_enable, false);
+    }
+
+    tmp = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/type", libxl_path));
+    if (!tmp) {
+        LOG(ERROR, "Missing xenstore node %s/type", libxl_path);
+        goto cleanup;
+    }
+    libxl_string_to_backend(ctx, tmp, &(disk->backend));
+
+    disk->vdev = xs_read(ctx->xsh, XBT_NULL,
+                         GCSPRINTF("%s/dev", libxl_path), &len);
+    if (!disk->vdev) {
+        LOG(ERROR, "Missing xenstore node %s/dev", libxl_path);
+        goto cleanup;
+    }
+
+    tmp = libxl__xs_read(gc, XBT_NULL, libxl__sprintf
+                         (gc, "%s/removable", libxl_path));
+    if (!tmp) {
+        LOG(ERROR, "Missing xenstore node %s/removable", libxl_path);
+        goto cleanup;
+    }
+    disk->removable = atoi(tmp);
+
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/mode", libxl_path));
+    if (!tmp) {
+        LOG(ERROR, "Missing xenstore node %s/mode", libxl_path);
+        goto cleanup;
+    }
+    if (!strcmp(tmp, "w"))
+        disk->readwrite = 1;
+    else
+        disk->readwrite = 0;
+
+    tmp = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/device-type", libxl_path));
+    if (!tmp) {
+        LOG(ERROR, "Missing xenstore node %s/device-type", libxl_path);
+        goto cleanup;
+    }
+    disk->is_cdrom = !strcmp(tmp, "cdrom");
+
+    disk->format = LIBXL_DISK_FORMAT_UNKNOWN;
+
+    return 0;
+cleanup:
+    rc = ERROR_FAIL;
+ out:
+    libxl_device_disk_dispose(disk);
+    return rc;
+}
+
+int libxl_vdev_to_device_disk(libxl_ctx *ctx, uint32_t domid,
+                              const char *vdev, libxl_device_disk *disk)
+{
+    GC_INIT(ctx);
+    char *dom_xl_path, *libxl_path;
+    int devid = libxl__device_disk_dev_number(vdev, NULL, NULL);
+    int rc = ERROR_FAIL;
+
+    if (devid < 0)
+        return ERROR_INVAL;
+
+    libxl_device_disk_init(disk);
+
+    dom_xl_path = libxl__xs_libxl_path(gc, domid);
+    if (!dom_xl_path) {
+        goto out;
+    }
+    libxl_path = GCSPRINTF("%s/device/vbd/%d", dom_xl_path, devid);
+
+    rc = libxl__device_disk_from_xenstore(gc, libxl_path, disk);
+out:
+    GC_FREE;
+    return rc;
+}
+
+static int libxl__append_disk_list(libxl__gc *gc,
+                                           uint32_t domid,
+                                           libxl_device_disk **disks,
+                                           int *ndisks)
+{
+    char *libxl_dir_path = NULL;
+    char **dir = NULL;
+    unsigned int n = 0;
+    libxl_device_disk *pdisk = NULL, *pdisk_end = NULL;
+    int rc=0;
+    int initial_disks = *ndisks;
+
+    libxl_dir_path = GCSPRINTF("%s/device/vbd",
+                        libxl__xs_libxl_path(gc, domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
+    if (dir && n) {
+        libxl_device_disk *tmp;
+        tmp = realloc(*disks, sizeof (libxl_device_disk) * (*ndisks + n));
+        if (tmp == NULL)
+            return ERROR_NOMEM;
+        *disks = tmp;
+        pdisk = *disks + initial_disks;
+        pdisk_end = *disks + initial_disks + n;
+        for (; pdisk < pdisk_end; pdisk++, dir++) {
+            const char *p;
+            p = GCSPRINTF("%s/%s", libxl_dir_path, *dir);
+            if ((rc=libxl__device_disk_from_xenstore(gc, p, pdisk)))
+                goto out;
+            *ndisks += 1;
+        }
+    }
+out:
+    return rc;
+}
+
+libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_disk *disks = NULL;
+    int rc;
+
+    *num = 0;
+
+    rc = libxl__append_disk_list(gc, domid, &disks, num);
+    if (rc) goto out_err;
+
+    GC_FREE;
+    return disks;
+
+out_err:
+    LOG(ERROR, "Unable to list disks");
+    while (disks && *num) {
+        (*num)--;
+        libxl_device_disk_dispose(&disks[*num]);
+    }
+    free(disks);
+    return NULL;
+}
+
+int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_disk *disk, libxl_diskinfo *diskinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *fe_path, *libxl_path;
+    char *val;
+    int rc;
+
+    diskinfo->backend = NULL;
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    diskinfo->devid = libxl__device_disk_dev_number(disk->vdev, NULL, NULL);
+
+    /* tap devices entries in xenstore are written as vbd devices. */
+    fe_path = GCSPRINTF("%s/device/vbd/%d", dompath, diskinfo->devid);
+    libxl_path = GCSPRINTF("%s/device/vbd/%d",
+                           libxl__xs_libxl_path(gc, domid), diskinfo->devid);
+    diskinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+                                GCSPRINTF("%s/backend", libxl_path), NULL);
+    if (!diskinfo->backend) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    rc = libxl__backendpath_parse_domid(gc, diskinfo->backend,
+                                        &diskinfo->backend_id);
+    if (rc) goto out;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
+    diskinfo->state = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/event-channel", fe_path));
+    diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
+    diskinfo->rref = val ? strtoul(val, NULL, 10) : -1;
+    diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
+                                 GCSPRINTF("%s/frontend", libxl_path), NULL);
+    diskinfo->frontend_id = domid;
+
+    GC_FREE;
+    return 0;
+
+ out:
+    free(diskinfo->backend);
+    return rc;
+}
+
+int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk,
+                       const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int num = 0, i;
+    libxl_device_disk *disks = NULL, disk_saved, disk_empty;
+    libxl_domain_config d_config;
+    int rc, dm_ver;
+    libxl__device device;
+    const char *be_path, *libxl_path;
+    char * tmp;
+    libxl__domain_userdata_lock *lock = NULL;
+    xs_transaction_t t = XBT_NULL;
+    flexarray_t *insert = NULL, *empty = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_disk_init(&disk_empty);
+    libxl_device_disk_init(&disk_saved);
+    libxl_device_disk_copy(ctx, &disk_saved, disk);
+
+    disk_empty.format = LIBXL_DISK_FORMAT_EMPTY;
+    disk_empty.vdev = libxl__strdup(NOGC, disk->vdev);
+    disk_empty.pdev_path = libxl__strdup(NOGC, "");
+    disk_empty.is_cdrom = 1;
+    libxl__device_disk_setdefault(gc, &disk_empty, domid);
+
+    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) {
+        LOGD(ERROR, domid, "cdrom-insert requires an HVM domain");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (libxl_get_stubdom_id(ctx, domid) != 0) {
+        LOGD(ERROR, domid, "cdrom-insert doesn't work for stub domains");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    dm_ver = libxl__device_model_version_running(gc, domid);
+    if (dm_ver == -1) {
+        LOGD(ERROR, domid, "Cannot determine device model version");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_NONE) {
+        LOGD(ERROR, domid, "Guests without a device model cannot use cd-insert");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    disks = libxl_device_disk_list(ctx, domid, &num);
+    for (i = 0; i < num; i++) {
+        if (disks[i].is_cdrom && !strcmp(disk->vdev, disks[i].vdev))
+        {
+            /* Found.  Set backend type appropriately. */
+            disk->backend=disks[i].backend;
+            break;
+        }
+    }
+    if (i == num) {
+        LOGD(ERROR, domid, "Virtual device not found");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__device_disk_setdefault(gc, disk, domid);
+    if (rc) goto out;
+
+    if (!disk->pdev_path) {
+        disk->pdev_path = libxl__strdup(NOGC, "");
+        disk->format = LIBXL_DISK_FORMAT_EMPTY;
+    }
+
+    rc = libxl__device_from_disk(gc, domid, disk, &device);
+    if (rc) goto out;
+
+    be_path = libxl__device_backend_path(gc, &device);
+    libxl_path = libxl__device_libxl_path(gc, &device);
+
+    insert = flexarray_make(gc, 4, 1);
+
+    flexarray_append_pair(insert, "type",
+                          libxl__device_disk_string_of_backend(disk->backend));
+    if (disk->format != LIBXL_DISK_FORMAT_EMPTY)
+        flexarray_append_pair(insert, "params",
+                        GCSPRINTF("%s:%s",
+                            libxl__device_disk_string_of_format(disk->format),
+                            disk->pdev_path));
+    else
+        flexarray_append_pair(insert, "params", "");
+
+    empty = flexarray_make(gc, 4, 1);
+    flexarray_append_pair(empty, "type",
+                          libxl__device_disk_string_of_backend(disk->backend));
+    flexarray_append_pair(empty, "params", "");
+
+    /* Note: CTX lock is already held at this point so lock hierarchy
+     * is maintained.
+     */
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {
+        rc = ERROR_LOCK_FAIL;
+        goto out;
+    }
+
+    /* We need to eject the original image first. This is implemented
+     * by inserting empty media. JSON is not updated.
+     */
+    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
+        rc = libxl__qmp_insert_cdrom(gc, domid, &disk_empty);
+        if (rc) goto out;
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+        /* Sanity check: make sure the device exists before writing here */
+        tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/frontend", libxl_path));
+        if (!tmp)
+        {
+            LOGD(ERROR, domid, "Internal error: %s does not exist",
+                 GCSPRINTF("%s/frontend", libxl_path));
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        char **kvs = libxl__xs_kvs_of_flexarray(gc, empty);
+
+        rc = libxl__xs_writev(gc, t, be_path, kvs);
+        if (rc) goto out;
+
+        rc = libxl__xs_writev(gc, t, libxl_path, kvs);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    DEVICE_ADD(disk, disks, domid, &disk_saved, COMPARE_DISK, &d_config);
+
+    rc = libxl__dm_check_start(gc, &d_config, domid);
+    if (rc) goto out;
+
+    if (dm_ver == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
+        rc = libxl__qmp_insert_cdrom(gc, domid, disk);
+        if (rc) goto out;
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+        /* Sanity check: make sure the device exists before writing here */
+        tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/frontend", libxl_path));
+        if (!tmp)
+        {
+            LOGD(ERROR, domid, "Internal error: %s does not exist",
+                 GCSPRINTF("%s/frontend", libxl_path));
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        rc = libxl__set_domain_configuration(gc, domid, &d_config);
+        if (rc) goto out;
+
+        char **kvs = libxl__xs_kvs_of_flexarray(gc, insert);
+
+        rc = libxl__xs_writev(gc, t, be_path, kvs);
+        if (rc) goto out;
+
+        rc = libxl__xs_writev(gc, t, libxl_path, kvs);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    /* success, no actual async */
+    libxl__ao_complete(egc, ao, 0);
+
+    rc = 0;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    for (i = 0; i < num; i++)
+        libxl_device_disk_dispose(&disks[i]);
+    free(disks);
+    libxl_device_disk_dispose(&disk_empty);
+    libxl_device_disk_dispose(&disk_saved);
+    libxl_domain_config_dispose(&d_config);
+
+    if (lock) libxl__unlock_domain_userdata(lock);
+
+    if (rc) return AO_CREATE_FAIL(rc);
+    return AO_INPROGRESS;
+}
+
+/* libxl__alloc_vdev only works on the local domain, that is the domain
+ * where the toolstack is running */
+static char * libxl__alloc_vdev(libxl__gc *gc, void *get_vdev_user,
+        xs_transaction_t t)
+{
+    const char *blkdev_start = (const char *) get_vdev_user;
+    int devid = 0, disk = 0, part = 0;
+    char *libxl_dom_path = libxl__xs_libxl_path(gc, LIBXL_TOOLSTACK_DOMID);
+
+    libxl__device_disk_dev_number(blkdev_start, &disk, &part);
+    if (part != 0) {
+        LOG(ERROR, "blkdev_start is invalid");
+        return NULL;
+    }
+
+    do {
+        devid = libxl__device_disk_dev_number(GCSPRINTF("d%dp0", disk),
+                NULL, NULL);
+        if (devid < 0)
+            return NULL;
+        if (libxl__xs_read(gc, t,
+                    GCSPRINTF("%s/device/vbd/%d/backend",
+                        libxl_dom_path, devid)) == NULL) {
+            if (errno == ENOENT)
+                return libxl__devid_to_vdev(gc, devid);
+            else
+                return NULL;
+        }
+        disk++;
+    } while (1);
+    return NULL;
+}
+
+/* Callbacks */
+
+char *libxl__device_disk_find_local_path(libxl__gc *gc,
+                                          libxl_domid guest_domid,
+                                          const libxl_device_disk *disk,
+                                          bool qdisk_direct)
+{
+    char *path = NULL;
+
+    /* No local paths for driver domains */
+    if (disk->backend_domname != NULL) {
+        LOG(DEBUG, "Non-local backend, can't access locally.\n");
+        goto out;
+    }
+
+    /*
+     * If this is in raw format, and we're not using a script or a
+     * driver domain, we can access the target path directly.
+     */
+    if (disk->format == LIBXL_DISK_FORMAT_RAW
+        && disk->script == NULL) {
+        path = libxl__strdup(gc, disk->pdev_path);
+        LOG(DEBUG, "Directly accessing local RAW disk %s", path);
+        goto out;
+    }
+
+    /*
+     * If we're being called for a qemu path, we can pass the target
+     * string directly as well
+     */
+    if (qdisk_direct && disk->backend == LIBXL_DISK_BACKEND_QDISK) {
+        path = libxl__strdup(gc, disk->pdev_path);
+        LOG(DEBUG, "Directly accessing local QDISK target %s", path);
+        goto out;
+    }
+
+    /*
+     * If the format isn't raw and / or we're using a script, then see
+     * if the script has written a path to the "cooked" node
+     */
+    if (disk->script && guest_domid != INVALID_DOMID) {
+        libxl__device device;
+        char *be_path, *pdpath;
+        int rc;
+
+        LOGD(DEBUG, guest_domid,
+             "Run from a script; checking for physical-device-path (vdev %s)",
+             disk->vdev);
+
+        rc = libxl__device_from_disk(gc, guest_domid, disk, &device);
+        if (rc < 0)
+            goto out;
+
+        be_path = libxl__device_backend_path(gc, &device);
+
+        pdpath = libxl__sprintf(gc, "%s/physical-device-path", be_path);
+
+        LOGD(DEBUG, guest_domid, "Attempting to read node %s", pdpath);
+        path = libxl__xs_read(gc, XBT_NULL, pdpath);
+
+        if (path)
+            LOGD(DEBUG, guest_domid, "Accessing cooked block device %s", path);
+        else
+            LOGD(DEBUG, guest_domid, "No physical-device-path, can't access locally.");
+
+        goto out;
+    }
+
+ out:
+    return path;
+}
+
+static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev);
+
+void libxl__device_disk_local_initiate_attach(libxl__egc *egc,
+                                     libxl__disk_local_state *dls)
+{
+    STATE_AO_GC(dls->ao);
+    int rc;
+    const libxl_device_disk *in_disk = dls->in_disk;
+    libxl_device_disk *disk = &dls->disk;
+    const char *blkdev_start = dls->blkdev_start;
+
+    assert(in_disk->pdev_path);
+
+    disk->vdev = NULL;
+
+    if (dls->diskpath)
+        LOG(DEBUG, "Strange, dls->diskpath already set: %s", dls->diskpath);
+
+    LOG(DEBUG, "Trying to find local path");
+
+    dls->diskpath = libxl__device_disk_find_local_path(gc, INVALID_DOMID,
+                                                       in_disk, false);
+    if (dls->diskpath) {
+        LOG(DEBUG, "Local path found, executing callback.");
+        dls->callback(egc, dls, 0);
+    } else {
+        LOG(DEBUG, "Local path not found, initiating attach.");
+
+        memcpy(disk, in_disk, sizeof(libxl_device_disk));
+        disk->pdev_path = libxl__strdup(gc, in_disk->pdev_path);
+        if (in_disk->script != NULL)
+            disk->script = libxl__strdup(gc, in_disk->script);
+        disk->vdev = NULL;
+
+        rc = libxl__device_disk_setdefault(gc, disk, LIBXL_TOOLSTACK_DOMID);
+        if (rc) goto out;
+
+        libxl__prepare_ao_device(ao, &dls->aodev);
+        dls->aodev.callback = local_device_attach_cb;
+        device_disk_add(egc, LIBXL_TOOLSTACK_DOMID, disk, &dls->aodev,
+                        libxl__alloc_vdev, (void *) blkdev_start);
+    }
+
+    return;
+
+ out:
+    assert(rc);
+    dls->rc = rc;
+    libxl__device_disk_local_initiate_detach(egc, dls);
+    dls->callback(egc, dls, rc);
+}
+
+static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
+    char *be_path = NULL;
+    int rc;
+    libxl__device device;
+    libxl_device_disk *disk = &dls->disk;
+
+    rc = aodev->rc;
+    if (rc) {
+        LOGE(ERROR, "unable locally attach device: %s", disk->pdev_path);
+        goto out;
+    }
+
+    rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID, disk, &device);
+    if (rc < 0)
+        goto out;
+    be_path = libxl__device_backend_path(gc, &device);
+    rc = libxl__wait_for_backend(gc, be_path, GCSPRINTF("%d", XenbusStateConnected));
+    if (rc < 0)
+        goto out;
+
+    dls->diskpath = GCSPRINTF("/dev/%s",
+                              libxl__devid_to_localdev(gc, device.devid));
+    LOG(DEBUG, "locally attached disk %s", dls->diskpath);
+
+    dls->callback(egc, dls, 0);
+    return;
+
+ out:
+    assert(rc);
+    dls->rc = rc;
+    libxl__device_disk_local_initiate_detach(egc, dls);
+    return;
+}
+
+/* Callbacks for local detach */
+
+static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev);
+
+void libxl__device_disk_local_initiate_detach(libxl__egc *egc,
+                                     libxl__disk_local_state *dls)
+{
+    STATE_AO_GC(dls->ao);
+    int rc = 0;
+    libxl_device_disk *disk = &dls->disk;
+    libxl__device *device;
+    libxl__ao_device *aodev = &dls->aodev;
+    libxl__prepare_ao_device(ao, aodev);
+
+    if (!dls->diskpath) goto out;
+
+    if (disk->vdev != NULL) {
+        GCNEW(device);
+        rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID,
+                                     disk, device);
+        if (rc != 0) goto out;
+
+        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+        aodev->dev = device;
+        aodev->callback = local_device_detach_cb;
+        aodev->force = 0;
+        libxl__initiate_device_generic_remove(egc, aodev);
+        return;
+    }
+
+out:
+    aodev->rc = rc;
+    local_device_detach_cb(egc, aodev);
+    return;
+}
+
+static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
+    int rc;
+
+    if (aodev->rc) {
+        LOGED(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
+                     libxl__device_action_to_string(aodev->action),
+                     libxl__device_kind_to_string(aodev->dev->kind),
+                     aodev->dev->devid);
+        goto out;
+    }
+
+out:
+    /*
+     * If there was an error in dls->rc, it means we have been called from
+     * a failed execution of libxl__device_disk_local_initiate_attach,
+     * so return the original error.
+     */
+    rc = dls->rc ? dls->rc : aodev->rc;
+    dls->callback(egc, dls, rc);
+    return;
+}
+
+/* The following functions are defined:
+ * libxl_device_disk_add
+ * libxl__add_disks
+ * libxl_device_disk_remove
+ * libxl_device_disk_destroy
+ */
+LIBXL_DEFINE_DEVICE_ADD(disk)
+LIBXL_DEFINE_DEVICES_ADD(disk)
+LIBXL_DEFINE_DEVICE_REMOVE(disk)
+
+static int libxl_device_disk_compare(libxl_device_disk *d1,
+                                     libxl_device_disk *d2)
+{
+    return COMPARE_DISK(d1, d2);
+}
+
+/* Take care of removable device. We maintain invariant in the
+ * insert / remove operation so that:
+ * 1. if xenstore is "empty" while JSON is not, the result
+ *    is "empty"
+ * 2. if xenstore has a different media than JSON, use the
+ *    one in JSON
+ * 3. if xenstore and JSON have the same media, well, you
+ *    know the answer :-)
+ *
+ * Currently there is only one removable device -- CDROM.
+ * Look for libxl_cdrom_insert for reference.
+ */
+static void libxl_device_disk_merge(libxl_ctx *ctx, void *d1, void *d2)
+{
+    GC_INIT(ctx);
+    libxl_device_disk *src = d1;
+    libxl_device_disk *dst = d2;
+
+    if (src->removable) {
+        if (!src->pdev_path || *src->pdev_path == '\0') {
+            /* 1, no media in drive */
+            free(dst->pdev_path);
+            dst->pdev_path = libxl__strdup(NOGC, "");
+            dst->format = LIBXL_DISK_FORMAT_EMPTY;
+        } else {
+            /* 2 and 3, use JSON, no need to touch anything */
+            ;
+        }
+    }
+}
+
+static int libxl_device_disk_dm_needed(void *e, unsigned domid)
+{
+    libxl_device_disk *elem = e;
+
+    return elem->backend == LIBXL_DISK_BACKEND_QDISK &&
+           elem->backend_domid == domid;
+}
+
+DEFINE_DEVICE_TYPE_STRUCT(disk,
+    .merge       = libxl_device_disk_merge,
+    .dm_needed   = libxl_device_disk_dm_needed,
+    .skip_attach = 1
+);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 5/9] libxl: carve out console specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (3 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 4/9] libxl: carve out disk " Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 6/9] libxl: carve out memory " Juergen Gross
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the console
related functions (including channels, keyboard and frame buffer)
to libxl_console.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile        |   2 +-
 tools/libxl/libxl.c         | 846 -------------------------------------------
 tools/libxl/libxl_console.c | 862 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 863 insertions(+), 847 deletions(-)
 create mode 100644 tools/libxl/libxl_console.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index baf591d..dd7aa41 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -136,7 +136,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_save_callout.o _libxl_save_msgs_callout.o \
 			libxl_qmp.o libxl_event.o libxl_fork.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
-			libxl_vtpm.o libxl_nic.o libxl_disk.o \
+			libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
 			libxl_cpupool.o libxl_sched.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 043c3d6..a0663eb 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1509,239 +1509,6 @@ static void domain_destroy_domid_cb(libxl__egc *egc,
     dis->callback(egc, dis, rc);
 }
 
-static int libxl__console_tty_path(libxl__gc *gc, uint32_t domid, int cons_num,
-                                   libxl_console_type type, char **tty_path)
-{
-    int rc;
-    char *dom_path;
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    switch (type) {
-    case LIBXL_CONSOLE_TYPE_SERIAL:
-        *tty_path = GCSPRINTF("%s/serial/%d/tty", dom_path, cons_num);
-        rc = 0;
-        break;
-    case LIBXL_CONSOLE_TYPE_PV:
-        if (cons_num == 0)
-            *tty_path = GCSPRINTF("%s/console/tty", dom_path);
-        else
-            *tty_path = GCSPRINTF("%s/device/console/%d/tty", dom_path,
-                                  cons_num);
-        rc = 0;
-        break;
-    default:
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-out:
-    return rc;
-}
-
-int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
-                       libxl_console_type type, int notify_fd)
-{
-    GC_INIT(ctx);
-    char *p = GCSPRINTF("%s/xenconsole", libxl__private_bindir_path());
-    char *domid_s = GCSPRINTF("%d", domid);
-    char *cons_num_s = GCSPRINTF("%d", cons_num);
-    char *notify_fd_s;
-    char *cons_type_s;
-
-    switch (type) {
-    case LIBXL_CONSOLE_TYPE_PV:
-        cons_type_s = "pv";
-        break;
-    case LIBXL_CONSOLE_TYPE_SERIAL:
-        cons_type_s = "serial";
-        break;
-    default:
-        goto out;
-    }
-
-    if (notify_fd != -1) {
-        notify_fd_s = GCSPRINTF("%d", notify_fd);
-        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
-              "--start-notify-fd", notify_fd_s, (void *)NULL);
-    } else {
-        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
-              (void *)NULL);
-    }
-
-out:
-    GC_FREE;
-    return ERROR_FAIL;
-}
-
-int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
-                          libxl_console_type type, char **path)
-{
-    GC_INIT(ctx);
-    char *tty_path;
-    char *tty;
-    int rc;
-
-    rc = libxl__console_tty_path(gc, domid, cons_num, type, &tty_path);
-    if (rc) {
-        LOGD(ERROR, domid, "Failed to get tty path\n");
-        goto out;
-    }
-
-    tty = libxl__xs_read(gc, XBT_NULL, tty_path);
-    if (!tty || tty[0] == '\0') {
-       LOGED(ERROR, domid, "Unable to read console tty path `%s'",
-             tty_path);
-       rc = ERROR_FAIL;
-       goto out;
-    }
-
-    *path = libxl__strdup(NOGC, tty);
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-static int libxl__primary_console_find(libxl_ctx *ctx, uint32_t domid_vm,
-                                       uint32_t *domid, int *cons_num,
-                                       libxl_console_type *type)
-{
-    GC_INIT(ctx);
-    uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
-    int rc;
-
-    if (stubdomid) {
-        *domid = stubdomid;
-        *cons_num = STUBDOM_CONSOLE_SERIAL;
-        *type = LIBXL_CONSOLE_TYPE_PV;
-    } else {
-        switch (libxl__domain_type(gc, domid_vm)) {
-        case LIBXL_DOMAIN_TYPE_HVM:
-            *domid = domid_vm;
-            *cons_num = 0;
-            *type = LIBXL_CONSOLE_TYPE_SERIAL;
-            break;
-        case LIBXL_DOMAIN_TYPE_PV:
-            *domid = domid_vm;
-            *cons_num = 0;
-            *type = LIBXL_CONSOLE_TYPE_PV;
-            break;
-        case LIBXL_DOMAIN_TYPE_INVALID:
-            rc = ERROR_INVAL;
-            goto out;
-        default: abort();
-        }
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm, int notify_fd)
-{
-    uint32_t domid;
-    int cons_num;
-    libxl_console_type type;
-    int rc;
-
-    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
-    if ( rc ) return rc;
-    return libxl_console_exec(ctx, domid, cons_num, type, notify_fd);
-}
-
-int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
-                                  char **path)
-{
-    uint32_t domid;
-    int cons_num;
-    libxl_console_type type;
-    int rc;
-
-    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
-    if ( rc ) return rc;
-    return libxl_console_get_tty(ctx, domid, cons_num, type, path);
-}
-
-int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
-{
-    GC_INIT(ctx);
-    const char *vnc_port;
-    const char *vnc_listen = NULL, *vnc_pass = NULL;
-    int port = 0, autopass_fd = -1;
-    char *vnc_bin, *args[] = {
-        "vncviewer",
-        NULL, /* hostname:display */
-        NULL, /* -autopass */
-        NULL,
-    };
-
-    vnc_port = libxl__xs_read(gc, XBT_NULL,
-                            GCSPRINTF(
-                            "/local/domain/%d/console/vnc-port", domid));
-    if (!vnc_port) {
-        LOGD(ERROR, domid, "Cannot get vnc-port");
-        goto x_fail;
-    }
-
-    port = atoi(vnc_port) - 5900;
-
-    vnc_listen = libxl__xs_read(gc, XBT_NULL,
-                                GCSPRINTF("/local/domain/%d/console/vnc-listen",
-                                          domid));
-
-    if ( autopass )
-        vnc_pass = libxl__xs_read(gc, XBT_NULL,
-                                  GCSPRINTF("/local/domain/%d/console/vnc-pass",
-					    domid));
-
-    if ( NULL == vnc_listen )
-        vnc_listen = "localhost";
-
-    if ( (vnc_bin = getenv("VNCVIEWER")) )
-        args[0] = vnc_bin;
-
-    args[1] = GCSPRINTF("%s:%d", vnc_listen, port);
-
-    if ( vnc_pass ) {
-        char tmpname[] = "/tmp/vncautopass.XXXXXX";
-        autopass_fd = mkstemp(tmpname);
-        if ( autopass_fd < 0 ) {
-            LOGED(ERROR, domid, "mkstemp %s failed", tmpname);
-            goto x_fail;
-        }
-
-        if ( unlink(tmpname) ) {
-            /* should never happen */
-            LOGED(ERROR, domid, "unlink %s failed", tmpname);
-            goto x_fail;
-        }
-
-        if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
-                                    tmpname, "vnc password") )
-            goto x_fail;
-
-        if ( lseek(autopass_fd, SEEK_SET, 0) ) {
-            LOGED(ERROR, domid, "rewind %s (autopass) failed", tmpname);
-            goto x_fail;
-        }
-
-        args[2] = "-autopass";
-    }
-
-    libxl__exec(gc, autopass_fd, -1, -1, args[0], args, NULL);
-
- x_fail:
-    GC_FREE;
-    return ERROR_FAIL;
-}
-
 int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
 {
     int rc;
@@ -1815,557 +1582,6 @@ int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
 }
 
 /******************************************************************************/
-int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
-                              libxl__device_console *console,
-                              libxl__domain_build_state *state,
-                              libxl__device *device)
-{
-    flexarray_t *front, *ro_front;
-    flexarray_t *back;
-    int rc;
-
-    if (console->devid && state) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    if (!console->devid && (console->name || console->path)) {
-        LOGD(ERROR, domid, "Primary console has invalid configuration");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    front = flexarray_make(gc, 16, 1);
-    ro_front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    device->backend_devid = console->devid;
-    device->backend_domid = console->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
-    device->devid = console->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_CONSOLE;
-
-    flexarray_append(back, "frontend-id");
-    flexarray_append(back, GCSPRINTF("%d", domid));
-    flexarray_append(back, "online");
-    flexarray_append(back, "1");
-    flexarray_append(back, "state");
-    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
-    flexarray_append(back, "protocol");
-    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
-
-    if (console->name) {
-        flexarray_append(ro_front, "name");
-        flexarray_append(ro_front, console->name);
-        flexarray_append(back, "name");
-        flexarray_append(back, console->name);
-    }
-    if (console->connection) {
-        flexarray_append(back, "connection");
-        flexarray_append(back, console->connection);
-    }
-    if (console->path) {
-        flexarray_append(back, "path");
-        flexarray_append(back, console->path);
-    }
-
-    flexarray_append(front, "backend-id");
-    flexarray_append(front, GCSPRINTF("%d", console->backend_domid));
-
-    flexarray_append(ro_front, "limit");
-    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
-    flexarray_append(ro_front, "type");
-    if (console->consback == LIBXL__CONSOLE_BACKEND_XENCONSOLED)
-        flexarray_append(ro_front, "xenconsoled");
-    else
-        flexarray_append(ro_front, "ioemu");
-    flexarray_append(ro_front, "output");
-    flexarray_append(ro_front, console->output);
-    flexarray_append(ro_front, "tty");
-    flexarray_append(ro_front, "");
-
-    if (state) {
-        flexarray_append(ro_front, "port");
-        flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
-        flexarray_append(ro_front, "ring-ref");
-        flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
-    } else {
-        flexarray_append(front, "state");
-        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
-        flexarray_append(front, "protocol");
-        flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
-    }
-    libxl__device_generic_add(gc, XBT_NULL, device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              libxl__xs_kvs_of_flexarray(gc, ro_front));
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__init_console_from_channel(libxl__gc *gc,
-                                     libxl__device_console *console,
-                                     int dev_num,
-                                     libxl_device_channel *channel)
-{
-    int rc;
-
-    libxl__device_console_init(console);
-
-    /* Perform validation first, allocate second. */
-
-    if (!channel->name) {
-        LOG(ERROR, "channel %d has no name", channel->devid);
-        return ERROR_INVAL;
-    }
-
-    if (channel->backend_domname) {
-        rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
-                                             &channel->backend_domid);
-        if (rc < 0) return rc;
-    }
-
-    /* The xenstore 'output' node tells the backend what to connect the console
-       to. If the channel has "connection = pty" then the "output" node will be
-       set to "pty". If the channel has "connection = socket" then the "output"
-       node will be set to "chardev:libxl-channel%d". This tells the qemu
-       backend to proxy data between the console ring and the character device
-       with id "libxl-channel%d". These character devices are currently defined
-       on the qemu command-line via "-chardev" options in libxl_dm.c */
-
-    switch (channel->connection) {
-        case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
-            LOG(ERROR, "channel %d has no defined connection; "
-                "to where should it be connected?", channel->devid);
-            return ERROR_INVAL;
-        case LIBXL_CHANNEL_CONNECTION_PTY:
-            console->connection = libxl__strdup(NOGC, "pty");
-            console->output = libxl__sprintf(NOGC, "pty");
-            break;
-        case LIBXL_CHANNEL_CONNECTION_SOCKET:
-            if (!channel->u.socket.path) {
-                LOG(ERROR, "channel %d has no path", channel->devid);
-                return ERROR_INVAL;
-            }
-            console->connection = libxl__strdup(NOGC, "socket");
-            console->path = libxl__strdup(NOGC, channel->u.socket.path);
-            console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
-                                             channel->devid);
-            break;
-        default:
-            /* We've forgotten to add the clause */
-            LOG(ERROR, "%s: missing implementation for channel connection %d",
-                __func__, channel->connection);
-            abort();
-    }
-
-    console->devid = dev_num;
-    console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
-    console->backend_domid = channel->backend_domid;
-    console->name = libxl__strdup(NOGC, channel->name);
-
-    return 0;
-}
-
-static int libxl__device_channel_from_xenstore(libxl__gc *gc,
-                                            const char *libxl_path,
-                                            libxl_device_channel *channel)
-{
-    const char *tmp;
-    int rc;
-
-    libxl_device_channel_init(channel);
-
-    rc = libxl__xs_read_checked(NOGC, XBT_NULL,
-                                GCSPRINTF("%s/name", libxl_path),
-                                (const char **)(&channel->name));
-    if (rc) goto out;
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                GCSPRINTF("%s/connection", libxl_path), &tmp);
-    if (rc) goto out;
-    if (!strcmp(tmp, "pty")) {
-        channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
-    } else if (!strcmp(tmp, "socket")) {
-        channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
-        rc = libxl__xs_read_checked(NOGC, XBT_NULL,
-                                    GCSPRINTF("%s/path", libxl_path),
-                                    (const char **)(&channel->u.socket.path));
-        if (rc) goto out;
-    } else {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    rc = 0;
- out:
-    return rc;
-}
-
-static int libxl__append_channel_list(libxl__gc *gc,
-                                              uint32_t domid,
-                                              libxl_device_channel **channels,
-                                              int *nchannels)
-{
-    char *libxl_dir_path = NULL;
-    char **dir = NULL;
-    unsigned int n = 0, devid = 0;
-    libxl_device_channel *next = NULL;
-    int rc = 0, i;
-
-    libxl_dir_path = GCSPRINTF("%s/device/console",
-                               libxl__xs_libxl_path(gc, domid));
-    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
-    if (!dir || !n)
-      goto out;
-
-    for (i = 0; i < n; i++) {
-        const char *libxl_path, *name;
-        libxl_device_channel *tmp;
-
-        libxl_path = GCSPRINTF("%s/%s", libxl_dir_path, dir[i]);
-        name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", libxl_path));
-        /* 'channels' are consoles with names, so ignore all consoles
-           without names */
-        if (!name) continue;
-        tmp = realloc(*channels,
-                      sizeof(libxl_device_channel) * (*nchannels + devid + 1));
-        if (!tmp) {
-          rc = ERROR_NOMEM;
-          goto out;
-        }
-        *channels = tmp;
-        next = *channels + *nchannels + devid;
-        rc = libxl__device_channel_from_xenstore(gc, libxl_path, next);
-        if (rc) goto out;
-        next->devid = devid;
-        devid++;
-    }
-    *nchannels += devid;
-    return 0;
-
- out:
-    return rc;
-}
-
-libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
-                                                uint32_t domid,
-                                                int *num)
-{
-    GC_INIT(ctx);
-    libxl_device_channel *channels = NULL;
-    int rc;
-
-    *num = 0;
-
-    rc = libxl__append_channel_list(gc, domid, &channels, num);
-    if (rc) goto out_err;
-
-    GC_FREE;
-    return channels;
-
-out_err:
-    LOGD(ERROR, domid, "Unable to list channels");
-    while (*num) {
-        (*num)--;
-        libxl_device_channel_dispose(&channels[*num]);
-    }
-    free(channels);
-    return NULL;
-}
-
-int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
-                                 libxl_device_channel *channel,
-                                 libxl_channelinfo *channelinfo)
-{
-    GC_INIT(ctx);
-    char *dompath, *fe_path, *libxl_path;
-    char *val;
-    int rc;
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    channelinfo->devid = channel->devid;
-
-    fe_path = GCSPRINTF("%s/device/console/%d", dompath,
-                        channelinfo->devid + 1);
-    libxl_path = GCSPRINTF("%s/device/console/%d",
-                           libxl__xs_libxl_path(gc, domid),
-                           channelinfo->devid + 1);
-    channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
-                                   GCSPRINTF("%s/backend", libxl_path), NULL);
-    if (!channelinfo->backend) {
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    rc = libxl__backendpath_parse_domid(gc, channelinfo->backend,
-                                        &channelinfo->backend_id);
-    if (rc) goto out;
-
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
-    channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
-    channelinfo->frontend = libxl__strdup(NOGC, fe_path);
-    channelinfo->frontend_id = domid;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
-    channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
-    channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
-
-    channelinfo->connection = channel->connection;
-    switch (channel->connection) {
-         case LIBXL_CHANNEL_CONNECTION_PTY:
-             val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
-             /*
-              * It is obviously very wrong for this value to be in the
-              * frontend.  But in XSA-175 we don't want to re-engineer
-              * this because other xenconsole code elsewhere (some
-              * even out of tree, perhaps) expects this node to be
-              * here.
-              *
-              * FE/pty is readonly for the guest.  It always exists if
-              * FE does because libxl__device_console_add
-              * unconditionally creates it and nothing deletes it.
-              *
-              * The guest can delete the whole FE (which it has write
-              * privilege on) but the containing directories
-              * /local/GUEST[/device[/console]] are also RO for the
-              * guest.  So if the guest deletes FE it cannot recreate
-              * it.
-              *
-              * Therefore the guest cannot cause FE/pty to contain bad
-              * data, although it can cause it to not exist.
-              */
-             if (!val) val = "/NO-SUCH-PATH";
-             channelinfo->u.pty.path = strdup(val);
-             break;
-         default:
-             break;
-    }
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb)
-{
-    int rc;
-    rc = libxl__resolve_domid(gc, vkb->backend_domname, &vkb->backend_domid);
-    return rc;
-}
-
-static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid,
-                                  libxl_device_vkb *vkb,
-                                  libxl__device *device)
-{
-    device->backend_devid = vkb->devid;
-    device->backend_domid = vkb->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_VKBD;
-    device->devid = vkb->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_VKBD;
-
-    return 0;
-}
-
-int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    rc = libxl__device_vkb_add(gc, domid, vkb);
-    if (rc) {
-        LOGD(ERROR, domid, "Unable to add vkb device");
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
-                          libxl_device_vkb *vkb)
-{
-    flexarray_t *front;
-    flexarray_t *back;
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_vkb_setdefault(gc, vkb);
-    if (rc) goto out;
-
-    front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    if (vkb->devid == -1) {
-        if ((vkb->devid = libxl__device_nextid(gc, domid, "vkb")) < 0) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
-    if (rc != 0) goto out;
-
-    flexarray_append(back, "frontend-id");
-    flexarray_append(back, GCSPRINTF("%d", domid));
-    flexarray_append(back, "online");
-    flexarray_append(back, "1");
-    flexarray_append(back, "state");
-    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
-
-    flexarray_append(front, "backend-id");
-    flexarray_append(front, GCSPRINTF("%d", vkb->backend_domid));
-    flexarray_append(front, "state");
-    flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
-
-    libxl__device_generic_add(gc, XBT_NULL, &device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              NULL);
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb)
-{
-    int rc;
-
-    libxl_defbool_setdefault(&vfb->vnc.enable, true);
-    if (libxl_defbool_val(vfb->vnc.enable)) {
-        if (!vfb->vnc.listen) {
-            vfb->vnc.listen = strdup("127.0.0.1");
-            if (!vfb->vnc.listen) return ERROR_NOMEM;
-        }
-
-        libxl_defbool_setdefault(&vfb->vnc.findunused, true);
-    } else {
-        libxl_defbool_setdefault(&vfb->vnc.findunused, false);
-    }
-
-    libxl_defbool_setdefault(&vfb->sdl.enable, false);
-    libxl_defbool_setdefault(&vfb->sdl.opengl, false);
-
-    rc = libxl__resolve_domid(gc, vfb->backend_domname, &vfb->backend_domid);
-    return rc;
-}
-
-static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid,
-                                  libxl_device_vfb *vfb,
-                                  libxl__device *device)
-{
-    device->backend_devid = vfb->devid;
-    device->backend_domid = vfb->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_VFB;
-    device->devid = vfb->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_VFB;
-    return 0;
-}
-
-int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    rc = libxl__device_vfb_add(gc, domid, vfb);
-    if (rc) {
-        LOGD(ERROR, domid, "Unable to add vfb device");
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-int libxl__device_vfb_add(libxl__gc *gc, uint32_t domid, libxl_device_vfb *vfb)
-{
-    flexarray_t *front;
-    flexarray_t *back;
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_vfb_setdefault(gc, vfb);
-    if (rc) goto out;
-
-    front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    if (vfb->devid == -1) {
-        if ((vfb->devid = libxl__device_nextid(gc, domid, "vfb")) < 0) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
-    if (rc != 0) goto out;
-
-    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
-    flexarray_append_pair(back, "online", "1");
-    flexarray_append_pair(back, "state", GCSPRINTF("%d", XenbusStateInitialising));
-    flexarray_append_pair(back, "vnc",
-                          libxl_defbool_val(vfb->vnc.enable) ? "1" : "0");
-    flexarray_append_pair(back, "vnclisten", vfb->vnc.listen);
-    flexarray_append_pair(back, "vncpasswd", vfb->vnc.passwd);
-    flexarray_append_pair(back, "vncdisplay",
-                          GCSPRINTF("%d", vfb->vnc.display));
-    flexarray_append_pair(back, "vncunused",
-                          libxl_defbool_val(vfb->vnc.findunused) ? "1" : "0");
-    flexarray_append_pair(back, "sdl",
-                          libxl_defbool_val(vfb->sdl.enable) ? "1" : "0");
-    flexarray_append_pair(back, "opengl",
-                          libxl_defbool_val(vfb->sdl.opengl) ? "1" : "0");
-    if (vfb->sdl.xauthority) {
-        flexarray_append_pair(back, "xauthority", vfb->sdl.xauthority);
-    }
-    if (vfb->sdl.display) {
-        flexarray_append_pair(back, "display", vfb->sdl.display);
-    }
-
-    flexarray_append_pair(front, "backend-id",
-                          GCSPRINTF("%d", vfb->backend_domid));
-    flexarray_append_pair(front, "state", GCSPRINTF("%d", XenbusStateInitialising));
-
-    libxl__device_generic_add(gc, XBT_NULL, &device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              NULL);
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-/* The following functions are defined:
- * libxl_device_vkb_remove
- * libxl_device_vkb_destroy
- * libxl_device_vfb_remove
- * libxl_device_vfb_destroy
- */
-
-/* channel/console hotunplug is not implemented. There are 2 possibilities:
- * 1. add support for secondary consoles to xenconsoled
- * 2. dynamically add/remove qemu chardevs via qmp messages. */
-
-/* vkb */
-LIBXL_DEFINE_DEVICE_REMOVE(vkb)
-
-/* vfb */
-LIBXL_DEFINE_DEVICE_REMOVE(vfb)
-
-/******************************************************************************/
 
 /*
  * Data structures used to track devices handled by driver domains
@@ -3863,68 +3079,6 @@ int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
     return 0;
 }
 
-libxl_xen_console_reader *
-    libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
-{
-    GC_INIT(ctx);
-    libxl_xen_console_reader *cr;
-    unsigned int size = 16384;
-
-    cr = libxl__zalloc(NOGC, sizeof(libxl_xen_console_reader));
-    cr->buffer = libxl__zalloc(NOGC, size);
-    cr->size = size;
-    cr->count = size;
-    cr->clear = clear;
-    cr->incremental = 1;
-
-    GC_FREE;
-    return cr;
-}
-
-/* return values:                                          *line_r
- *   1          success, whole line obtained from buffer    non-0
- *   0          no more lines available right now           0
- *   negative   error code ERROR_*                          0
- * On success *line_r is updated to point to a nul-terminated
- * string which is valid until the next call on the same console
- * reader.  The libxl caller may overwrite parts of the string
- * if it wishes. */
-int libxl_xen_console_read_line(libxl_ctx *ctx,
-                                libxl_xen_console_reader *cr,
-                                char **line_r)
-{
-    int ret;
-    GC_INIT(ctx);
-
-    memset(cr->buffer, 0, cr->size);
-    ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
-                             cr->clear, cr->incremental, &cr->index);
-    if (ret < 0) {
-        LOGE(ERROR, "reading console ring buffer");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    if (!ret) {
-        if (cr->count) {
-            *line_r = cr->buffer;
-            ret = 1;
-        } else {
-            *line_r = NULL;
-            ret = 0;
-        }
-    }
-
-    GC_FREE;
-    return ret;
-}
-
-void libxl_xen_console_read_finish(libxl_ctx *ctx,
-                                   libxl_xen_console_reader *cr)
-{
-    free(cr->buffer);
-    free(cr);
-}
-
 uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
 {
     GC_INIT(ctx);
diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
new file mode 100644
index 0000000..cbc70b7
--- /dev/null
+++ b/tools/libxl/libxl_console.c
@@ -0,0 +1,862 @@
+/*
+ * 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"
+
+static int libxl__console_tty_path(libxl__gc *gc, uint32_t domid, int cons_num,
+                                   libxl_console_type type, char **tty_path)
+{
+    int rc;
+    char *dom_path;
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    switch (type) {
+    case LIBXL_CONSOLE_TYPE_SERIAL:
+        *tty_path = GCSPRINTF("%s/serial/%d/tty", dom_path, cons_num);
+        rc = 0;
+        break;
+    case LIBXL_CONSOLE_TYPE_PV:
+        if (cons_num == 0)
+            *tty_path = GCSPRINTF("%s/console/tty", dom_path);
+        else
+            *tty_path = GCSPRINTF("%s/device/console/%d/tty", dom_path,
+                                  cons_num);
+        rc = 0;
+        break;
+    default:
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
+int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
+                       libxl_console_type type, int notify_fd)
+{
+    GC_INIT(ctx);
+    char *p = GCSPRINTF("%s/xenconsole", libxl__private_bindir_path());
+    char *domid_s = GCSPRINTF("%d", domid);
+    char *cons_num_s = GCSPRINTF("%d", cons_num);
+    char *notify_fd_s;
+    char *cons_type_s;
+
+    switch (type) {
+    case LIBXL_CONSOLE_TYPE_PV:
+        cons_type_s = "pv";
+        break;
+    case LIBXL_CONSOLE_TYPE_SERIAL:
+        cons_type_s = "serial";
+        break;
+    default:
+        goto out;
+    }
+
+    if (notify_fd != -1) {
+        notify_fd_s = GCSPRINTF("%d", notify_fd);
+        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
+              "--start-notify-fd", notify_fd_s, (void *)NULL);
+    } else {
+        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
+              (void *)NULL);
+    }
+
+out:
+    GC_FREE;
+    return ERROR_FAIL;
+}
+
+int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
+                          libxl_console_type type, char **path)
+{
+    GC_INIT(ctx);
+    char *tty_path;
+    char *tty;
+    int rc;
+
+    rc = libxl__console_tty_path(gc, domid, cons_num, type, &tty_path);
+    if (rc) {
+        LOGD(ERROR, domid, "Failed to get tty path\n");
+        goto out;
+    }
+
+    tty = libxl__xs_read(gc, XBT_NULL, tty_path);
+    if (!tty || tty[0] == '\0') {
+       LOGED(ERROR, domid, "Unable to read console tty path `%s'",
+             tty_path);
+       rc = ERROR_FAIL;
+       goto out;
+    }
+
+    *path = libxl__strdup(NOGC, tty);
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+static int libxl__primary_console_find(libxl_ctx *ctx, uint32_t domid_vm,
+                                       uint32_t *domid, int *cons_num,
+                                       libxl_console_type *type)
+{
+    GC_INIT(ctx);
+    uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
+    int rc;
+
+    if (stubdomid) {
+        *domid = stubdomid;
+        *cons_num = STUBDOM_CONSOLE_SERIAL;
+        *type = LIBXL_CONSOLE_TYPE_PV;
+    } else {
+        switch (libxl__domain_type(gc, domid_vm)) {
+        case LIBXL_DOMAIN_TYPE_HVM:
+            *domid = domid_vm;
+            *cons_num = 0;
+            *type = LIBXL_CONSOLE_TYPE_SERIAL;
+            break;
+        case LIBXL_DOMAIN_TYPE_PV:
+            *domid = domid_vm;
+            *cons_num = 0;
+            *type = LIBXL_CONSOLE_TYPE_PV;
+            break;
+        case LIBXL_DOMAIN_TYPE_INVALID:
+            rc = ERROR_INVAL;
+            goto out;
+        default: abort();
+        }
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm, int notify_fd)
+{
+    uint32_t domid;
+    int cons_num;
+    libxl_console_type type;
+    int rc;
+
+    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
+    if ( rc ) return rc;
+    return libxl_console_exec(ctx, domid, cons_num, type, notify_fd);
+}
+
+int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
+                                  char **path)
+{
+    uint32_t domid;
+    int cons_num;
+    libxl_console_type type;
+    int rc;
+
+    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
+    if ( rc ) return rc;
+    return libxl_console_get_tty(ctx, domid, cons_num, type, path);
+}
+
+int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
+{
+    GC_INIT(ctx);
+    const char *vnc_port;
+    const char *vnc_listen = NULL, *vnc_pass = NULL;
+    int port = 0, autopass_fd = -1;
+    char *vnc_bin, *args[] = {
+        "vncviewer",
+        NULL, /* hostname:display */
+        NULL, /* -autopass */
+        NULL,
+    };
+
+    vnc_port = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF(
+                            "/local/domain/%d/console/vnc-port", domid));
+    if (!vnc_port) {
+        LOGD(ERROR, domid, "Cannot get vnc-port");
+        goto x_fail;
+    }
+
+    port = atoi(vnc_port) - 5900;
+
+    vnc_listen = libxl__xs_read(gc, XBT_NULL,
+                                GCSPRINTF("/local/domain/%d/console/vnc-listen",
+                                          domid));
+
+    if ( autopass )
+        vnc_pass = libxl__xs_read(gc, XBT_NULL,
+                                  GCSPRINTF("/local/domain/%d/console/vnc-pass",
+                                            domid));
+
+    if ( NULL == vnc_listen )
+        vnc_listen = "localhost";
+
+    if ( (vnc_bin = getenv("VNCVIEWER")) )
+        args[0] = vnc_bin;
+
+    args[1] = GCSPRINTF("%s:%d", vnc_listen, port);
+
+    if ( vnc_pass ) {
+        char tmpname[] = "/tmp/vncautopass.XXXXXX";
+        autopass_fd = mkstemp(tmpname);
+        if ( autopass_fd < 0 ) {
+            LOGED(ERROR, domid, "mkstemp %s failed", tmpname);
+            goto x_fail;
+        }
+
+        if ( unlink(tmpname) ) {
+            /* should never happen */
+            LOGED(ERROR, domid, "unlink %s failed", tmpname);
+            goto x_fail;
+        }
+
+        if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
+                                    tmpname, "vnc password") )
+            goto x_fail;
+
+        if ( lseek(autopass_fd, SEEK_SET, 0) ) {
+            LOGED(ERROR, domid, "rewind %s (autopass) failed", tmpname);
+            goto x_fail;
+        }
+
+        args[2] = "-autopass";
+    }
+
+    libxl__exec(gc, autopass_fd, -1, -1, args[0], args, NULL);
+
+ x_fail:
+    GC_FREE;
+    return ERROR_FAIL;
+}
+
+int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
+                              libxl__device_console *console,
+                              libxl__domain_build_state *state,
+                              libxl__device *device)
+{
+    flexarray_t *front, *ro_front;
+    flexarray_t *back;
+    int rc;
+
+    if (console->devid && state) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    if (!console->devid && (console->name || console->path)) {
+        LOGD(ERROR, domid, "Primary console has invalid configuration");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    front = flexarray_make(gc, 16, 1);
+    ro_front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    device->backend_devid = console->devid;
+    device->backend_domid = console->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
+    device->devid = console->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_CONSOLE;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append(back, "protocol");
+    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
+
+    if (console->name) {
+        flexarray_append(ro_front, "name");
+        flexarray_append(ro_front, console->name);
+        flexarray_append(back, "name");
+        flexarray_append(back, console->name);
+    }
+    if (console->connection) {
+        flexarray_append(back, "connection");
+        flexarray_append(back, console->connection);
+    }
+    if (console->path) {
+        flexarray_append(back, "path");
+        flexarray_append(back, console->path);
+    }
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", console->backend_domid));
+
+    flexarray_append(ro_front, "limit");
+    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
+    flexarray_append(ro_front, "type");
+    if (console->consback == LIBXL__CONSOLE_BACKEND_XENCONSOLED)
+        flexarray_append(ro_front, "xenconsoled");
+    else
+        flexarray_append(ro_front, "ioemu");
+    flexarray_append(ro_front, "output");
+    flexarray_append(ro_front, console->output);
+    flexarray_append(ro_front, "tty");
+    flexarray_append(ro_front, "");
+
+    if (state) {
+        flexarray_append(ro_front, "port");
+        flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
+        flexarray_append(ro_front, "ring-ref");
+        flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
+    } else {
+        flexarray_append(front, "state");
+        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+        flexarray_append(front, "protocol");
+        flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
+    }
+    libxl__device_generic_add(gc, XBT_NULL, device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              libxl__xs_kvs_of_flexarray(gc, ro_front));
+    rc = 0;
+out:
+    return rc;
+}
+
+int libxl__init_console_from_channel(libxl__gc *gc,
+                                     libxl__device_console *console,
+                                     int dev_num,
+                                     libxl_device_channel *channel)
+{
+    int rc;
+
+    libxl__device_console_init(console);
+
+    /* Perform validation first, allocate second. */
+
+    if (!channel->name) {
+        LOG(ERROR, "channel %d has no name", channel->devid);
+        return ERROR_INVAL;
+    }
+
+    if (channel->backend_domname) {
+        rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
+                                             &channel->backend_domid);
+        if (rc < 0) return rc;
+    }
+
+    /* The xenstore 'output' node tells the backend what to connect the console
+       to. If the channel has "connection = pty" then the "output" node will be
+       set to "pty". If the channel has "connection = socket" then the "output"
+       node will be set to "chardev:libxl-channel%d". This tells the qemu
+       backend to proxy data between the console ring and the character device
+       with id "libxl-channel%d". These character devices are currently defined
+       on the qemu command-line via "-chardev" options in libxl_dm.c */
+
+    switch (channel->connection) {
+        case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
+            LOG(ERROR, "channel %d has no defined connection; "
+                "to where should it be connected?", channel->devid);
+            return ERROR_INVAL;
+        case LIBXL_CHANNEL_CONNECTION_PTY:
+            console->connection = libxl__strdup(NOGC, "pty");
+            console->output = libxl__sprintf(NOGC, "pty");
+            break;
+        case LIBXL_CHANNEL_CONNECTION_SOCKET:
+            if (!channel->u.socket.path) {
+                LOG(ERROR, "channel %d has no path", channel->devid);
+                return ERROR_INVAL;
+            }
+            console->connection = libxl__strdup(NOGC, "socket");
+            console->path = libxl__strdup(NOGC, channel->u.socket.path);
+            console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
+                                             channel->devid);
+            break;
+        default:
+            /* We've forgotten to add the clause */
+            LOG(ERROR, "%s: missing implementation for channel connection %d",
+                __func__, channel->connection);
+            abort();
+    }
+
+    console->devid = dev_num;
+    console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
+    console->backend_domid = channel->backend_domid;
+    console->name = libxl__strdup(NOGC, channel->name);
+
+    return 0;
+}
+
+static int libxl__device_channel_from_xenstore(libxl__gc *gc,
+                                            const char *libxl_path,
+                                            libxl_device_channel *channel)
+{
+    const char *tmp;
+    int rc;
+
+    libxl_device_channel_init(channel);
+
+    rc = libxl__xs_read_checked(NOGC, XBT_NULL,
+                                GCSPRINTF("%s/name", libxl_path),
+                                (const char **)(&channel->name));
+    if (rc) goto out;
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/connection", libxl_path), &tmp);
+    if (rc) goto out;
+    if (!strcmp(tmp, "pty")) {
+        channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
+    } else if (!strcmp(tmp, "socket")) {
+        channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
+        rc = libxl__xs_read_checked(NOGC, XBT_NULL,
+                                    GCSPRINTF("%s/path", libxl_path),
+                                    (const char **)(&channel->u.socket.path));
+        if (rc) goto out;
+    } else {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    rc = 0;
+ out:
+    return rc;
+}
+
+static int libxl__append_channel_list(libxl__gc *gc,
+                                              uint32_t domid,
+                                              libxl_device_channel **channels,
+                                              int *nchannels)
+{
+    char *libxl_dir_path = NULL;
+    char **dir = NULL;
+    unsigned int n = 0, devid = 0;
+    libxl_device_channel *next = NULL;
+    int rc = 0, i;
+
+    libxl_dir_path = GCSPRINTF("%s/device/console",
+                               libxl__xs_libxl_path(gc, domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
+    if (!dir || !n)
+      goto out;
+
+    for (i = 0; i < n; i++) {
+        const char *libxl_path, *name;
+        libxl_device_channel *tmp;
+
+        libxl_path = GCSPRINTF("%s/%s", libxl_dir_path, dir[i]);
+        name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", libxl_path));
+        /* 'channels' are consoles with names, so ignore all consoles
+           without names */
+        if (!name) continue;
+        tmp = realloc(*channels,
+                      sizeof(libxl_device_channel) * (*nchannels + devid + 1));
+        if (!tmp) {
+          rc = ERROR_NOMEM;
+          goto out;
+        }
+        *channels = tmp;
+        next = *channels + *nchannels + devid;
+        rc = libxl__device_channel_from_xenstore(gc, libxl_path, next);
+        if (rc) goto out;
+        next->devid = devid;
+        devid++;
+    }
+    *nchannels += devid;
+    return 0;
+
+ out:
+    return rc;
+}
+
+libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
+                                                uint32_t domid,
+                                                int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_channel *channels = NULL;
+    int rc;
+
+    *num = 0;
+
+    rc = libxl__append_channel_list(gc, domid, &channels, num);
+    if (rc) goto out_err;
+
+    GC_FREE;
+    return channels;
+
+out_err:
+    LOGD(ERROR, domid, "Unable to list channels");
+    while (*num) {
+        (*num)--;
+        libxl_device_channel_dispose(&channels[*num]);
+    }
+    free(channels);
+    return NULL;
+}
+
+int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_channel *channel,
+                                 libxl_channelinfo *channelinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *fe_path, *libxl_path;
+    char *val;
+    int rc;
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    channelinfo->devid = channel->devid;
+
+    fe_path = GCSPRINTF("%s/device/console/%d", dompath,
+                        channelinfo->devid + 1);
+    libxl_path = GCSPRINTF("%s/device/console/%d",
+                           libxl__xs_libxl_path(gc, domid),
+                           channelinfo->devid + 1);
+    channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+                                   GCSPRINTF("%s/backend", libxl_path), NULL);
+    if (!channelinfo->backend) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    rc = libxl__backendpath_parse_domid(gc, channelinfo->backend,
+                                        &channelinfo->backend_id);
+    if (rc) goto out;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
+    channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
+    channelinfo->frontend = libxl__strdup(NOGC, fe_path);
+    channelinfo->frontend_id = domid;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
+    channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
+    channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+
+    channelinfo->connection = channel->connection;
+    switch (channel->connection) {
+         case LIBXL_CHANNEL_CONNECTION_PTY:
+             val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
+             /*
+              * It is obviously very wrong for this value to be in the
+              * frontend.  But in XSA-175 we don't want to re-engineer
+              * this because other xenconsole code elsewhere (some
+              * even out of tree, perhaps) expects this node to be
+              * here.
+              *
+              * FE/pty is readonly for the guest.  It always exists if
+              * FE does because libxl__device_console_add
+              * unconditionally creates it and nothing deletes it.
+              *
+              * The guest can delete the whole FE (which it has write
+              * privilege on) but the containing directories
+              * /local/GUEST[/device[/console]] are also RO for the
+              * guest.  So if the guest deletes FE it cannot recreate
+              * it.
+              *
+              * Therefore the guest cannot cause FE/pty to contain bad
+              * data, although it can cause it to not exist.
+              */
+             if (!val) val = "/NO-SUCH-PATH";
+             channelinfo->u.pty.path = strdup(val);
+             break;
+         default:
+             break;
+    }
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb)
+{
+    int rc;
+    rc = libxl__resolve_domid(gc, vkb->backend_domname, &vkb->backend_domid);
+    return rc;
+}
+
+static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid,
+                                  libxl_device_vkb *vkb,
+                                  libxl__device *device)
+{
+    device->backend_devid = vkb->devid;
+    device->backend_domid = vkb->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_VKBD;
+    device->devid = vkb->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_VKBD;
+
+    return 0;
+}
+
+int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_vkb_add(gc, domid, vkb);
+    if (rc) {
+        LOGD(ERROR, domid, "Unable to add vkb device");
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
+                          libxl_device_vkb *vkb)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device device;
+    int rc;
+
+    rc = libxl__device_vkb_setdefault(gc, vkb);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    if (vkb->devid == -1) {
+        if ((vkb->devid = libxl__device_nextid(gc, domid, "vkb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
+    if (rc != 0) goto out;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", vkb->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+
+    libxl__device_generic_add(gc, XBT_NULL, &device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              NULL);
+    rc = 0;
+out:
+    return rc;
+}
+
+int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb)
+{
+    int rc;
+
+    libxl_defbool_setdefault(&vfb->vnc.enable, true);
+    if (libxl_defbool_val(vfb->vnc.enable)) {
+        if (!vfb->vnc.listen) {
+            vfb->vnc.listen = strdup("127.0.0.1");
+            if (!vfb->vnc.listen) return ERROR_NOMEM;
+        }
+
+        libxl_defbool_setdefault(&vfb->vnc.findunused, true);
+    } else {
+        libxl_defbool_setdefault(&vfb->vnc.findunused, false);
+    }
+
+    libxl_defbool_setdefault(&vfb->sdl.enable, false);
+    libxl_defbool_setdefault(&vfb->sdl.opengl, false);
+
+    rc = libxl__resolve_domid(gc, vfb->backend_domname, &vfb->backend_domid);
+    return rc;
+}
+
+static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid,
+                                  libxl_device_vfb *vfb,
+                                  libxl__device *device)
+{
+    device->backend_devid = vfb->devid;
+    device->backend_domid = vfb->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_VFB;
+    device->devid = vfb->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_VFB;
+    return 0;
+}
+
+int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_vfb_add(gc, domid, vfb);
+    if (rc) {
+        LOGD(ERROR, domid, "Unable to add vfb device");
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_vfb_add(libxl__gc *gc, uint32_t domid, libxl_device_vfb *vfb)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device device;
+    int rc;
+
+    rc = libxl__device_vfb_setdefault(gc, vfb);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    if (vfb->devid == -1) {
+        if ((vfb->devid = libxl__device_nextid(gc, domid, "vfb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
+    if (rc != 0) goto out;
+
+    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
+    flexarray_append_pair(back, "online", "1");
+    flexarray_append_pair(back, "state", GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append_pair(back, "vnc",
+                          libxl_defbool_val(vfb->vnc.enable) ? "1" : "0");
+    flexarray_append_pair(back, "vnclisten", vfb->vnc.listen);
+    flexarray_append_pair(back, "vncpasswd", vfb->vnc.passwd);
+    flexarray_append_pair(back, "vncdisplay",
+                          GCSPRINTF("%d", vfb->vnc.display));
+    flexarray_append_pair(back, "vncunused",
+                          libxl_defbool_val(vfb->vnc.findunused) ? "1" : "0");
+    flexarray_append_pair(back, "sdl",
+                          libxl_defbool_val(vfb->sdl.enable) ? "1" : "0");
+    flexarray_append_pair(back, "opengl",
+                          libxl_defbool_val(vfb->sdl.opengl) ? "1" : "0");
+    if (vfb->sdl.xauthority) {
+        flexarray_append_pair(back, "xauthority", vfb->sdl.xauthority);
+    }
+    if (vfb->sdl.display) {
+        flexarray_append_pair(back, "display", vfb->sdl.display);
+    }
+
+    flexarray_append_pair(front, "backend-id",
+                          GCSPRINTF("%d", vfb->backend_domid));
+    flexarray_append_pair(front, "state", GCSPRINTF("%d", XenbusStateInitialising));
+
+    libxl__device_generic_add(gc, XBT_NULL, &device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              NULL);
+    rc = 0;
+out:
+    return rc;
+}
+
+/* The following functions are defined:
+ * libxl_device_vkb_remove
+ * libxl_device_vkb_destroy
+ * libxl_device_vfb_remove
+ * libxl_device_vfb_destroy
+ */
+
+/* channel/console hotunplug is not implemented. There are 2 possibilities:
+ * 1. add support for secondary consoles to xenconsoled
+ * 2. dynamically add/remove qemu chardevs via qmp messages. */
+
+/* vkb */
+LIBXL_DEFINE_DEVICE_REMOVE(vkb)
+
+/* vfb */
+LIBXL_DEFINE_DEVICE_REMOVE(vfb)
+
+libxl_xen_console_reader *
+    libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
+{
+    GC_INIT(ctx);
+    libxl_xen_console_reader *cr;
+    unsigned int size = 16384;
+
+    cr = libxl__zalloc(NOGC, sizeof(libxl_xen_console_reader));
+    cr->buffer = libxl__zalloc(NOGC, size);
+    cr->size = size;
+    cr->count = size;
+    cr->clear = clear;
+    cr->incremental = 1;
+
+    GC_FREE;
+    return cr;
+}
+
+/* return values:                                          *line_r
+ *   1          success, whole line obtained from buffer    non-0
+ *   0          no more lines available right now           0
+ *   negative   error code ERROR_*                          0
+ * On success *line_r is updated to point to a nul-terminated
+ * string which is valid until the next call on the same console
+ * reader.  The libxl caller may overwrite parts of the string
+ * if it wishes. */
+int libxl_xen_console_read_line(libxl_ctx *ctx,
+                                libxl_xen_console_reader *cr,
+                                char **line_r)
+{
+    int ret;
+    GC_INIT(ctx);
+
+    memset(cr->buffer, 0, cr->size);
+    ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
+                             cr->clear, cr->incremental, &cr->index);
+    if (ret < 0) {
+        LOGE(ERROR, "reading console ring buffer");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    if (!ret) {
+        if (cr->count) {
+            *line_r = cr->buffer;
+            ret = 1;
+        } else {
+            *line_r = NULL;
+            ret = 0;
+        }
+    }
+
+    GC_FREE;
+    return ret;
+}
+
+void libxl_xen_console_read_finish(libxl_ctx *ctx,
+                                   libxl_xen_console_reader *cr)
+{
+    free(cr->buffer);
+    free(cr);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 6/9] libxl: carve out memory specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (4 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 5/9] libxl: carve out console " Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 7/9] libxl: move device specific functions out of libxl.c Juergen Gross
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the memory
related functions to libxl_mem.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile         |   2 +-
 tools/libxl/libxl.c          | 583 +----------------------------------------
 tools/libxl/libxl_internal.h |   7 +
 tools/libxl/libxl_mem.c      | 601 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 612 insertions(+), 581 deletions(-)
 create mode 100644 tools/libxl/libxl_mem.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index dd7aa41..4b05e34 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -137,7 +137,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_qmp.o libxl_event.o libxl_fork.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_sched.o \
+			libxl_cpupool.o libxl_mem.o libxl_sched.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 a0663eb..d040e12 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -15,7 +15,6 @@
 #include "libxl_osdeps.h"
 
 #include "libxl_internal.h"
-#include "libxl_arch.h"
 
 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
 
@@ -593,9 +592,9 @@ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
     return 0;
 }
 
-static void xcinfo2xlinfo(libxl_ctx *ctx,
-                          const xc_domaininfo_t *xcinfo,
-                          libxl_dominfo *xlinfo)
+void xcinfo2xlinfo(libxl_ctx *ctx,
+                   const xc_domaininfo_t *xcinfo,
+                   libxl_dominfo *xlinfo)
 {
     size_t size;
 
@@ -1954,582 +1953,6 @@ out:
 }
 
 /******************************************************************************/
-
-/*
- * Set the maximum memory size of the domain in the hypervisor. There is no
- * change of the current memory size involved. The specified memory size can
- * even be above the configured maxmem size of the domain, but the related
- * Xenstore entry memory/static-max isn't modified!
- */
-int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint64_t max_memkb)
-{
-    GC_INIT(ctx);
-    char *mem, *endptr;
-    uint64_t memorykb, size;
-    char *dompath = libxl__xs_get_dompath(gc, domid);
-    int rc = 1;
-    libxl__domain_userdata_lock *lock = NULL;
-    libxl_domain_config d_config;
-
-    libxl_domain_config_init(&d_config);
-
-    CTX_LOCK;
-
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out;
-    }
-
-    mem = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target", dompath));
-    if (!mem) {
-        LOGED(ERROR, domid, "Cannot get memory info from %s/memory/target",
-              dompath);
-        goto out;
-    }
-    memorykb = strtoull(mem, &endptr, 10);
-    if (*endptr != '\0') {
-        LOGED(ERROR, domid, "Invalid memory %s from %s/memory/target\n",
-              mem, dompath);
-        goto out;
-    }
-
-    if (max_memkb < memorykb) {
-        LOGED(ERROR, domid,
-              "memory_static_max must be greater than or or equal to memory_dynamic_max");
-        goto out;
-    }
-
-    rc = libxl__get_domain_configuration(gc, domid, &d_config);
-    if (rc < 0) {
-        LOGE(ERROR, "unable to retrieve domain configuration");
-        goto out;
-    }
-
-    rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
-    if (rc < 0) {
-        LOGE(ERROR, "Couldn't get arch extra constant memory size");
-        goto out;
-    }
-
-    rc = xc_domain_setmaxmem(ctx->xch, domid, max_memkb + size);
-    if (rc != 0) {
-        LOGED(ERROR, domid,
-              "xc_domain_setmaxmem domid=%d memkb=%"PRIu64" failed ""rc=%d\n",
-              domid, max_memkb + size, rc);
-        goto out;
-    }
-
-    rc = 0;
-out:
-    libxl_domain_config_dispose(&d_config);
-    if (lock) libxl__unlock_domain_userdata(lock);
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-}
-
-static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint64_t *target_memkb,
-                                        uint64_t *max_memkb)
-{
-    int rc;
-    libxl_dominfo info;
-    libxl_physinfo physinfo;
-    char *target = NULL, *staticmax = NULL, *endptr = NULL;
-    char *target_path = "/local/domain/0/memory/target";
-    char *max_path = "/local/domain/0/memory/static-max";
-    xs_transaction_t t;
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-
-    libxl_dominfo_init(&info);
-
-retry_transaction:
-    t = xs_transaction_start(ctx->xsh);
-
-    target = libxl__xs_read(gc, t, target_path);
-    staticmax = libxl__xs_read(gc, t, max_path);
-    if (target && staticmax) {
-        rc = 0;
-        goto out;
-    }
-
-    if (target) {
-        *target_memkb = strtoull(target, &endptr, 10);
-        if (*endptr != '\0') {
-            LOGED(ERROR, 0, "Invalid memory target %s from %s\n", target,
-                 target_path);
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    if (staticmax) {
-        *max_memkb = strtoull(staticmax, &endptr, 10);
-        if (*endptr != '\0') {
-            LOGED(ERROR, 0, "Invalid memory static-max %s from %s\n",
-                 staticmax,
-                 max_path);
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    libxl_dominfo_dispose(&info);
-    libxl_dominfo_init(&info);
-    rc = libxl_domain_info(ctx, &info, 0);
-    if (rc < 0)
-        goto out;
-
-    rc = libxl_get_physinfo(ctx, &physinfo);
-    if (rc < 0)
-        goto out;
-
-    if (target == NULL) {
-        libxl__xs_printf(gc, t, target_path, "%"PRIu64, info.current_memkb);
-        *target_memkb = info.current_memkb;
-    }
-    if (staticmax == NULL) {
-        libxl__xs_printf(gc, t, max_path, "%"PRIu64, info.max_memkb);
-        *max_memkb = info.max_memkb;
-    }
-
-    rc = 0;
-
-out:
-    if (!xs_transaction_end(ctx->xsh, t, 0)) {
-        if (errno == EAGAIN)
-            goto retry_transaction;
-        else
-            rc = ERROR_FAIL;
-    }
-
-    libxl_dominfo_dispose(&info);
-    return rc;
-}
-
-int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
-        int64_t target_memkb, int relative, int enforce)
-{
-    GC_INIT(ctx);
-    int rc, r, lrc, abort_transaction = 0;
-    uint64_t memorykb, size;
-    uint64_t videoram = 0;
-    uint64_t current_target_memkb = 0, new_target_memkb = 0;
-    uint64_t current_max_memkb = 0;
-    char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
-    char *dompath = libxl__xs_get_dompath(gc, domid);
-    xc_domaininfo_t info;
-    libxl_dominfo ptr;
-    char *uuid;
-    xs_transaction_t t;
-    libxl__domain_userdata_lock *lock;
-    libxl_domain_config d_config;
-
-    libxl_domain_config_init(&d_config);
-
-    CTX_LOCK;
-
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out_no_transaction;
-    }
-
-    rc = libxl__get_domain_configuration(gc, domid, &d_config);
-    if (rc < 0) {
-        LOGE(ERROR, "unable to retrieve domain configuration");
-        goto out_no_transaction;
-    }
-
-    rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
-    if (rc < 0) {
-        LOGE(ERROR, "Couldn't get arch extra constant memory size");
-        goto out_no_transaction;
-    }
-
-retry_transaction:
-    t = xs_transaction_start(ctx->xsh);
-
-    target = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/target", dompath));
-    if (!target && !domid) {
-        if (!xs_transaction_end(ctx->xsh, t, 1)) {
-            rc = ERROR_FAIL;
-            goto out_no_transaction;
-        }
-        lrc = libxl__fill_dom0_memory_info(gc, &current_target_memkb,
-                                           &current_max_memkb);
-        if (lrc < 0) { rc = ERROR_FAIL; goto out_no_transaction; }
-        goto retry_transaction;
-    } else if (!target) {
-        LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
-              dompath);
-        abort_transaction = 1;
-        rc = ERROR_FAIL;
-        goto out;
-    } else {
-        current_target_memkb = strtoull(target, &endptr, 10);
-        if (*endptr != '\0') {
-            LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
-                  target, dompath);
-            abort_transaction = 1;
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-    memmax = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/static-max", dompath));
-    if (!memmax) {
-        LOGED(ERROR, domid, "Cannot get memory info from %s/memory/static-max",
-              dompath);
-        abort_transaction = 1;
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    memorykb = strtoull(memmax, &endptr, 10);
-    if (*endptr != '\0') {
-        LOGED(ERROR, domid, "Invalid max memory %s from %s/memory/static-max\n",
-             memmax, dompath);
-        abort_transaction = 1;
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    videoram_s = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/videoram",
-                                                 dompath));
-    videoram = videoram_s ? atoi(videoram_s) : 0;
-
-    if (relative) {
-        if (target_memkb < 0 && llabs(target_memkb) > current_target_memkb)
-            new_target_memkb = 0;
-        else
-            new_target_memkb = current_target_memkb + target_memkb;
-    } else
-        new_target_memkb = target_memkb - videoram;
-    if (new_target_memkb > memorykb) {
-        LOGD(ERROR, domid,
-             "memory_dynamic_max must be less than or equal to"
-             " memory_static_max\n");
-        abort_transaction = 1;
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
-        LOGD(ERROR, domid,
-             "New target %"PRIu64" for dom0 is below the minimum threshold",
-             new_target_memkb);
-        abort_transaction = 1;
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    if (enforce) {
-        memorykb = new_target_memkb + videoram;
-        r = xc_domain_setmaxmem(ctx->xch, domid, memorykb + size);
-        if (r != 0) {
-            LOGED(ERROR, domid,
-                  "xc_domain_setmaxmem memkb=%"PRIu64" failed ""rc=%d\n",
-                  memorykb + size,
-                  r);
-            abort_transaction = 1;
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    r = xc_domain_set_pod_target(ctx->xch, domid,
-            (new_target_memkb + size) / 4, NULL, NULL, NULL);
-    if (r != 0) {
-        LOGED(ERROR, domid,
-              "xc_domain_set_pod_target memkb=%"PRIu64" failed rc=%d\n",
-              (new_target_memkb + size) / 4,
-              r);
-        abort_transaction = 1;
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    libxl__xs_printf(gc, t, GCSPRINTF("%s/memory/target", dompath),
-                     "%"PRIu64, new_target_memkb);
-
-    r = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
-    if (r != 1 || info.domain != domid) {
-        abort_transaction = 1;
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    libxl_dominfo_init(&ptr);
-    xcinfo2xlinfo(ctx, &info, &ptr);
-    uuid = libxl__uuid2string(gc, ptr.uuid);
-    libxl__xs_printf(gc, t, GCSPRINTF("/vm/%s/memory", uuid),
-                     "%"PRIu64, new_target_memkb / 1024);
-    libxl_dominfo_dispose(&ptr);
-
-    rc = 0;
-out:
-    if (!xs_transaction_end(ctx->xsh, t, abort_transaction)
-        && !abort_transaction)
-        if (errno == EAGAIN)
-            goto retry_transaction;
-
-out_no_transaction:
-    libxl_domain_config_dispose(&d_config);
-    if (lock) libxl__unlock_domain_userdata(lock);
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-}
-
-/* out_target_memkb and out_max_memkb can be NULL */
-static int libxl__get_memory_target(libxl__gc *gc, uint32_t domid,
-                                    uint64_t *out_target_memkb,
-                                    uint64_t *out_max_memkb)
-{
-    int rc;
-    char *target = NULL, *static_max = NULL, *endptr = NULL;
-    char *dompath = libxl__xs_get_dompath(gc, domid);
-    uint64_t target_memkb, max_memkb;
-
-    target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target",
-                                                    dompath));
-    static_max = libxl__xs_read(gc, XBT_NULL,
-                    GCSPRINTF("%s/memory/static-max", dompath));
-
-    rc = ERROR_FAIL;
-    if ((!target || !static_max) && !domid) {
-        rc = libxl__fill_dom0_memory_info(gc, &target_memkb,
-                                          &max_memkb);
-        if (rc < 0)
-            goto out;
-    } else if (!target) {
-        LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
-              dompath);
-        goto out;
-    } else if (!static_max) {
-        LOGED(ERROR, domid,
-              "Cannot get target memory info from %s/memory/static-max",
-               dompath);
-        goto out;
-    } else {
-        target_memkb = strtoull(target, &endptr, 10);
-        if (*endptr != '\0') {
-            LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
-                  target, dompath);
-            goto out;
-        }
-        max_memkb = strtoull(static_max, &endptr, 10);
-        if (*endptr != '\0') {
-            LOGED(ERROR, domid,
-                  "Invalid memory target %s from %s/memory/static-max\n",
-                  static_max,
-                  dompath);
-            goto out;
-        }
-
-    }
-
-    if (out_target_memkb)
-        *out_target_memkb = target_memkb;
-
-    if (out_max_memkb)
-        *out_max_memkb = max_memkb;
-
-    rc = 0;
-
-out:
-    return rc;
-}
-
-static int libxl__memkb_64to32(libxl_ctx *ctx, int rc,
-                               uint64_t val64, uint32_t *ptr32)
-{
-    GC_INIT(ctx);
-
-    if (rc)
-        goto out;
-
-    *ptr32 = val64;
-    if (*ptr32 == val64)
-        goto out;
-
-    LOGE(ERROR, "memory size %"PRIu64" too large for 32 bit value\n", val64);
-    rc = ERROR_FAIL;
-
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid,
-                            uint64_t *out_target)
-{
-    GC_INIT(ctx);
-    int rc;
-
-    rc = libxl__get_memory_target(gc, domid, out_target, NULL);
-
-    GC_FREE;
-    return rc;
-}
-
-int libxl_get_memory_target_0x040700(
-    libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
-{
-    uint64_t my_out_target;
-    int rc;
-
-    rc = libxl_get_memory_target(ctx, domid, &my_out_target);
-    return libxl__memkb_64to32(ctx, rc, my_out_target, out_target);
-}
-
-int libxl_domain_need_memory(libxl_ctx *ctx,
-                             const libxl_domain_build_info *b_info_in,
-                             uint64_t *need_memkb)
-{
-    GC_INIT(ctx);
-    libxl_domain_build_info b_info[1];
-    int rc;
-
-    libxl_domain_build_info_init(b_info);
-    libxl_domain_build_info_copy(ctx, b_info, b_info_in);
-
-    rc = libxl__domain_build_info_setdefault(gc, b_info);
-    if (rc) goto out;
-
-    *need_memkb = b_info->target_memkb;
-    switch (b_info->type) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
-        if (libxl_defbool_val(b_info->device_model_stubdomain))
-            *need_memkb += 32 * 1024;
-        break;
-    case LIBXL_DOMAIN_TYPE_PV:
-        *need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY;
-        break;
-    default:
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    if (*need_memkb % (2 * 1024))
-        *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
-    rc = 0;
-out:
-    GC_FREE;
-    libxl_domain_build_info_dispose(b_info);
-    return rc;
-
-}
-
-int libxl_domain_need_memory_0x040700(libxl_ctx *ctx,
-                                      const libxl_domain_build_info *b_info_in,
-                                      uint32_t *need_memkb)
-{
-    uint64_t my_need_memkb;
-    int rc;
-
-    rc = libxl_domain_need_memory(ctx, b_info_in, &my_need_memkb);
-    return libxl__memkb_64to32(ctx, rc, my_need_memkb, need_memkb);
-}
-
-int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb)
-{
-    int rc = 0;
-    libxl_physinfo info;
-    GC_INIT(ctx);
-
-    rc = libxl_get_physinfo(ctx, &info);
-    if (rc < 0)
-        goto out;
-
-    *memkb = (info.free_pages + info.scrub_pages) * 4;
-
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_get_free_memory_0x040700(libxl_ctx *ctx, uint32_t *memkb)
-{
-    uint64_t my_memkb;
-    int rc;
-
-    rc = libxl_get_free_memory(ctx, &my_memkb);
-    return libxl__memkb_64to32(ctx, rc, my_memkb, memkb);
-}
-
-int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid,
-                               uint64_t memory_kb, int wait_secs)
-{
-    int rc = 0;
-    libxl_physinfo info;
-    GC_INIT(ctx);
-
-    while (wait_secs > 0) {
-        rc = libxl_get_physinfo(ctx, &info);
-        if (rc < 0)
-            goto out;
-        if (info.free_pages * 4 >= memory_kb) {
-            rc = 0;
-            goto out;
-        }
-        wait_secs--;
-        sleep(1);
-    }
-    rc = ERROR_NOMEM;
-
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
-{
-    int rc = 0;
-    uint64_t target_memkb = 0;
-    uint64_t current_memkb, prev_memkb;
-    libxl_dominfo info;
-
-    rc = libxl_get_memory_target(ctx, domid, &target_memkb);
-    if (rc < 0)
-        return rc;
-
-    libxl_dominfo_init(&info);
-    prev_memkb = UINT64_MAX;
-
-    do {
-        sleep(2);
-
-        libxl_dominfo_dispose(&info);
-        libxl_dominfo_init(&info);
-        rc = libxl_domain_info(ctx, &info, domid);
-        if (rc < 0)
-            goto out;
-
-        current_memkb = info.current_memkb + info.outstanding_memkb;
-
-        if (current_memkb > prev_memkb)
-        {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-        else if (current_memkb == prev_memkb)
-            wait_secs -= 2;
-        /* if current_memkb < prev_memkb loop for free as progress has
-         * been made */
-
-        prev_memkb = current_memkb;
-    } while (wait_secs > 0 && current_memkb > target_memkb);
-
-    if (current_memkb <= target_memkb)
-        rc = 0;
-    else
-        rc = ERROR_FAIL;
-
-out:
-    libxl_dominfo_dispose(&info);
-    return rc;
-}
-
 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
 {
     xc_physinfo_t xcphysinfo = { 0 };
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5f46578..43456a9 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -4239,6 +4239,13 @@ uint64_t libxl__get_targetmem_fudge(libxl__gc *gc,
     return info->video_memkb + mem_target_fudge;
 }
 
+int libxl__get_memory_target(libxl__gc *gc, uint32_t domid, 
+                             uint64_t *out_target_memkb,
+                             uint64_t *out_max_memkb);
+void xcinfo2xlinfo(libxl_ctx *ctx,
+                   const xc_domaininfo_t *xcinfo,
+                   libxl_dominfo *xlinfo);
+
 /* Macros used to compare device identifier. Returns true if the two
  * devices have same identifier. */
 #define COMPARE_DEVID(a, b) ((a)->devid == (b)->devid)
diff --git a/tools/libxl/libxl_mem.c b/tools/libxl/libxl_mem.c
new file mode 100644
index 0000000..a4cc99a
--- /dev/null
+++ b/tools/libxl/libxl_mem.c
@@ -0,0 +1,601 @@
+/*
+ * 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"
+#include "libxl_arch.h"
+
+/*
+ * Set the maximum memory size of the domain in the hypervisor. There is no
+ * change of the current memory size involved. The specified memory size can
+ * even be above the configured maxmem size of the domain, but the related
+ * Xenstore entry memory/static-max isn't modified!
+ */
+int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint64_t max_memkb)
+{
+    GC_INIT(ctx);
+    char *mem, *endptr;
+    uint64_t memorykb, size;
+    char *dompath = libxl__xs_get_dompath(gc, domid);
+    int rc = 1;
+    libxl__domain_userdata_lock *lock = NULL;
+    libxl_domain_config d_config;
+
+    libxl_domain_config_init(&d_config);
+
+    CTX_LOCK;
+
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {
+        rc = ERROR_LOCK_FAIL;
+        goto out;
+    }
+
+    mem = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target", dompath));
+    if (!mem) {
+        LOGED(ERROR, domid, "Cannot get memory info from %s/memory/target",
+              dompath);
+        goto out;
+    }
+    memorykb = strtoull(mem, &endptr, 10);
+    if (*endptr != '\0') {
+        LOGED(ERROR, domid, "Invalid memory %s from %s/memory/target\n",
+              mem, dompath);
+        goto out;
+    }
+
+    if (max_memkb < memorykb) {
+        LOGED(ERROR, domid,
+              "memory_static_max must be greater than or or equal to memory_dynamic_max");
+        goto out;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, &d_config);
+    if (rc < 0) {
+        LOGE(ERROR, "unable to retrieve domain configuration");
+        goto out;
+    }
+
+    rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
+    if (rc < 0) {
+        LOGE(ERROR, "Couldn't get arch extra constant memory size");
+        goto out;
+    }
+
+    rc = xc_domain_setmaxmem(ctx->xch, domid, max_memkb + size);
+    if (rc != 0) {
+        LOGED(ERROR, domid,
+              "xc_domain_setmaxmem domid=%d memkb=%"PRIu64" failed ""rc=%d\n",
+              domid, max_memkb + size, rc);
+        goto out;
+    }
+
+    rc = 0;
+out:
+    libxl_domain_config_dispose(&d_config);
+    if (lock) libxl__unlock_domain_userdata(lock);
+    CTX_UNLOCK;
+    GC_FREE;
+    return rc;
+}
+
+static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint64_t *target_memkb,
+                                        uint64_t *max_memkb)
+{
+    int rc;
+    libxl_dominfo info;
+    libxl_physinfo physinfo;
+    char *target = NULL, *staticmax = NULL, *endptr = NULL;
+    char *target_path = "/local/domain/0/memory/target";
+    char *max_path = "/local/domain/0/memory/static-max";
+    xs_transaction_t t;
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+
+    libxl_dominfo_init(&info);
+
+retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+
+    target = libxl__xs_read(gc, t, target_path);
+    staticmax = libxl__xs_read(gc, t, max_path);
+    if (target && staticmax) {
+        rc = 0;
+        goto out;
+    }
+
+    if (target) {
+        *target_memkb = strtoull(target, &endptr, 10);
+        if (*endptr != '\0') {
+            LOGED(ERROR, 0, "Invalid memory target %s from %s\n", target,
+                 target_path);
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    if (staticmax) {
+        *max_memkb = strtoull(staticmax, &endptr, 10);
+        if (*endptr != '\0') {
+            LOGED(ERROR, 0, "Invalid memory static-max %s from %s\n",
+                 staticmax,
+                 max_path);
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    libxl_dominfo_dispose(&info);
+    libxl_dominfo_init(&info);
+    rc = libxl_domain_info(ctx, &info, 0);
+    if (rc < 0)
+        goto out;
+
+    rc = libxl_get_physinfo(ctx, &physinfo);
+    if (rc < 0)
+        goto out;
+
+    if (target == NULL) {
+        libxl__xs_printf(gc, t, target_path, "%"PRIu64, info.current_memkb);
+        *target_memkb = info.current_memkb;
+    }
+    if (staticmax == NULL) {
+        libxl__xs_printf(gc, t, max_path, "%"PRIu64, info.max_memkb);
+        *max_memkb = info.max_memkb;
+    }
+
+    rc = 0;
+
+out:
+    if (!xs_transaction_end(ctx->xsh, t, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else
+            rc = ERROR_FAIL;
+    }
+
+    libxl_dominfo_dispose(&info);
+    return rc;
+}
+
+int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
+        int64_t target_memkb, int relative, int enforce)
+{
+    GC_INIT(ctx);
+    int rc, r, lrc, abort_transaction = 0;
+    uint64_t memorykb, size;
+    uint64_t videoram = 0;
+    uint64_t current_target_memkb = 0, new_target_memkb = 0;
+    uint64_t current_max_memkb = 0;
+    char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
+    char *dompath = libxl__xs_get_dompath(gc, domid);
+    xc_domaininfo_t info;
+    libxl_dominfo ptr;
+    char *uuid;
+    xs_transaction_t t;
+    libxl__domain_userdata_lock *lock;
+    libxl_domain_config d_config;
+
+    libxl_domain_config_init(&d_config);
+
+    CTX_LOCK;
+
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {
+        rc = ERROR_LOCK_FAIL;
+        goto out_no_transaction;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, &d_config);
+    if (rc < 0) {
+        LOGE(ERROR, "unable to retrieve domain configuration");
+        goto out_no_transaction;
+    }
+
+    rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size);
+    if (rc < 0) {
+        LOGE(ERROR, "Couldn't get arch extra constant memory size");
+        goto out_no_transaction;
+    }
+
+retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+
+    target = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/target", dompath));
+    if (!target && !domid) {
+        if (!xs_transaction_end(ctx->xsh, t, 1)) {
+            rc = ERROR_FAIL;
+            goto out_no_transaction;
+        }
+        lrc = libxl__fill_dom0_memory_info(gc, &current_target_memkb,
+                                           &current_max_memkb);
+        if (lrc < 0) { rc = ERROR_FAIL; goto out_no_transaction; }
+        goto retry_transaction;
+    } else if (!target) {
+        LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
+              dompath);
+        abort_transaction = 1;
+        rc = ERROR_FAIL;
+        goto out;
+    } else {
+        current_target_memkb = strtoull(target, &endptr, 10);
+        if (*endptr != '\0') {
+            LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
+                  target, dompath);
+            abort_transaction = 1;
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+    memmax = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/static-max", dompath));
+    if (!memmax) {
+        LOGED(ERROR, domid, "Cannot get memory info from %s/memory/static-max",
+              dompath);
+        abort_transaction = 1;
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    memorykb = strtoull(memmax, &endptr, 10);
+    if (*endptr != '\0') {
+        LOGED(ERROR, domid, "Invalid max memory %s from %s/memory/static-max\n",
+             memmax, dompath);
+        abort_transaction = 1;
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    videoram_s = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/videoram",
+                                                 dompath));
+    videoram = videoram_s ? atoi(videoram_s) : 0;
+
+    if (relative) {
+        if (target_memkb < 0 && llabs(target_memkb) > current_target_memkb)
+            new_target_memkb = 0;
+        else
+            new_target_memkb = current_target_memkb + target_memkb;
+    } else
+        new_target_memkb = target_memkb - videoram;
+    if (new_target_memkb > memorykb) {
+        LOGD(ERROR, domid,
+             "memory_dynamic_max must be less than or equal to"
+             " memory_static_max\n");
+        abort_transaction = 1;
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
+        LOGD(ERROR, domid,
+             "New target %"PRIu64" for dom0 is below the minimum threshold",
+             new_target_memkb);
+        abort_transaction = 1;
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (enforce) {
+        memorykb = new_target_memkb + videoram;
+        r = xc_domain_setmaxmem(ctx->xch, domid, memorykb + size);
+        if (r != 0) {
+            LOGED(ERROR, domid,
+                  "xc_domain_setmaxmem memkb=%"PRIu64" failed ""rc=%d\n",
+                  memorykb + size,
+                  r);
+            abort_transaction = 1;
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    r = xc_domain_set_pod_target(ctx->xch, domid,
+            (new_target_memkb + size) / 4, NULL, NULL, NULL);
+    if (r != 0) {
+        LOGED(ERROR, domid,
+              "xc_domain_set_pod_target memkb=%"PRIu64" failed rc=%d\n",
+              (new_target_memkb + size) / 4,
+              r);
+        abort_transaction = 1;
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    libxl__xs_printf(gc, t, GCSPRINTF("%s/memory/target", dompath),
+                     "%"PRIu64, new_target_memkb);
+
+    r = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
+    if (r != 1 || info.domain != domid) {
+        abort_transaction = 1;
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    libxl_dominfo_init(&ptr);
+    xcinfo2xlinfo(ctx, &info, &ptr);
+    uuid = libxl__uuid2string(gc, ptr.uuid);
+    libxl__xs_printf(gc, t, GCSPRINTF("/vm/%s/memory", uuid),
+                     "%"PRIu64, new_target_memkb / 1024);
+    libxl_dominfo_dispose(&ptr);
+
+    rc = 0;
+out:
+    if (!xs_transaction_end(ctx->xsh, t, abort_transaction)
+        && !abort_transaction)
+        if (errno == EAGAIN)
+            goto retry_transaction;
+
+out_no_transaction:
+    libxl_domain_config_dispose(&d_config);
+    if (lock) libxl__unlock_domain_userdata(lock);
+    CTX_UNLOCK;
+    GC_FREE;
+    return rc;
+}
+
+/* out_target_memkb and out_max_memkb can be NULL */
+int libxl__get_memory_target(libxl__gc *gc, uint32_t domid,
+                             uint64_t *out_target_memkb,
+                             uint64_t *out_max_memkb)
+{
+    int rc;
+    char *target = NULL, *static_max = NULL, *endptr = NULL;
+    char *dompath = libxl__xs_get_dompath(gc, domid);
+    uint64_t target_memkb, max_memkb;
+
+    target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/memory/target",
+                                                    dompath));
+    static_max = libxl__xs_read(gc, XBT_NULL,
+                    GCSPRINTF("%s/memory/static-max", dompath));
+
+    rc = ERROR_FAIL;
+    if ((!target || !static_max) && !domid) {
+        rc = libxl__fill_dom0_memory_info(gc, &target_memkb,
+                                          &max_memkb);
+        if (rc < 0)
+            goto out;
+    } else if (!target) {
+        LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target",
+              dompath);
+        goto out;
+    } else if (!static_max) {
+        LOGED(ERROR, domid,
+              "Cannot get target memory info from %s/memory/static-max",
+               dompath);
+        goto out;
+    } else {
+        target_memkb = strtoull(target, &endptr, 10);
+        if (*endptr != '\0') {
+            LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n",
+                  target, dompath);
+            goto out;
+        }
+        max_memkb = strtoull(static_max, &endptr, 10);
+        if (*endptr != '\0') {
+            LOGED(ERROR, domid,
+                  "Invalid memory target %s from %s/memory/static-max\n",
+                  static_max,
+                  dompath);
+            goto out;
+        }
+
+    }
+
+    if (out_target_memkb)
+        *out_target_memkb = target_memkb;
+
+    if (out_max_memkb)
+        *out_max_memkb = max_memkb;
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+static int libxl__memkb_64to32(libxl_ctx *ctx, int rc,
+                               uint64_t val64, uint32_t *ptr32)
+{
+    GC_INIT(ctx);
+
+    if (rc)
+        goto out;
+
+    *ptr32 = val64;
+    if (*ptr32 == val64)
+        goto out;
+
+    LOGE(ERROR, "memory size %"PRIu64" too large for 32 bit value\n", val64);
+    rc = ERROR_FAIL;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid,
+                            uint64_t *out_target)
+{
+    GC_INIT(ctx);
+    int rc;
+
+    rc = libxl__get_memory_target(gc, domid, out_target, NULL);
+
+    GC_FREE;
+    return rc;
+}
+
+int libxl_get_memory_target_0x040700(
+    libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
+{
+    uint64_t my_out_target;
+    int rc;
+
+    rc = libxl_get_memory_target(ctx, domid, &my_out_target);
+    return libxl__memkb_64to32(ctx, rc, my_out_target, out_target);
+}
+
+int libxl_domain_need_memory(libxl_ctx *ctx,
+                             const libxl_domain_build_info *b_info_in,
+                             uint64_t *need_memkb)
+{
+    GC_INIT(ctx);
+    libxl_domain_build_info b_info[1];
+    int rc;
+
+    libxl_domain_build_info_init(b_info);
+    libxl_domain_build_info_copy(ctx, b_info, b_info_in);
+
+    rc = libxl__domain_build_info_setdefault(gc, b_info);
+    if (rc) goto out;
+
+    *need_memkb = b_info->target_memkb;
+    switch (b_info->type) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
+        if (libxl_defbool_val(b_info->device_model_stubdomain))
+            *need_memkb += 32 * 1024;
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        *need_memkb += b_info->shadow_memkb + LIBXL_PV_EXTRA_MEMORY;
+        break;
+    default:
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    if (*need_memkb % (2 * 1024))
+        *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
+    rc = 0;
+out:
+    GC_FREE;
+    libxl_domain_build_info_dispose(b_info);
+    return rc;
+
+}
+
+int libxl_domain_need_memory_0x040700(libxl_ctx *ctx,
+                                      const libxl_domain_build_info *b_info_in,
+                                      uint32_t *need_memkb)
+{
+    uint64_t my_need_memkb;
+    int rc;
+
+    rc = libxl_domain_need_memory(ctx, b_info_in, &my_need_memkb);
+    return libxl__memkb_64to32(ctx, rc, my_need_memkb, need_memkb);
+}
+
+int libxl_get_free_memory(libxl_ctx *ctx, uint64_t *memkb)
+{
+    int rc = 0;
+    libxl_physinfo info;
+    GC_INIT(ctx);
+
+    rc = libxl_get_physinfo(ctx, &info);
+    if (rc < 0)
+        goto out;
+
+    *memkb = (info.free_pages + info.scrub_pages) * 4;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_get_free_memory_0x040700(libxl_ctx *ctx, uint32_t *memkb)
+{
+    uint64_t my_memkb;
+    int rc;
+
+    rc = libxl_get_free_memory(ctx, &my_memkb);
+    return libxl__memkb_64to32(ctx, rc, my_memkb, memkb);
+}
+
+int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid,
+                               uint64_t memory_kb, int wait_secs)
+{
+    int rc = 0;
+    libxl_physinfo info;
+    GC_INIT(ctx);
+
+    while (wait_secs > 0) {
+        rc = libxl_get_physinfo(ctx, &info);
+        if (rc < 0)
+            goto out;
+        if (info.free_pages * 4 >= memory_kb) {
+            rc = 0;
+            goto out;
+        }
+        wait_secs--;
+        sleep(1);
+    }
+    rc = ERROR_NOMEM;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
+{
+    int rc = 0;
+    uint64_t target_memkb = 0;
+    uint64_t current_memkb, prev_memkb;
+    libxl_dominfo info;
+
+    rc = libxl_get_memory_target(ctx, domid, &target_memkb);
+    if (rc < 0)
+        return rc;
+
+    libxl_dominfo_init(&info);
+    prev_memkb = UINT64_MAX;
+
+    do {
+        sleep(2);
+
+        libxl_dominfo_dispose(&info);
+        libxl_dominfo_init(&info);
+        rc = libxl_domain_info(ctx, &info, domid);
+        if (rc < 0)
+            goto out;
+
+        current_memkb = info.current_memkb + info.outstanding_memkb;
+
+        if (current_memkb > prev_memkb)
+        {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+        else if (current_memkb == prev_memkb)
+            wait_secs -= 2;
+        /* if current_memkb < prev_memkb loop for free as progress has
+         * been made */
+
+        prev_memkb = current_memkb;
+    } while (wait_secs > 0 && current_memkb > target_memkb);
+
+    if (current_memkb <= target_memkb)
+        rc = 0;
+    else
+        rc = ERROR_FAIL;
+
+out:
+    libxl_dominfo_dispose(&info);
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 7/9] libxl: move device specific functions out of libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (5 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 6/9] libxl: carve out memory " Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 8/9] libxl: carve out tmem specific functions from libxl.c Juergen Gross
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

Move the few generic device specific functions left in libxl.c to
libxl_device.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/libxl.c          | 416 -----------------------------------------
 tools/libxl/libxl_device.c   | 435 +++++++++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl_internal.h |   1 -
 3 files changed, 423 insertions(+), 429 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index d040e12..d559991 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1529,50 +1529,6 @@ out:
 
 /******************************************************************************/
 
-/* generic callback for devices that only need to set ao_complete */
-void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-
-    if (aodev->rc) {
-        if (aodev->dev) {
-            LOGD(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
-                        libxl__device_action_to_string(aodev->action),
-                        libxl__device_kind_to_string(aodev->dev->kind),
-                        aodev->dev->devid);
-        } else {
-            LOG(ERROR, "unable to %s device",
-                       libxl__device_action_to_string(aodev->action));
-        }
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, aodev->rc);
-    return;
-}
-
-/* common function to get next device id */
-int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
-{
-    char *libxl_dom_path, **l;
-    unsigned int nb;
-    int nextid = -1;
-
-    if (!(libxl_dom_path = libxl__xs_libxl_path(gc, domid)))
-        return nextid;
-
-    l = libxl__xs_directory(gc, XBT_NULL,
-        GCSPRINTF("%s/device/%s", libxl_dom_path, device),
-                            &nb);
-    if (l == NULL || nb == 0)
-        nextid = 0;
-    else
-        nextid = strtoul(l[nb - 1], NULL, 10) + 1;
-
-    return nextid;
-}
-
 int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
 {
     if (!name)
@@ -1581,378 +1537,6 @@ int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
 }
 
 /******************************************************************************/
-
-/*
- * Data structures used to track devices handled by driver domains
- */
-
-/*
- * Structure that describes a device handled by a driver domain
- */
-typedef struct libxl__ddomain_device {
-    libxl__device *dev;
-    LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next;
-} libxl__ddomain_device;
-
-/*
- * Structure that describes a domain and it's associated devices
- */
-typedef struct libxl__ddomain_guest {
-    uint32_t domid;
-    int num_vifs, num_vbds, num_qdisks;
-    LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices;
-    LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next;
-} libxl__ddomain_guest;
-
-/*
- * Main structure used by a driver domain to keep track of devices
- * currently in use
- */
-typedef struct {
-    libxl__ao *ao;
-    libxl__ev_xswatch watch;
-    LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests;
-} libxl__ddomain;
-
-static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain,
-                                               uint32_t domid)
-{
-    libxl__ddomain_guest *dguest;
-
-    LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) {
-        if (dguest->domid == domid)
-            return dguest;
-    }
-    return NULL;
-}
-
-static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest,
-                                                libxl__device *dev)
-{
-    libxl__ddomain_device *ddev;
-
-    LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) {
-#define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry)
-        if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, devid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, domid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, kind))
-            return ddev;
-#undef LIBXL_DEVICE_CMP
-    }
-
-    return NULL;
-}
-
-static void device_complete(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-
-    LOG(DEBUG, "device %s %s %s",
-               libxl__device_backend_path(gc, aodev->dev),
-               libxl__device_action_to_string(aodev->action),
-               aodev->rc ? "failed" : "succeed");
-
-    if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE)
-        free(aodev->dev);
-
-    libxl__nested_ao_free(aodev->ao);
-}
-
-static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss,
-                                int rc)
-{
-    STATE_AO_GC(dmss->spawn.ao);
-
-    LOGD(DEBUG, dmss->guest_domid, "qdisk backend spawn %s",
-                rc ? "failed" : "succeed");
-
-    libxl__nested_ao_free(dmss->spawn.ao);
-}
-
-/*
- * The following comment applies to both add_device and remove_device.
- *
- * If the return value is greater than 0, it means there's no ao dispatched,
- * so the free of the nested ao should be done by the parent when it has
- * finished.
- */
-static int add_device(libxl__egc *egc, libxl__ao *ao,
-                      libxl__ddomain_guest *dguest,
-                      libxl__ddomain_device *ddev)
-{
-    AO_GC;
-    libxl__device *dev = ddev->dev;
-    libxl__ao_device *aodev;
-    libxl__dm_spawn_state *dmss;
-    int rc = 0;
-
-    switch(dev->backend_kind) {
-    case LIBXL__DEVICE_KIND_VBD:
-    case LIBXL__DEVICE_KIND_VIF:
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++;
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++;
-
-        GCNEW(aodev);
-        libxl__prepare_ao_device(ao, aodev);
-        aodev->dev = dev;
-        aodev->action = LIBXL__DEVICE_ACTION_ADD;
-        aodev->callback = device_complete;
-        libxl__wait_device_connection(egc, aodev);
-
-        break;
-    case LIBXL__DEVICE_KIND_QDISK:
-        if (dguest->num_qdisks == 0) {
-            GCNEW(dmss);
-            dmss->guest_domid = dev->domid;
-            dmss->spawn.ao = ao;
-            dmss->callback = qdisk_spawn_outcome;
-
-            libxl__spawn_qdisk_backend(egc, dmss);
-        }
-        dguest->num_qdisks++;
-
-        break;
-    default:
-        rc = 1;
-        break;
-    }
-
-    return rc;
-}
-
-static int remove_device(libxl__egc *egc, libxl__ao *ao,
-                         libxl__ddomain_guest *dguest,
-                         libxl__ddomain_device *ddev)
-{
-    AO_GC;
-    libxl__device *dev = ddev->dev;
-    libxl__ao_device *aodev;
-    int rc = 0;
-
-    switch(ddev->dev->backend_kind) {
-    case LIBXL__DEVICE_KIND_VBD:
-    case LIBXL__DEVICE_KIND_VIF:
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--;
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--;
-
-        GCNEW(aodev);
-        libxl__prepare_ao_device(ao, aodev);
-        aodev->dev = dev;
-        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
-        aodev->callback = device_complete;
-        libxl__initiate_device_generic_remove(egc, aodev);
-        break;
-    case LIBXL__DEVICE_KIND_QDISK:
-        if (--dguest->num_qdisks == 0) {
-            rc = libxl__destroy_qdisk_backend(gc, dev->domid);
-            if (rc)
-                goto out;
-        }
-        libxl__device_destroy(gc, dev);
-        free(dev);
-        /* Fall through to return > 0, no ao has been dispatched */
-    default:
-        rc = 1;
-        break;
-    }
-
-out:
-    return rc;
-}
-
-static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch,
-                                   const char *watch_path,
-                                   const char *event_path)
-{
-    libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch);
-    libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao);
-    STATE_AO_GC(nested_ao);
-    char *p, *path;
-    const char *sstate, *sonline;
-    int state, online, rc, num_devs;
-    libxl__device *dev = NULL;
-    libxl__ddomain_device *ddev = NULL;
-    libxl__ddomain_guest *dguest = NULL;
-    bool free_ao = false;
-
-    /* Check if event_path ends with "state" or "online" and truncate it. */
-    path = libxl__strdup(gc, event_path);
-    p = strrchr(path, '/');
-    if (p == NULL)
-        goto skip;
-    if (strcmp(p, "/state") != 0 && strcmp(p, "/online") != 0)
-        goto skip;
-    /* Truncate the string so it points to the backend directory. */
-    *p = '\0';
-
-    /* Fetch the value of the state and online nodes. */
-    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/state", path),
-                                &sstate);
-    if (rc || !sstate)
-        goto skip;
-    state = atoi(sstate);
-
-    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/online", path),
-                                &sonline);
-    if (rc || !sonline)
-        goto skip;
-    online = atoi(sonline);
-
-    dev = libxl__zalloc(NOGC, sizeof(*dev));
-    rc = libxl__parse_backend_path(gc, path, dev);
-    if (rc)
-        goto skip;
-
-    dguest = search_for_guest(ddomain, dev->domid);
-    if (dguest == NULL && state == XenbusStateClosed) {
-        /*
-         * Spurious state change, device has already been disconnected
-         * or never attached.
-         */
-        goto skip;
-    }
-    if (dguest == NULL) {
-        /* Create a new guest struct and initialize it */
-        dguest = libxl__zalloc(NOGC, sizeof(*dguest));
-        dguest->domid = dev->domid;
-        LIBXL_SLIST_INIT(&dguest->devices);
-        LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next);
-        LOGD(DEBUG, dguest->domid, "Added domain to the list of active guests");
-    }
-    ddev = search_for_device(dguest, dev);
-    if (ddev == NULL && state == XenbusStateClosed) {
-        /*
-         * Spurious state change, device has already been disconnected
-         * or never attached.
-         */
-        goto skip;
-    } else if (ddev == NULL) {
-        /*
-         * New device addition, allocate a struct to hold it and add it
-         * to the list of active devices for a given guest.
-         */
-        ddev = libxl__zalloc(NOGC, sizeof(*ddev));
-        ddev->dev = dev;
-        LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next);
-        LOGD(DEBUG, dev->domid, "Added device %s to the list of active devices",
-             path);
-        rc = add_device(egc, nested_ao, dguest, ddev);
-        if (rc > 0)
-            free_ao = true;
-    } else if (state == XenbusStateClosed && online == 0) {
-        /*
-         * Removal of an active device, remove it from the list and
-         * free it's data structures if they are no longer needed.
-         *
-         * The free of the associated libxl__device is left to the
-         * helper remove_device function.
-         */
-        LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device,
-                           next);
-        LOGD(DEBUG, dev->domid, "Removed device %s from the list of active devices",
-             path);
-        rc = remove_device(egc, nested_ao, dguest, ddev);
-        if (rc > 0)
-            free_ao = true;
-
-        free(ddev);
-        /* If this was the last device in the domain, remove it from the list */
-        num_devs = dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks;
-        if (num_devs == 0) {
-            LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest,
-                               next);
-            LOGD(DEBUG, dguest->domid, "Removed domain from the list of active guests");
-            /* Clear any leftovers in libxl/<domid> */
-            libxl__xs_rm_checked(gc, XBT_NULL,
-                                 GCSPRINTF("libxl/%u", dguest->domid));
-            free(dguest);
-        }
-    }
-
-    if (free_ao)
-        libxl__nested_ao_free(nested_ao);
-
-    return;
-
-skip:
-    libxl__nested_ao_free(nested_ao);
-    free(dev);
-    free(ddev);
-    free(dguest);
-    return;
-}
-
-/* Handler of events for device driver domains */
-int libxl_device_events_handler(libxl_ctx *ctx,
-                                const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, 0, ao_how);
-    int rc;
-    uint32_t domid;
-    libxl__ddomain ddomain;
-    char *be_path;
-    char **kinds = NULL, **domains = NULL, **devs = NULL;
-    const char *sstate;
-    char *state_path;
-    int state;
-    unsigned int nkinds, ndomains, ndevs;
-    int i, j, k;
-
-    ddomain.ao = ao;
-    LIBXL_SLIST_INIT(&ddomain.guests);
-
-    rc = libxl__get_domid(gc, &domid);
-    if (rc) {
-        LOG(ERROR, "unable to get domain id");
-        goto out;
-    }
-
-    /*
-     * We use absolute paths because we want xswatch to also return
-     * absolute paths that can be parsed by libxl__parse_backend_path.
-     */
-    be_path = GCSPRINTF("/local/domain/%u/backend", domid);
-    rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback,
-                                    be_path);
-    if (rc) goto out;
-
-    kinds = libxl__xs_directory(gc, XBT_NULL, be_path, &nkinds);
-    if (kinds) {
-        for (i = 0; i < nkinds; i++) {
-            domains = libxl__xs_directory(gc, XBT_NULL,
-                    GCSPRINTF("%s/%s", be_path, kinds[i]), &ndomains);
-            if (!domains)
-                continue;
-            for (j = 0; j < ndomains; j++) {
-                devs = libxl__xs_directory(gc, XBT_NULL,
-                        GCSPRINTF("%s/%s/%s", be_path, kinds[i], domains[j]), &ndevs);
-                if (!devs)
-                    continue;
-                for (k = 0; k < ndevs; k++) {
-                    state_path = GCSPRINTF("%s/%s/%s/%s/state",
-                            be_path, kinds[i], domains[j], devs[k]);
-                    rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, &sstate);
-                    if (rc || !sstate)
-                        continue;
-                    state = atoi(sstate);
-                    if (state == XenbusStateInitWait)
-                        backend_watch_callback(egc, &ddomain.watch,
-                                               be_path, state_path);
-                }
-            }
-        }
-    }
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_CREATE_FAIL(rc);
-}
-
-/******************************************************************************/
 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
 {
     xc_physinfo_t xcphysinfo = { 0 };
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index b2aeefc..e54d1a2 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -18,7 +18,7 @@
 
 #include "libxl_internal.h"
 
-char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
+static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
 {
     char *dom_path = libxl__xs_get_dompath(gc, device->domid);
 
@@ -756,7 +756,14 @@ out:
 /* Callback for device destruction */
 
 static void devices_remove_callback(libxl__egc *egc,
-                                    libxl__multidev *multidev, int rc);
+                                    libxl__multidev *multidev, int rc)
+{
+    libxl__devices_remove_state *drs = CONTAINER_OF(multidev, *drs, multidev);
+    STATE_AO_GC(drs->ao);
+
+    drs->callback(egc, drs, rc);
+    return;
+}
 
 void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
 {
@@ -1307,16 +1314,6 @@ static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev)
     assert(!libxl__async_exec_inuse(&aodev->aes));
 }
 
-static void devices_remove_callback(libxl__egc *egc,
-                                    libxl__multidev *multidev, int rc)
-{
-    libxl__devices_remove_state *drs = CONTAINER_OF(multidev, *drs, multidev);
-    STATE_AO_GC(drs->ao);
-
-    drs->callback(egc, drs, rc);
-    return;
-}
-
 int libxl__wait_for_device_model_deprecated(libxl__gc *gc,
                                  uint32_t domid, char *state,
                                  libxl__spawn_starting *spawning,
@@ -1362,6 +1359,420 @@ int libxl__wait_for_backend(libxl__gc *gc, const char *be_path,
     return ERROR_FAIL;
 }
 
+/* generic callback for devices that only need to set ao_complete */
+void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    if (aodev->rc) {
+        if (aodev->dev) {
+            LOGD(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
+                        libxl__device_action_to_string(aodev->action),
+                        libxl__device_kind_to_string(aodev->dev->kind),
+                        aodev->dev->devid);
+        } else {
+            LOG(ERROR, "unable to %s device",
+                       libxl__device_action_to_string(aodev->action));
+        }
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, aodev->rc);
+    return;
+}
+
+/* common function to get next device id */
+int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
+{
+    char *libxl_dom_path, **l;
+    unsigned int nb;
+    int nextid = -1;
+
+    if (!(libxl_dom_path = libxl__xs_libxl_path(gc, domid)))
+        return nextid;
+
+    l = libxl__xs_directory(gc, XBT_NULL,
+        GCSPRINTF("%s/device/%s", libxl_dom_path, device),
+                            &nb);
+    if (l == NULL || nb == 0)
+        nextid = 0;
+    else
+        nextid = strtoul(l[nb - 1], NULL, 10) + 1;
+
+    return nextid;
+}
+
+static void device_complete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    LOG(DEBUG, "device %s %s %s",
+               libxl__device_backend_path(gc, aodev->dev),
+               libxl__device_action_to_string(aodev->action),
+               aodev->rc ? "failed" : "succeed");
+
+    if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE)
+        free(aodev->dev);
+
+    libxl__nested_ao_free(aodev->ao);
+}
+
+static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss,
+                                int rc)
+{
+    STATE_AO_GC(dmss->spawn.ao);
+
+    LOGD(DEBUG, dmss->guest_domid, "qdisk backend spawn %s",
+                rc ? "failed" : "succeed");
+
+    libxl__nested_ao_free(dmss->spawn.ao);
+}
+
+/*
+ * Data structures used to track devices handled by driver domains
+ */
+
+/*
+ * Structure that describes a device handled by a driver domain
+ */
+typedef struct libxl__ddomain_device {
+    libxl__device *dev;
+    LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next;
+} libxl__ddomain_device;
+
+/*
+ * Structure that describes a domain and it's associated devices
+ */
+typedef struct libxl__ddomain_guest {
+    uint32_t domid;
+    int num_vifs, num_vbds, num_qdisks;
+    LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices;
+    LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next;
+} libxl__ddomain_guest;
+
+/*
+ * Main structure used by a driver domain to keep track of devices
+ * currently in use
+ */
+typedef struct {
+    libxl__ao *ao;
+    libxl__ev_xswatch watch;
+    LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests;
+} libxl__ddomain;
+
+static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain,
+                                               uint32_t domid)
+{
+    libxl__ddomain_guest *dguest;
+
+    LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) {
+        if (dguest->domid == domid)
+            return dguest;
+    }
+    return NULL;
+}
+
+static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest,
+                                                libxl__device *dev)
+{
+    libxl__ddomain_device *ddev;
+
+    LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) {
+#define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry)
+        if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, devid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, domid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, kind))
+            return ddev;
+#undef LIBXL_DEVICE_CMP
+    }
+
+    return NULL;
+}
+
+/*
+ * The following comment applies to both add_device and remove_device.
+ *
+ * If the return value is greater than 0, it means there's no ao dispatched,
+ * so the free of the nested ao should be done by the parent when it has
+ * finished.
+ */
+static int add_device(libxl__egc *egc, libxl__ao *ao,
+                      libxl__ddomain_guest *dguest,
+                      libxl__ddomain_device *ddev)
+{
+    AO_GC;
+    libxl__device *dev = ddev->dev;
+    libxl__ao_device *aodev;
+    libxl__dm_spawn_state *dmss;
+    int rc = 0;
+
+    switch(dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+    case LIBXL__DEVICE_KIND_VIF:
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++;
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++;
+
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->dev = dev;
+        aodev->action = LIBXL__DEVICE_ACTION_ADD;
+        aodev->callback = device_complete;
+        libxl__wait_device_connection(egc, aodev);
+
+        break;
+    case LIBXL__DEVICE_KIND_QDISK:
+        if (dguest->num_qdisks == 0) {
+            GCNEW(dmss);
+            dmss->guest_domid = dev->domid;
+            dmss->spawn.ao = ao;
+            dmss->callback = qdisk_spawn_outcome;
+
+            libxl__spawn_qdisk_backend(egc, dmss);
+        }
+        dguest->num_qdisks++;
+
+        break;
+    default:
+        rc = 1;
+        break;
+    }
+
+    return rc;
+}
+
+static int remove_device(libxl__egc *egc, libxl__ao *ao,
+                         libxl__ddomain_guest *dguest,
+                         libxl__ddomain_device *ddev)
+{
+    AO_GC;
+    libxl__device *dev = ddev->dev;
+    libxl__ao_device *aodev;
+    int rc = 0;
+
+    switch(ddev->dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+    case LIBXL__DEVICE_KIND_VIF:
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--;
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--;
+
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->dev = dev;
+        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+        aodev->callback = device_complete;
+        libxl__initiate_device_generic_remove(egc, aodev);
+        break;
+    case LIBXL__DEVICE_KIND_QDISK:
+        if (--dguest->num_qdisks == 0) {
+            rc = libxl__destroy_qdisk_backend(gc, dev->domid);
+            if (rc)
+                goto out;
+        }
+        libxl__device_destroy(gc, dev);
+        free(dev);
+        /* Fall through to return > 0, no ao has been dispatched */
+    default:
+        rc = 1;
+        break;
+    }
+
+out:
+    return rc;
+}
+
+static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch,
+                                   const char *watch_path,
+                                   const char *event_path)
+{
+    libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch);
+    libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao);
+    STATE_AO_GC(nested_ao);
+    char *p, *path;
+    const char *sstate, *sonline;
+    int state, online, rc, num_devs;
+    libxl__device *dev = NULL;
+    libxl__ddomain_device *ddev = NULL;
+    libxl__ddomain_guest *dguest = NULL;
+    bool free_ao = false;
+
+    /* Check if event_path ends with "state" or "online" and truncate it. */
+    path = libxl__strdup(gc, event_path);
+    p = strrchr(path, '/');
+    if (p == NULL)
+        goto skip;
+    if (strcmp(p, "/state") != 0 && strcmp(p, "/online") != 0)
+        goto skip;
+    /* Truncate the string so it points to the backend directory. */
+    *p = '\0';
+
+    /* Fetch the value of the state and online nodes. */
+    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/state", path),
+                                &sstate);
+    if (rc || !sstate)
+        goto skip;
+    state = atoi(sstate);
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/online", path),
+                                &sonline);
+    if (rc || !sonline)
+        goto skip;
+    online = atoi(sonline);
+
+    dev = libxl__zalloc(NOGC, sizeof(*dev));
+    rc = libxl__parse_backend_path(gc, path, dev);
+    if (rc)
+        goto skip;
+
+    dguest = search_for_guest(ddomain, dev->domid);
+    if (dguest == NULL && state == XenbusStateClosed) {
+        /*
+         * Spurious state change, device has already been disconnected
+         * or never attached.
+         */
+        goto skip;
+    }
+    if (dguest == NULL) {
+        /* Create a new guest struct and initialize it */
+        dguest = libxl__zalloc(NOGC, sizeof(*dguest));
+        dguest->domid = dev->domid;
+        LIBXL_SLIST_INIT(&dguest->devices);
+        LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next);
+        LOGD(DEBUG, dguest->domid, "Added domain to the list of active guests");
+    }
+    ddev = search_for_device(dguest, dev);
+    if (ddev == NULL && state == XenbusStateClosed) {
+        /*
+         * Spurious state change, device has already been disconnected
+         * or never attached.
+         */
+        goto skip;
+    } else if (ddev == NULL) {
+        /*
+         * New device addition, allocate a struct to hold it and add it
+         * to the list of active devices for a given guest.
+         */
+        ddev = libxl__zalloc(NOGC, sizeof(*ddev));
+        ddev->dev = dev;
+        LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next);
+        LOGD(DEBUG, dev->domid, "Added device %s to the list of active devices",
+             path);
+        rc = add_device(egc, nested_ao, dguest, ddev);
+        if (rc > 0)
+            free_ao = true;
+    } else if (state == XenbusStateClosed && online == 0) {
+        /*
+         * Removal of an active device, remove it from the list and
+         * free it's data structures if they are no longer needed.
+         *
+         * The free of the associated libxl__device is left to the
+         * helper remove_device function.
+         */
+        LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device,
+                           next);
+        LOGD(DEBUG, dev->domid, "Removed device %s from the list of active devices",
+             path);
+        rc = remove_device(egc, nested_ao, dguest, ddev);
+        if (rc > 0)
+            free_ao = true;
+
+        free(ddev);
+        /* If this was the last device in the domain, remove it from the list */
+        num_devs = dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks;
+        if (num_devs == 0) {
+            LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest,
+                               next);
+            LOGD(DEBUG, dguest->domid, "Removed domain from the list of active guests");
+            /* Clear any leftovers in libxl/<domid> */
+            libxl__xs_rm_checked(gc, XBT_NULL,
+                                 GCSPRINTF("libxl/%u", dguest->domid));
+            free(dguest);
+        }
+    }
+
+    if (free_ao)
+        libxl__nested_ao_free(nested_ao);
+
+    return;
+
+skip:
+    libxl__nested_ao_free(nested_ao);
+    free(dev);
+    free(ddev);
+    free(dguest);
+    return;
+}
+
+/* Handler of events for device driver domains */
+int libxl_device_events_handler(libxl_ctx *ctx,
+                                const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, 0, ao_how);
+    int rc;
+    uint32_t domid;
+    libxl__ddomain ddomain;
+    char *be_path;
+    char **kinds = NULL, **domains = NULL, **devs = NULL;
+    const char *sstate;
+    char *state_path;
+    int state;
+    unsigned int nkinds, ndomains, ndevs;
+    int i, j, k;
+
+    ddomain.ao = ao;
+    LIBXL_SLIST_INIT(&ddomain.guests);
+
+    rc = libxl__get_domid(gc, &domid);
+    if (rc) {
+        LOG(ERROR, "unable to get domain id");
+        goto out;
+    }
+
+    /*
+     * We use absolute paths because we want xswatch to also return
+     * absolute paths that can be parsed by libxl__parse_backend_path.
+     */
+    be_path = GCSPRINTF("/local/domain/%u/backend", domid);
+    rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback,
+                                    be_path);
+    if (rc) goto out;
+
+    kinds = libxl__xs_directory(gc, XBT_NULL, be_path, &nkinds);
+    if (kinds) {
+        for (i = 0; i < nkinds; i++) {
+            domains = libxl__xs_directory(gc, XBT_NULL,
+                    GCSPRINTF("%s/%s", be_path, kinds[i]), &ndomains);
+            if (!domains)
+                continue;
+            for (j = 0; j < ndomains; j++) {
+                devs = libxl__xs_directory(gc, XBT_NULL,
+                        GCSPRINTF("%s/%s/%s", be_path, kinds[i], domains[j]), &ndevs);
+                if (!devs)
+                    continue;
+                for (k = 0; k < ndevs; k++) {
+                    state_path = GCSPRINTF("%s/%s/%s/%s/state",
+                            be_path, kinds[i], domains[j], devs[k]);
+                    rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, &sstate);
+                    if (rc || !sstate)
+                        continue;
+                    state = atoi(sstate);
+                    if (state == XenbusStateInitWait)
+                        backend_watch_callback(egc, &ddomain.watch,
+                                               be_path, state_path);
+                }
+            }
+        }
+    }
+
+    return AO_INPROGRESS;
+
+out:
+    return AO_CREATE_FAIL(rc);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 43456a9..292c480 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1199,7 +1199,6 @@ _hidden int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
 _hidden int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t,
         libxl__device *device, char **bents, char **fents, char **ro_fents);
 _hidden char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device);
-_hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device);
 _hidden char *libxl__device_libxl_path(libxl__gc *gc, libxl__device *device);
 _hidden int libxl__parse_backend_path(libxl__gc *gc, const char *path,
                                       libxl__device *dev);
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 8/9] libxl: carve out tmem specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (6 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 7/9] libxl: move device specific functions out of libxl.c Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 13:13 ` [PATCH 9/9] libxl: carve out domain " Juergen Gross
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the tmem
related functions to libxl_tmem.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile     |   2 +-
 tools/libxl/libxl.c      | 142 ----------------------------------------
 tools/libxl/libxl_tmem.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+), 143 deletions(-)
 create mode 100644 tools/libxl/libxl_tmem.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 4b05e34..99ddae1 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -137,7 +137,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_qmp.o libxl_event.o libxl_fork.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_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.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 d559991..9065c79 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2107,148 +2107,6 @@ uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
     return ret;
 }
 
-char *libxl_tmem_list(libxl_ctx *ctx, uint32_t domid, int use_long)
-{
-    int r;
-    char _buf[32768];
-    GC_INIT(ctx);
-
-    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_LIST, domid, 32768,
-                        use_long, _buf);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not get tmem list");
-        GC_FREE;
-        return NULL;
-    }
-
-    GC_FREE;
-    return strdup(_buf);
-}
-
-int libxl_tmem_freeze(libxl_ctx *ctx, uint32_t domid)
-{
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_FREEZE, domid, 0, 0,
-                        NULL);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not freeze tmem pools");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_tmem_thaw(libxl_ctx *ctx, uint32_t domid)
-{
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_THAW, domid, 0, 0,
-                        NULL);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not thaw tmem pools");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-static int32_t tmem_setop_from_string(char *set_name, uint32_t val,
-                                      xen_tmem_client_t *info)
-{
-    if (!strcmp(set_name, "weight"))
-        info->weight = val;
-    else if (!strcmp(set_name, "compress"))
-        info->flags.u.compress = val;
-    else
-        return -1;
-
-    return 0;
-}
-
-int libxl_tmem_set(libxl_ctx *ctx, uint32_t domid, char* name, uint32_t set)
-{
-    int r, rc;
-    xen_tmem_client_t info;
-    GC_INIT(ctx);
-
-    r = xc_tmem_control(ctx->xch, -1 /* pool_id */,
-                        XEN_SYSCTL_TMEM_OP_GET_CLIENT_INFO,
-                        domid, sizeof(info), 0 /* arg */, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not get tmem data!");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    rc = tmem_setop_from_string(name, set, &info);
-    if (rc == -1) {
-        LOGEVD(ERROR, -1, domid, "Invalid set, valid sets are <weight|compress>");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    r = xc_tmem_control(ctx->xch, -1 /* pool_id */,
-                        XEN_SYSCTL_TMEM_OP_SET_CLIENT_INFO,
-                        domid, sizeof(info), 0 /* arg */, &info);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not set tmem %s", name);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_tmem_shared_auth(libxl_ctx *ctx, uint32_t domid,
-                           char* uuid, int auth)
-{
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_tmem_auth(ctx->xch, domid, uuid, auth);
-    if (r < 0) {
-        LOGED(ERROR, domid, "Can not set tmem shared auth");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_tmem_freeable(libxl_ctx *ctx)
-{
-    int r, rc;
-    GC_INIT(ctx);
-
-    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_QUERY_FREEABLE_MB,
-                        -1, 0, 0, 0);
-    if (r < 0) {
-        LOGE(ERROR, "Can not get tmem freeable memory");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
 static int fd_set_flags(libxl_ctx *ctx, int fd,
                         int fcntlgetop, int fcntlsetop, const char *fl,
                         int flagmask, int set_p)
diff --git a/tools/libxl/libxl_tmem.c b/tools/libxl/libxl_tmem.c
new file mode 100644
index 0000000..2bee8d1
--- /dev/null
+++ b/tools/libxl/libxl_tmem.c
@@ -0,0 +1,167 @@
+/*
+ * 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"
+
+char *libxl_tmem_list(libxl_ctx *ctx, uint32_t domid, int use_long)
+{
+    int r;
+    char _buf[32768];
+    GC_INIT(ctx);
+
+    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_LIST, domid, 32768,
+                        use_long, _buf);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not get tmem list");
+        GC_FREE;
+        return NULL;
+    }
+
+    GC_FREE;
+    return strdup(_buf);
+}
+
+int libxl_tmem_freeze(libxl_ctx *ctx, uint32_t domid)
+{
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_FREEZE, domid, 0, 0,
+                        NULL);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not freeze tmem pools");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_tmem_thaw(libxl_ctx *ctx, uint32_t domid)
+{
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_THAW, domid, 0, 0,
+                        NULL);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not thaw tmem pools");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+static int32_t tmem_setop_from_string(char *set_name, uint32_t val,
+                                      xen_tmem_client_t *info)
+{
+    if (!strcmp(set_name, "weight"))
+        info->weight = val;
+    else if (!strcmp(set_name, "compress"))
+        info->flags.u.compress = val;
+    else
+        return -1;
+
+    return 0;
+}
+
+int libxl_tmem_set(libxl_ctx *ctx, uint32_t domid, char* name, uint32_t set)
+{
+    int r, rc;
+    xen_tmem_client_t info;
+    GC_INIT(ctx);
+
+    r = xc_tmem_control(ctx->xch, -1 /* pool_id */,
+                        XEN_SYSCTL_TMEM_OP_GET_CLIENT_INFO,
+                        domid, sizeof(info), 0 /* arg */, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not get tmem data!");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = tmem_setop_from_string(name, set, &info);
+    if (rc == -1) {
+        LOGEVD(ERROR, -1, domid, "Invalid set, valid sets are <weight|compress>");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    r = xc_tmem_control(ctx->xch, -1 /* pool_id */,
+                        XEN_SYSCTL_TMEM_OP_SET_CLIENT_INFO,
+                        domid, sizeof(info), 0 /* arg */, &info);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not set tmem %s", name);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_tmem_shared_auth(libxl_ctx *ctx, uint32_t domid,
+                           char* uuid, int auth)
+{
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_tmem_auth(ctx->xch, domid, uuid, auth);
+    if (r < 0) {
+        LOGED(ERROR, domid, "Can not set tmem shared auth");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_tmem_freeable(libxl_ctx *ctx)
+{
+    int r, rc;
+    GC_INIT(ctx);
+
+    r = xc_tmem_control(ctx->xch, -1, XEN_SYSCTL_TMEM_OP_QUERY_FREEABLE_MB,
+                        -1, 0, 0, 0);
+    if (r < 0) {
+        LOGE(ERROR, "Can not get tmem freeable memory");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 9/9] libxl: carve out domain specific functions from libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (7 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 8/9] libxl: carve out tmem specific functions from libxl.c Juergen Gross
@ 2017-02-08 13:13 ` Juergen Gross
  2017-02-08 14:33 ` [PATCH 0/9] libxl: spolit up libxl.c Ian Jackson
  2017-02-08 14:35 ` Wei Liu
  10 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 13:13 UTC (permalink / raw)
  To: xen-devel; +Cc: Juergen Gross, wei.liu2, ian.jackson, haozhong.zhang

libxl.c has grown to an uncomfortable size. Carve out the domain
related functions to libxl_domain.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/Makefile       |    1 +
 tools/libxl/libxl.c        | 1724 -------------------------------------------
 tools/libxl/libxl_domain.c | 1744 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1745 insertions(+), 1724 deletions(-)
 create mode 100644 tools/libxl/libxl_domain.c

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 9065c79..f8cc065 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)
 {
@@ -353,1190 +351,6 @@ const char *libxl_defbool_to_string(libxl_defbool b)
 }
 
 /******************************************************************************/
-
-
-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 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++) {
-            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)
-        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) {
-        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);
-        }
-    }
-    LOGD(DEBUG, domid, "Forked pid %ld for destroy of domain", (long)rc);
-
-    return;
-
-out:
-    dis->callback(egc, dis, rc);
-    return;
-}
-
-static void domain_destroy_domid_cb(libxl__egc *egc,
-                                    libxl__ev_child *destroyer,
-                                    pid_t pid, int status)
-{
-    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);
-}
-
-int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
-{
-    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;
-    }
-
-    *domid = atoi(xs_domid);
-
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
-{
-    if (!name)
-        return 0;
-    return libxl_domain_qualifier_to_domid(CTX, name, domid);
-}
-
-/******************************************************************************/
 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
 {
     xc_physinfo_t xcphysinfo = { 0 };
@@ -1812,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);
@@ -2086,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)
@@ -2214,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..9102f40
--- /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 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++) {
+            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)
+        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) {
+        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);
+        }
+    }
+    LOGD(DEBUG, domid, "Forked pid %ld for destroy of domain", (long)rc);
+
+    return;
+
+out:
+    dis->callback(egc, dis, rc);
+    return;
+}
+
+static void domain_destroy_domid_cb(libxl__egc *egc,
+                                    libxl__ev_child *destroyer,
+                                    pid_t pid, int status)
+{
+    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);
+}
+
+int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
+{
+    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;
+    }
+
+    *domid = atoi(xs_domid);
+
+out:
+    return rc;
+}
+
+int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
+{
+    if (!name)
+        return 0;
+    return libxl_domain_qualifier_to_domid(CTX, name, domid);
+}
+
+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;
+}
+
+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;
+}
+
+/* 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
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (8 preceding siblings ...)
  2017-02-08 13:13 ` [PATCH 9/9] libxl: carve out domain " Juergen Gross
@ 2017-02-08 14:33 ` Ian Jackson
  2017-02-08 14:54   ` Juergen Gross
  2017-02-08 14:35 ` Wei Liu
  10 siblings, 1 reply; 19+ messages in thread
From: Ian Jackson @ 2017-02-08 14:33 UTC (permalink / raw)
  To: Juergen Gross; +Cc: xen-devel, wei.liu2, haozhong.zhang

Juergen Gross writes ("[PATCH 0/9] libxl: spolit up libxl.c"):
> Code movement only. No functional change intended.

This statement is not true because

> Juergen Gross (9):
>   libxl: adjust copyright comment of libxl.c

... that patch is not just code motion.

Can you please double-check, and explicitly enumerate the other
intentional changes ?  Obviously there is an intentional change to the
Makefile, and the copyright header is duplicated in each case.

Are there any other changes which are not precisely moving a block of
lines from libxl.c into other file(s), completely unchanged ?

Did you have to make any functions non-static ?

Thanks,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
                   ` (9 preceding siblings ...)
  2017-02-08 14:33 ` [PATCH 0/9] libxl: spolit up libxl.c Ian Jackson
@ 2017-02-08 14:35 ` Wei Liu
  2017-02-08 16:54   ` Wei Liu
  2017-02-09  1:12   ` Haozhong Zhang
  10 siblings, 2 replies; 19+ messages in thread
From: Wei Liu @ 2017-02-08 14:35 UTC (permalink / raw)
  To: Juergen Gross; +Cc: xen-devel, ian.jackson, wei.liu2, yi.y.sun, haozhong.zhang

Cc Yi Sun as well.

Haozhong and Yi: This is just a heads-up -- Juergen from SuSE took the
time to split libxl.c so things are better organised. It's likely this
series will go in before yours, so you will then need to rebase your
series. I don't expect there to be much breakage because it is all
mechanical, but rebasing is still work for you.

Let us know if you have any concern so that we can coordinate this.

Wei.

On Wed, Feb 08, 2017 at 02:13:37PM +0100, Juergen Gross wrote:
> libxl.c has become rather large. Split it up into multiple files.
> 
> Code movement only. No functional change intended.
> 
> Juergen Gross (9):
>   libxl: adjust copyright comment of libxl.c
>   libxl: carve out cpupool specific functions from libxl.c
>   libxl: carve out scheduler specific functions from libxl.c
>   libxl: carve out disk specific functions from libxl.c
>   libxl: carve out console specific functions from libxl.c
>   libxl: carve out memory specific functions from libxl.c
>   libxl: move device specific functions out of libxl.c
>   libxl: carve out tmem specific functions from libxl.c
>   libxl: carve out domain specific functions from libxl.c
> 
>  tools/libxl/Makefile         |    4 +-
>  tools/libxl/libxl.c          | 6252 +-----------------------------------------
>  tools/libxl/libxl_console.c  |  862 ++++++
>  tools/libxl/libxl_cpupool.c  |  443 +++
>  tools/libxl/libxl_device.c   |  435 ++-
>  tools/libxl/libxl_disk.c     | 1258 +++++++++
>  tools/libxl/libxl_domain.c   | 1744 ++++++++++++
>  tools/libxl/libxl_internal.h |    8 +-
>  tools/libxl/libxl_mem.c      |  601 ++++
>  tools/libxl/libxl_sched.c    |  915 +++++++
>  tools/libxl/libxl_tmem.c     |  167 ++
>  11 files changed, 6424 insertions(+), 6265 deletions(-)
>  create mode 100644 tools/libxl/libxl_console.c
>  create mode 100644 tools/libxl/libxl_cpupool.c
>  create mode 100644 tools/libxl/libxl_disk.c
>  create mode 100644 tools/libxl/libxl_domain.c
>  create mode 100644 tools/libxl/libxl_mem.c
>  create mode 100644 tools/libxl/libxl_sched.c
>  create mode 100644 tools/libxl/libxl_tmem.c
> 
> -- 
> 2.10.2
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 14:33 ` [PATCH 0/9] libxl: spolit up libxl.c Ian Jackson
@ 2017-02-08 14:54   ` Juergen Gross
  2017-02-08 16:12     ` Ian Jackson
  0 siblings, 1 reply; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 14:54 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, wei.liu2, haozhong.zhang

On 08/02/17 15:33, Ian Jackson wrote:
> Juergen Gross writes ("[PATCH 0/9] libxl: spolit up libxl.c"):
>> Code movement only. No functional change intended.
> 
> This statement is not true because
> 
>> Juergen Gross (9):
>>   libxl: adjust copyright comment of libxl.c
> 
> ... that patch is not just code motion.

Okay, more precise wording:

Changes are:
- moving functions into new or existing sources
- modification of Copyright comment
- made two functions non-static: libxl__get_memory_target(),
  xcinfo2xlinfo()
- made one function static: libxl__device_frontend_path()
- modified Makefile to include new source files
- removed some trailing spaces in moved code
- reordered some functions in new sources to get rid of some local
  prototypes

> Can you please double-check, and explicitly enumerate the other
> intentional changes ?  Obviously there is an intentional change to the
> Makefile, and the copyright header is duplicated in each case.
> 
> Are there any other changes which are not precisely moving a block of
> lines from libxl.c into other file(s), completely unchanged ?
> 
> Did you have to make any functions non-static ?


Juergen


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 14:54   ` Juergen Gross
@ 2017-02-08 16:12     ` Ian Jackson
  2017-02-08 16:28       ` Juergen Gross
  0 siblings, 1 reply; 19+ messages in thread
From: Ian Jackson @ 2017-02-08 16:12 UTC (permalink / raw)
  To: Juergen Gross; +Cc: xen-devel, wei.liu2, haozhong.zhang

Juergen Gross writes ("Re: [PATCH 0/9] libxl: spolit up libxl.c"):
> Okay, more precise wording:

Thanks.

> Changes are:
> - moving functions into new or existing sources
> - modification of Copyright comment

> - made two functions non-static: libxl__get_memory_target(),
>   xcinfo2xlinfo()
> - made one function static: libxl__device_frontend_path()

Can you split these out into their own patch(es) ?

> - removed some trailing spaces in moved code

And split this one out too ?

Sorry to be pernickety, but this will make it much easier to check
what you have done automatically, without trying read the whole thing
by eye !

Thanks,
Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 16:12     ` Ian Jackson
@ 2017-02-08 16:28       ` Juergen Gross
  0 siblings, 0 replies; 19+ messages in thread
From: Juergen Gross @ 2017-02-08 16:28 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, wei.liu2, haozhong.zhang

On 08/02/17 17:12, Ian Jackson wrote:
> Juergen Gross writes ("Re: [PATCH 0/9] libxl: spolit up libxl.c"):
>> Okay, more precise wording:
> 
> Thanks.
> 
>> Changes are:
>> - moving functions into new or existing sources
>> - modification of Copyright comment
> 
>> - made two functions non-static: libxl__get_memory_target(),
>>   xcinfo2xlinfo()
>> - made one function static: libxl__device_frontend_path()
> 
> Can you split these out into their own patch(es) ?
> 
>> - removed some trailing spaces in moved code
> 
> And split this one out too ?
> 
> Sorry to be pernickety, but this will make it much easier to check
> what you have done automatically, without trying read the whole thing
> by eye !

Okay.


Juergen


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 14:35 ` Wei Liu
@ 2017-02-08 16:54   ` Wei Liu
  2017-02-09  1:51     ` Zhang Chen
  2017-02-09  1:12   ` Haozhong Zhang
  1 sibling, 1 reply; 19+ messages in thread
From: Wei Liu @ 2017-02-08 16:54 UTC (permalink / raw)
  To: Juergen Gross
  Cc: haozhong.zhang, wei.liu2, zhangchen.fnst, ian.jackson, yi.y.sun,
	xen-devel

And CC Zhangchen

On Wed, Feb 08, 2017 at 02:35:27PM +0000, Wei Liu wrote:
> Cc Yi Sun as well.
> 
> Haozhong and Yi: This is just a heads-up -- Juergen from SuSE took the
> time to split libxl.c so things are better organised. It's likely this
> series will go in before yours, so you will then need to rebase your
> series. I don't expect there to be much breakage because it is all
> mechanical, but rebasing is still work for you.
> 
> Let us know if you have any concern so that we can coordinate this.
> 
> Wei.
> 
> On Wed, Feb 08, 2017 at 02:13:37PM +0100, Juergen Gross wrote:
> > libxl.c has become rather large. Split it up into multiple files.
> > 
> > Code movement only. No functional change intended.
> > 
> > Juergen Gross (9):
> >   libxl: adjust copyright comment of libxl.c
> >   libxl: carve out cpupool specific functions from libxl.c
> >   libxl: carve out scheduler specific functions from libxl.c
> >   libxl: carve out disk specific functions from libxl.c
> >   libxl: carve out console specific functions from libxl.c
> >   libxl: carve out memory specific functions from libxl.c
> >   libxl: move device specific functions out of libxl.c
> >   libxl: carve out tmem specific functions from libxl.c
> >   libxl: carve out domain specific functions from libxl.c
> > 
> >  tools/libxl/Makefile         |    4 +-
> >  tools/libxl/libxl.c          | 6252 +-----------------------------------------
> >  tools/libxl/libxl_console.c  |  862 ++++++
> >  tools/libxl/libxl_cpupool.c  |  443 +++
> >  tools/libxl/libxl_device.c   |  435 ++-
> >  tools/libxl/libxl_disk.c     | 1258 +++++++++
> >  tools/libxl/libxl_domain.c   | 1744 ++++++++++++
> >  tools/libxl/libxl_internal.h |    8 +-
> >  tools/libxl/libxl_mem.c      |  601 ++++
> >  tools/libxl/libxl_sched.c    |  915 +++++++
> >  tools/libxl/libxl_tmem.c     |  167 ++
> >  11 files changed, 6424 insertions(+), 6265 deletions(-)
> >  create mode 100644 tools/libxl/libxl_console.c
> >  create mode 100644 tools/libxl/libxl_cpupool.c
> >  create mode 100644 tools/libxl/libxl_disk.c
> >  create mode 100644 tools/libxl/libxl_domain.c
> >  create mode 100644 tools/libxl/libxl_mem.c
> >  create mode 100644 tools/libxl/libxl_sched.c
> >  create mode 100644 tools/libxl/libxl_tmem.c
> > 
> > -- 
> > 2.10.2
> > 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 14:35 ` Wei Liu
  2017-02-08 16:54   ` Wei Liu
@ 2017-02-09  1:12   ` Haozhong Zhang
  1 sibling, 0 replies; 19+ messages in thread
From: Haozhong Zhang @ 2017-02-09  1:12 UTC (permalink / raw)
  To: Wei Liu; +Cc: Juergen Gross, xen-devel, ian.jackson, yi.y.sun

On 02/08/17 14:35 +0000, Wei Liu wrote:
>Cc Yi Sun as well.
>
>Haozhong and Yi: This is just a heads-up -- Juergen from SuSE took the
>time to split libxl.c so things are better organised. It's likely this
>series will go in before yours, so you will then need to rebase your
>series. I don't expect there to be much breakage because it is all
>mechanical, but rebasing is still work for you.
>

Thank you for the remind. As this series does not introduce functional
changes and most of libxl changes for NVDIMM already went into a
separate libxl_nvdimm.c in my patches, the rebase should be trivial
for me.

Haozhong

>Let us know if you have any concern so that we can coordinate this.
>
>Wei.
>
>On Wed, Feb 08, 2017 at 02:13:37PM +0100, Juergen Gross wrote:
>> libxl.c has become rather large. Split it up into multiple files.
>>
>> Code movement only. No functional change intended.
>>
>> Juergen Gross (9):
>>   libxl: adjust copyright comment of libxl.c
>>   libxl: carve out cpupool specific functions from libxl.c
>>   libxl: carve out scheduler specific functions from libxl.c
>>   libxl: carve out disk specific functions from libxl.c
>>   libxl: carve out console specific functions from libxl.c
>>   libxl: carve out memory specific functions from libxl.c
>>   libxl: move device specific functions out of libxl.c
>>   libxl: carve out tmem specific functions from libxl.c
>>   libxl: carve out domain specific functions from libxl.c
>>
>>  tools/libxl/Makefile         |    4 +-
>>  tools/libxl/libxl.c          | 6252 +-----------------------------------------
>>  tools/libxl/libxl_console.c  |  862 ++++++
>>  tools/libxl/libxl_cpupool.c  |  443 +++
>>  tools/libxl/libxl_device.c   |  435 ++-
>>  tools/libxl/libxl_disk.c     | 1258 +++++++++
>>  tools/libxl/libxl_domain.c   | 1744 ++++++++++++
>>  tools/libxl/libxl_internal.h |    8 +-
>>  tools/libxl/libxl_mem.c      |  601 ++++
>>  tools/libxl/libxl_sched.c    |  915 +++++++
>>  tools/libxl/libxl_tmem.c     |  167 ++
>>  11 files changed, 6424 insertions(+), 6265 deletions(-)
>>  create mode 100644 tools/libxl/libxl_console.c
>>  create mode 100644 tools/libxl/libxl_cpupool.c
>>  create mode 100644 tools/libxl/libxl_disk.c
>>  create mode 100644 tools/libxl/libxl_domain.c
>>  create mode 100644 tools/libxl/libxl_mem.c
>>  create mode 100644 tools/libxl/libxl_sched.c
>>  create mode 100644 tools/libxl/libxl_tmem.c
>>
>> --
>> 2.10.2
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-08 16:54   ` Wei Liu
@ 2017-02-09  1:51     ` Zhang Chen
  2017-02-09  9:36       ` Wei Liu
  0 siblings, 1 reply; 19+ messages in thread
From: Zhang Chen @ 2017-02-09  1:51 UTC (permalink / raw)
  To: Wei Liu, Juergen Gross; +Cc: xen-devel, ian.jackson, yi.y.sun, haozhong.zhang



On 02/09/2017 12:54 AM, Wei Liu wrote:
> And CC Zhangchen

Thanks, I will apply this patch set before test my patch.


Zhang Chen

>
> On Wed, Feb 08, 2017 at 02:35:27PM +0000, Wei Liu wrote:
>> Cc Yi Sun as well.
>>
>> Haozhong and Yi: This is just a heads-up -- Juergen from SuSE took the
>> time to split libxl.c so things are better organised. It's likely this
>> series will go in before yours, so you will then need to rebase your
>> series. I don't expect there to be much breakage because it is all
>> mechanical, but rebasing is still work for you.
>>
>> Let us know if you have any concern so that we can coordinate this.
>>
>> Wei.
>>
>> On Wed, Feb 08, 2017 at 02:13:37PM +0100, Juergen Gross wrote:
>>> libxl.c has become rather large. Split it up into multiple files.
>>>
>>> Code movement only. No functional change intended.
>>>
>>> Juergen Gross (9):
>>>    libxl: adjust copyright comment of libxl.c
>>>    libxl: carve out cpupool specific functions from libxl.c
>>>    libxl: carve out scheduler specific functions from libxl.c
>>>    libxl: carve out disk specific functions from libxl.c
>>>    libxl: carve out console specific functions from libxl.c
>>>    libxl: carve out memory specific functions from libxl.c
>>>    libxl: move device specific functions out of libxl.c
>>>    libxl: carve out tmem specific functions from libxl.c
>>>    libxl: carve out domain specific functions from libxl.c
>>>
>>>   tools/libxl/Makefile         |    4 +-
>>>   tools/libxl/libxl.c          | 6252 +-----------------------------------------
>>>   tools/libxl/libxl_console.c  |  862 ++++++
>>>   tools/libxl/libxl_cpupool.c  |  443 +++
>>>   tools/libxl/libxl_device.c   |  435 ++-
>>>   tools/libxl/libxl_disk.c     | 1258 +++++++++
>>>   tools/libxl/libxl_domain.c   | 1744 ++++++++++++
>>>   tools/libxl/libxl_internal.h |    8 +-
>>>   tools/libxl/libxl_mem.c      |  601 ++++
>>>   tools/libxl/libxl_sched.c    |  915 +++++++
>>>   tools/libxl/libxl_tmem.c     |  167 ++
>>>   11 files changed, 6424 insertions(+), 6265 deletions(-)
>>>   create mode 100644 tools/libxl/libxl_console.c
>>>   create mode 100644 tools/libxl/libxl_cpupool.c
>>>   create mode 100644 tools/libxl/libxl_disk.c
>>>   create mode 100644 tools/libxl/libxl_domain.c
>>>   create mode 100644 tools/libxl/libxl_mem.c
>>>   create mode 100644 tools/libxl/libxl_sched.c
>>>   create mode 100644 tools/libxl/libxl_tmem.c
>>>
>>> -- 
>>> 2.10.2
>>>
>
> .
>

-- 
Thanks
Zhang Chen




_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/9] libxl: spolit up libxl.c
  2017-02-09  1:51     ` Zhang Chen
@ 2017-02-09  9:36       ` Wei Liu
  0 siblings, 0 replies; 19+ messages in thread
From: Wei Liu @ 2017-02-09  9:36 UTC (permalink / raw)
  To: Zhang Chen
  Cc: Juergen Gross, haozhong.zhang, Wei Liu, ian.jackson, yi.y.sun, xen-devel

On Thu, Feb 09, 2017 at 09:51:48AM +0800, Zhang Chen wrote:
> 
> 
> On 02/09/2017 12:54 AM, Wei Liu wrote:
> > And CC Zhangchen
> 
> Thanks, I will apply this patch set before test my patch.
> 

This is not yet the final form. Please need to wait until this work gets
applied.

Wei.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2017-02-09  9:36 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-08 13:13 [PATCH 0/9] libxl: spolit up libxl.c Juergen Gross
2017-02-08 13:13 ` [PATCH 1/9] libxl: adjust copyright comment of libxl.c Juergen Gross
2017-02-08 13:13 ` [PATCH 2/9] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
2017-02-08 13:13 ` [PATCH 3/9] libxl: carve out scheduler " Juergen Gross
2017-02-08 13:13 ` [PATCH 4/9] libxl: carve out disk " Juergen Gross
2017-02-08 13:13 ` [PATCH 5/9] libxl: carve out console " Juergen Gross
2017-02-08 13:13 ` [PATCH 6/9] libxl: carve out memory " Juergen Gross
2017-02-08 13:13 ` [PATCH 7/9] libxl: move device specific functions out of libxl.c Juergen Gross
2017-02-08 13:13 ` [PATCH 8/9] libxl: carve out tmem specific functions from libxl.c Juergen Gross
2017-02-08 13:13 ` [PATCH 9/9] libxl: carve out domain " Juergen Gross
2017-02-08 14:33 ` [PATCH 0/9] libxl: spolit up libxl.c Ian Jackson
2017-02-08 14:54   ` Juergen Gross
2017-02-08 16:12     ` Ian Jackson
2017-02-08 16:28       ` Juergen Gross
2017-02-08 14:35 ` Wei Liu
2017-02-08 16:54   ` Wei Liu
2017-02-09  1:51     ` Zhang Chen
2017-02-09  9:36       ` Wei Liu
2017-02-09  1:12   ` Haozhong Zhang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.