All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/12] libxl: split up libxl.c
@ 2017-02-09  9:30 Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
                   ` (13 more replies)
  0 siblings, 14 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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

Changes are:
- modification of Copyright comment (patch 1)
- made two functions non-static: libxl__get_memory_target(),
  xcinfo2xlinfo() (patch 2)
- white space cleanup of libxl.c (patch 3)
- moving functions into new or existing sources (patches 4-11):
  just code movement, no functional changes besides needed Makefile
  adjustments for new sources
- made one function static: libxl__device_frontend_path() (patch 12)

Changes in V2:
- address comments of Ian Jackson: add new patches 1-3, 12

Juergen Gross (12):
  libxl: adjust copyright comment of libxl.c
  libxl: make some functions global to prepare splitting up libxl.c
  libxl: white space cleanup
  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
  libxl: make one function static

 tools/libxl/Makefile         |    4 +-
 tools/libxl/libxl.c          | 6254 +-----------------------------------------
 tools/libxl/libxl_console.c  |  862 ++++++
 tools/libxl/libxl_cpupool.c  |  443 +++
 tools/libxl/libxl_device.c   |  416 ++-
 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, 6417 insertions(+), 6255 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] 23+ messages in thread

* [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09 10:18   ` Wei Liu
  2017-02-09 11:37   ` Ian Jackson
  2017-02-09  9:30 ` [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c Juergen Gross
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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] 23+ messages in thread

* [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09 11:36   ` Ian Jackson
  2017-02-09  9:30 ` [PATCH v2 03/12] libxl: white space cleanup Juergen Gross
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

Splitting up libxl.c will require two functions to be globally visible.
Add their prototypes to libxl_internal.h.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/libxl.c          | 12 ++++++------
 tools/libxl/libxl_internal.h |  7 +++++++
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 0641a8a..ea66149 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -594,9 +594,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;
 
@@ -4342,9 +4342,9 @@ out_no_transaction:
 }
 
 /* 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 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;
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index a093bc6..b880801 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -4246,6 +4246,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)
-- 
2.10.2


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

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

* [PATCH v2 03/12] libxl: white space cleanup
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09 11:37   ` Ian Jackson
  2017-02-09  9:30 ` [PATCH v2 04/12] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

Before moving code to new sources clean up some white space issues in
libxl.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/libxl.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index ea66149..6b87f48 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -72,7 +72,7 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version,
 
     ctx->childproc_hooks = &libxl__childproc_default_hooks;
     ctx->childproc_user = 0;
-        
+
     ctx->sigchld_selfpipe[0] = -1;
     ctx->sigchld_selfpipe[1] = -1;
     libxl__ev_fd_init(&ctx->sigchld_selfpipe_efd);
@@ -355,8 +355,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)
@@ -1242,7 +1240,7 @@ int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid,
     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; }
@@ -1315,7 +1313,7 @@ static void disk_eject_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch *w,
 
     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",
@@ -1425,7 +1423,7 @@ 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 */
 
@@ -2515,7 +2513,6 @@ out:
     return rc;
 }
 
-
 static int libxl__append_disk_list(libxl__gc *gc,
                                            uint32_t domid,
                                            libxl_device_disk **disks,
@@ -2862,7 +2859,7 @@ static char * libxl__alloc_vdev(libxl__gc *gc, void *get_vdev_user,
 
 /* Callbacks */
 
-char *libxl__device_disk_find_local_path(libxl__gc *gc, 
+char *libxl__device_disk_find_local_path(libxl__gc *gc,
                                           libxl_domid guest_domid,
                                           const libxl_device_disk *disk,
                                           bool qdisk_direct)
@@ -2884,7 +2881,7 @@ char *libxl__device_disk_find_local_path(libxl__gc *gc,
         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
@@ -2894,9 +2891,9 @@ char *libxl__device_disk_find_local_path(libxl__gc *gc,
         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
      */
@@ -2965,7 +2962,7 @@ void libxl__device_disk_local_initiate_attach(libxl__egc *egc,
         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;
 
@@ -3042,7 +3039,7 @@ void libxl__device_disk_local_initiate_detach(libxl__egc *egc,
         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;
-- 
2.10.2


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

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

* [PATCH v2 04/12] libxl: carve out cpupool specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (2 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 03/12] libxl: white space cleanup Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 05/12] libxl: carve out scheduler " Juergen Gross
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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 6b87f48..d0080ca 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -683,100 +683,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)
@@ -6253,330 +6159,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] 23+ messages in thread

* [PATCH v2 05/12] libxl: carve out scheduler specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (3 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 04/12] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 06/12] libxl: carve out disk " Juergen Gross
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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 d0080ca..ae6c7d4 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -4830,146 +4830,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)
@@ -5085,757 +4945,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] 23+ messages in thread

* [PATCH v2 06/12] libxl: carve out disk specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (4 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 05/12] libxl: carve out scheduler " Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 07/12] libxl: carve out console " Juergen Gross
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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      | 1233 ---------------------------------------------
 tools/libxl/libxl_disk.c | 1258 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1259 insertions(+), 1234 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 ae6c7d4..3f8f16e 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)
@@ -1197,140 +1196,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,
@@ -1948,1044 +1813,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,
@@ -3520,10 +2347,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
@@ -3534,11 +2357,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)
 
@@ -5644,57 +4462,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] 23+ messages in thread

* [PATCH v2 07/12] libxl: carve out console specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (5 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 06/12] libxl: carve out disk " Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 08/12] libxl: carve out memory " Juergen Gross
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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 3f8f16e..20ae61a 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1507,239 +1507,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;
@@ -1813,557 +1580,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
@@ -3861,68 +3077,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] 23+ messages in thread

* [PATCH v2 08/12] libxl: carve out memory specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (6 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 07/12] libxl: carve out console " Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 09/12] libxl: move device specific functions out of libxl.c Juergen Gross
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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     | 577 ----------------------------------------------
 tools/libxl/libxl_mem.c | 601 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 602 insertions(+), 578 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 20ae61a..f9aad9b 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)
 
@@ -1952,582 +1951,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 */
-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_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] 23+ messages in thread

* [PATCH v2 09/12] libxl: move device specific functions out of libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (7 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 08/12] libxl: carve out memory " Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 10/12] libxl: carve out tmem specific functions from libxl.c Juergen Gross
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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 | 414 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 414 insertions(+), 416 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index f9aad9b..3cf4a56 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1527,50 +1527,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)
@@ -1579,378 +1535,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..c72a2b8 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -1362,6 +1362,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
-- 
2.10.2


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

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

* [PATCH v2 10/12] libxl: carve out tmem specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (8 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 09/12] libxl: move device specific functions out of libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 11/12] libxl: carve out domain " Juergen Gross
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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 3cf4a56..67c0a13 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2105,148 +2105,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] 23+ messages in thread

* [PATCH v2 11/12] libxl: carve out domain specific functions from libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (9 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 10/12] libxl: carve out tmem specific functions from libxl.c Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09  9:30 ` [PATCH v2 12/12] libxl: make one function static Juergen Gross
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

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        | 1722 -------------------------------------------
 tools/libxl/libxl_domain.c | 1744 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1745 insertions(+), 1722 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 67c0a13..0ef8744 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -16,8 +16,6 @@
 
 #include "libxl_internal.h"
 
-#define PAGE_TO_MEMKB(pages) ((pages) * 4)
-
 int libxl_ctx_alloc(libxl_ctx **pctx, int version,
                     unsigned flags, xentoollog_logger * lg)
 {
@@ -353,1188 +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 };
@@ -1810,254 +626,6 @@ const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx)
     return info;
 }
 
-libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
-                                       int *nr_vcpus_out, int *nr_cpus_out)
-{
-    GC_INIT(ctx);
-    libxl_vcpuinfo *ptr, *ret;
-    xc_domaininfo_t domaininfo;
-    xc_vcpuinfo_t vcpuinfo;
-
-    if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
-        LOGED(ERROR, domid, "Getting infolist");
-        GC_FREE;
-        return NULL;
-    }
-
-    if (domaininfo.max_vcpu_id == XEN_INVALID_MAX_VCPU_ID) {
-        GC_FREE;
-        return NULL;
-    }
-
-    *nr_cpus_out = libxl_get_max_cpus(ctx);
-    ret = ptr = libxl__calloc(NOGC, domaininfo.max_vcpu_id + 1,
-                              sizeof(libxl_vcpuinfo));
-
-    for (*nr_vcpus_out = 0;
-         *nr_vcpus_out <= domaininfo.max_vcpu_id;
-         ++*nr_vcpus_out, ++ptr) {
-        libxl_bitmap_init(&ptr->cpumap);
-        if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap, 0))
-            goto err;
-        libxl_bitmap_init(&ptr->cpumap_soft);
-        if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap_soft, 0))
-            goto err;
-        if (xc_vcpu_getinfo(ctx->xch, domid, *nr_vcpus_out, &vcpuinfo) == -1) {
-            LOGED(ERROR, domid, "Getting vcpu info");
-            goto err;
-        }
-
-        if (xc_vcpu_getaffinity(ctx->xch, domid, *nr_vcpus_out,
-                                ptr->cpumap.map, ptr->cpumap_soft.map,
-                                XEN_VCPUAFFINITY_SOFT|XEN_VCPUAFFINITY_HARD) == -1) {
-            LOGED(ERROR, domid, "Getting vcpu affinity");
-            goto err;
-        }
-        ptr->vcpuid = *nr_vcpus_out;
-        ptr->cpu = vcpuinfo.cpu;
-        ptr->online = !!vcpuinfo.online;
-        ptr->blocked = !!vcpuinfo.blocked;
-        ptr->running = !!vcpuinfo.running;
-        ptr->vcpu_time = vcpuinfo.cpu_time;
-    }
-    GC_FREE;
-    return ret;
-
-err:
-    libxl_bitmap_dispose(&ptr->cpumap);
-    libxl_bitmap_dispose(&ptr->cpumap_soft);
-    free(ret);
-    GC_FREE;
-    return NULL;
-}
-
-static int libxl__set_vcpuonline_xenstore(libxl__gc *gc, uint32_t domid,
-                                         libxl_bitmap *cpumap,
-                                         const libxl_dominfo *info)
-{
-    char *dompath;
-    xs_transaction_t t;
-    int i, rc = ERROR_FAIL;
-
-    if (!(dompath = libxl__xs_get_dompath(gc, domid)))
-        goto out;
-
-retry_transaction:
-    t = xs_transaction_start(CTX->xsh);
-    for (i = 0; i <= info->vcpu_max_id; i++)
-        libxl__xs_printf(gc, t,
-                         GCSPRINTF("%s/cpu/%u/availability", dompath, i),
-                         "%s", libxl_bitmap_test(cpumap, i) ? "online" : "offline");
-    if (!xs_transaction_end(CTX->xsh, t, 0)) {
-        if (errno == EAGAIN)
-            goto retry_transaction;
-    } else
-        rc = 0;
-out:
-    return rc;
-}
-
-static int libxl__set_vcpuonline_qmp(libxl__gc *gc, uint32_t domid,
-                                     libxl_bitmap *cpumap,
-                                     const libxl_dominfo *info)
-{
-    int i, rc;
-    libxl_bitmap current_map, final_map;
-
-    libxl_bitmap_init(&current_map);
-    libxl_bitmap_init(&final_map);
-
-    libxl_bitmap_alloc(CTX, &current_map, info->vcpu_max_id + 1);
-    libxl_bitmap_set_none(&current_map);
-    rc = libxl__qmp_query_cpus(gc, domid, &current_map);
-    if (rc) {
-        LOGD(ERROR, domid, "Failed to query cpus");
-        goto out;
-    }
-
-    libxl_bitmap_copy_alloc(CTX, &final_map, cpumap);
-
-    libxl_for_each_set_bit(i, current_map)
-        libxl_bitmap_reset(&final_map, i);
-
-    libxl_for_each_set_bit(i, final_map) {
-        rc = libxl__qmp_cpu_add(gc, domid, i);
-        if (rc) {
-            LOGD(ERROR, domid, "Failed to add cpu %d", i);
-            goto out;
-        }
-    }
-
-    rc = 0;
-out:
-    libxl_bitmap_dispose(&current_map);
-    libxl_bitmap_dispose(&final_map);
-    return rc;
-}
-
-int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *cpumap)
-{
-    GC_INIT(ctx);
-    int rc, maxcpus;
-    libxl_dominfo info;
-
-    libxl_dominfo_init(&info);
-
-    rc = libxl_domain_info(CTX, &info, domid);
-    if (rc < 0) {
-        LOGED(ERROR, domid, "Getting domain info list");
-        goto out;
-    }
-
-    maxcpus = libxl_bitmap_count_set(cpumap);
-    if (maxcpus > info.vcpu_max_id + 1)
-    {
-        LOGED(ERROR, domid, "Requested %d VCPUs, however maxcpus is %d!",
-              maxcpus, info.vcpu_max_id + 1);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        switch (libxl__device_model_version_running(gc, domid)) {
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-        case LIBXL_DEVICE_MODEL_VERSION_NONE:
-            break;
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-            rc = libxl__set_vcpuonline_qmp(gc, domid, cpumap, &info);
-            break;
-        default:
-            rc = ERROR_INVAL;
-        }
-        break;
-    case LIBXL_DOMAIN_TYPE_PV:
-        break;
-    default:
-        rc = ERROR_INVAL;
-    }
-
-    if (!rc)
-        rc = libxl__set_vcpuonline_xenstore(gc, domid, cpumap, &info);
-
-out:
-    libxl_dominfo_dispose(&info);
-    GC_FREE;
-    return rc;
-}
-
-static int libxl__domain_s3_resume(libxl__gc *gc, int domid)
-{
-    int rc = 0;
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        switch (libxl__device_model_version_running(gc, domid)) {
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-            rc = xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_ACPI_S_STATE, 0);
-            break;
-        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-            rc = libxl__qmp_system_wakeup(gc, domid);
-            break;
-        default:
-            rc = ERROR_INVAL;
-            break;
-        }
-        break;
-    default:
-        rc = ERROR_INVAL;
-        break;
-    }
-
-    return rc;
-}
-
-int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid,
-                       libxl_trigger trigger, uint32_t vcpuid)
-{
-    int rc;
-    GC_INIT(ctx);
-
-    switch (trigger) {
-    case LIBXL_TRIGGER_POWER:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_POWER, vcpuid);
-        break;
-    case LIBXL_TRIGGER_SLEEP:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_SLEEP, vcpuid);
-        break;
-    case LIBXL_TRIGGER_NMI:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_NMI, vcpuid);
-        break;
-    case LIBXL_TRIGGER_INIT:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_INIT, vcpuid);
-        break;
-    case LIBXL_TRIGGER_RESET:
-        rc = xc_domain_send_trigger(ctx->xch, domid,
-                                    XEN_DOMCTL_SENDTRIGGER_RESET, vcpuid);
-        break;
-    case LIBXL_TRIGGER_S3RESUME:
-        rc = libxl__domain_s3_resume(gc, domid);
-        break;
-    default:
-        rc = -1;
-        errno = EINVAL;
-        break;
-    }
-
-    if (rc != 0) {
-        LOGED(ERROR, domid, "Send trigger '%s' failed",
-              libxl_trigger_to_string(trigger));
-        rc = ERROR_FAIL;
-    }
-
-    GC_FREE;
-    return rc;
-}
-
 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
 {
     GC_INIT(ctx);
@@ -2084,27 +652,6 @@ int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
     return 0;
 }
 
-uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    char *dompath = libxl__xs_get_dompath(gc, domid);
-    char *vm_path, *start_time;
-    uint32_t ret;
-
-    vm_path = libxl__xs_read(
-        gc, XBT_NULL, GCSPRINTF("%s/vm", dompath));
-    start_time = libxl__xs_read(
-        gc, XBT_NULL, GCSPRINTF("%s/start_time", vm_path));
-    if (start_time == NULL) {
-        LOGEVD(ERROR, -1, domid, "Can't get start time of domain");
-        ret = -1;
-    }else{
-        ret = strtoul(start_time, NULL, 10);
-    }
-    GC_FREE;
-    return ret;
-}
-
 static int fd_set_flags(libxl_ctx *ctx, int fd,
                         int fcntlgetop, int fcntlsetop, const char *fl,
                         int flagmask, int set_p)
@@ -2212,275 +759,6 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, const libxl_mac *src)
         (*dst)[i] = (*src)[i];
 }
 
-/* For QEMU upstream we always need to provide the number of cpus present to
- * QEMU whether they are online or not; otherwise QEMU won't accept the saved
- * state. See implementation of libxl__qmp_query_cpus.
- */
-static int libxl__update_avail_vcpus_qmp(libxl__gc *gc, uint32_t domid,
-                                         unsigned int max_vcpus,
-                                         libxl_bitmap *map)
-{
-    int rc;
-
-    rc = libxl__qmp_query_cpus(gc, domid, map);
-    if (rc) {
-        LOGD(ERROR, domid, "Fail to get number of cpus");
-        goto out;
-    }
-
-    rc = 0;
-out:
-    return rc;
-}
-
-static int libxl__update_avail_vcpus_xenstore(libxl__gc *gc, uint32_t domid,
-                                              unsigned int max_vcpus,
-                                              libxl_bitmap *map)
-{
-    int rc;
-    unsigned int i;
-    const char *dompath;
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    if (!dompath) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    for (i = 0; i < max_vcpus; i++) {
-        const char *path = GCSPRINTF("%s/cpu/%u/availability", dompath, i);
-        const char *content;
-        rc = libxl__xs_read_checked(gc, XBT_NULL, path, &content);
-        if (rc) goto out;
-        if (content && !strcmp(content, "online"))
-            libxl_bitmap_set(map, i);
-    }
-
-    rc = 0;
-out:
-    return rc;
-}
-
-int libxl_retrieve_domain_configuration(libxl_ctx *ctx, uint32_t domid,
-                                        libxl_domain_config *d_config)
-{
-    GC_INIT(ctx);
-    int rc;
-    libxl__domain_userdata_lock *lock = NULL;
-
-    CTX_LOCK;
-
-    lock = libxl__lock_domain_userdata(gc, domid);
-    if (!lock) {
-        rc = ERROR_LOCK_FAIL;
-        goto out;
-    }
-
-    rc = libxl__get_domain_configuration(gc, domid, d_config);
-    if (rc) {
-        LOGD(ERROR, domid, "Fail to get domain configuration");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /* Domain name */
-    {
-        char *domname;
-        domname = libxl_domid_to_name(ctx, domid);
-        if (!domname) {
-            LOGD(ERROR, domid, "Fail to get domain name");
-            goto out;
-        }
-        free(d_config->c_info.name);
-        d_config->c_info.name = domname; /* steals allocation */
-    }
-
-    /* Domain UUID */
-    {
-        libxl_dominfo info;
-        libxl_dominfo_init(&info);
-        rc = libxl_domain_info(ctx, &info, domid);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get domain info");
-            libxl_dominfo_dispose(&info);
-            goto out;
-        }
-        libxl_uuid_copy(ctx, &d_config->c_info.uuid, &info.uuid);
-        libxl_dominfo_dispose(&info);
-    }
-
-    /* VCPUs */
-    {
-        libxl_bitmap *map = &d_config->b_info.avail_vcpus;
-        unsigned int max_vcpus = d_config->b_info.max_vcpus;
-        libxl_device_model_version version;
-
-        libxl_bitmap_dispose(map);
-        libxl_bitmap_init(map);
-        libxl_bitmap_alloc(CTX, map, max_vcpus);
-        libxl_bitmap_set_none(map);
-
-        switch (d_config->b_info.type) {
-        case LIBXL_DOMAIN_TYPE_HVM:
-            version = libxl__device_model_version_running(gc, domid);
-            assert(version != LIBXL_DEVICE_MODEL_VERSION_UNKNOWN);
-            switch (version) {
-            case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
-                rc = libxl__update_avail_vcpus_qmp(gc, domid,
-                                                   max_vcpus, map);
-                break;
-            case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
-            case LIBXL_DEVICE_MODEL_VERSION_NONE:
-                rc = libxl__update_avail_vcpus_xenstore(gc, domid,
-                                                        max_vcpus, map);
-                break;
-            default:
-                abort();
-            }
-            break;
-        case LIBXL_DOMAIN_TYPE_PV:
-            rc = libxl__update_avail_vcpus_xenstore(gc, domid,
-                                                    max_vcpus, map);
-            break;
-        default:
-            abort();
-        }
-
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to update available cpu map");
-            goto out;
-        }
-    }
-
-    /* Memory limits:
-     *
-     * Currently there are three memory limits:
-     *  1. "target" in xenstore (originally memory= in config file)
-     *  2. "static-max" in xenstore (originally maxmem= in config file)
-     *  3. "max_memkb" in hypervisor
-     *
-     * The third one is not visible and currently managed by
-     * toolstack. In order to rebuild a domain we only need to have
-     * "target" and "static-max".
-     */
-    {
-        uint64_t target_memkb = 0, max_memkb = 0;
-
-        /* "target" */
-        rc = libxl__get_memory_target(gc, domid, &target_memkb, &max_memkb);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get memory target");
-            goto out;
-        }
-
-        /* libxl__get_targetmem_fudge() calculates the difference from
-         * what is in xenstore to what we have in the domain build info.
-         */
-        d_config->b_info.target_memkb = target_memkb +
-            libxl__get_targetmem_fudge(gc, &d_config->b_info);
-
-        d_config->b_info.max_memkb = max_memkb;
-    }
-
-    /* Scheduler params */
-    {
-        libxl_domain_sched_params_dispose(&d_config->b_info.sched_params);
-        rc = libxl_domain_sched_params_get(ctx, domid,
-                                           &d_config->b_info.sched_params);
-        if (rc) {
-            LOGD(ERROR, domid, "Fail to get scheduler parameters");
-            goto out;
-        }
-    }
-
-    /* Devices: disk, nic, vtpm, pcidev etc. */
-
-    /* The MERGE macro implements following logic:
-     * 0. retrieve JSON (done by now)
-     * 1. retrieve list of device from xenstore
-     * 2. use xenstore entries as primary reference and compare JSON
-     *    entries with them.
-     *    a. if a device is present in xenstore and in JSON, merge the
-     *       two views.
-     *    b. if a device is not present in xenstore but in JSON, delete
-     *       it from the result.
-     *    c. it's impossible to have an entry present in xenstore but
-     *       not in JSON, because we maintain an invariant that every
-     *       entry in xenstore must have a corresponding entry in JSON.
-     * 3. "merge" operates on "src" and "dst". "src" points to the
-     *    entry retrieved from xenstore while "dst" points to the entry
-     *    retrieve from JSON.
-     */
-    {
-        const struct libxl_device_type *dt;
-        int idx;
-
-        for (idx = 0;; idx++) {
-            void *p = NULL;
-            void **devs;
-            int i, j, num;
-            int *num_dev;
-
-            dt = device_type_tbl[idx];
-            if (!dt)
-                break;
-
-            if (!dt->list || !dt->compare)
-                continue;
-
-            num_dev = libxl__device_type_get_num(dt, d_config);
-            p = dt->list(CTX, domid, &num);
-            if (p == NULL) {
-                LOGD(DEBUG, domid, "No %s from xenstore",
-                     dt->type);
-            }
-            devs = libxl__device_type_get_ptr(dt, d_config);
-
-            for (i = 0; i < *num_dev; i++) {
-                void *q;
-
-                q = libxl__device_type_get_elem(dt, d_config, i);
-                for (j = 0; j < num; j++) {
-                    if (dt->compare(p + dt->dev_elem_size * j, q))
-                        break;
-                }
-
-                if (j < num) {         /* found in xenstore */
-                    if (dt->merge)
-                        dt->merge(ctx, p + dt->dev_elem_size * j, q);
-                } else {                /* not found in xenstore */
-                    LOGD(WARN, domid,
-                         "Device present in JSON but not in xenstore, ignored");
-
-                    dt->dispose(q);
-
-                    for (j = i; j < *num_dev - 1; j++)
-                        memcpy(libxl__device_type_get_elem(dt, d_config, j),
-                               libxl__device_type_get_elem(dt, d_config, j+1),
-                               dt->dev_elem_size);
-
-                    /* rewind counters */
-                    (*num_dev)--;
-                    i--;
-
-                    *devs = libxl__realloc(NOGC, *devs,
-                                           dt->dev_elem_size * *num_dev);
-                }
-            }
-
-            for (i = 0; i < num; i++)
-                dt->dispose(p + dt->dev_elem_size * i);
-            free(p);
-        }
-    }
-
-out:
-    if (lock) libxl__unlock_domain_userdata(lock);
-    CTX_UNLOCK;
-    GC_FREE;
-    return rc;
-}
-
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_domain.c b/tools/libxl/libxl_domain.c
new file mode 100644
index 0000000..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] 23+ messages in thread

* [PATCH v2 12/12] libxl: make one function static
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (10 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 11/12] libxl: carve out domain " Juergen Gross
@ 2017-02-09  9:30 ` Juergen Gross
  2017-02-09 11:42   ` Ian Jackson
  2017-02-09 10:22 ` [PATCH v2 00/12] libxl: split up libxl.c Wei Liu
  2017-02-09 11:41 ` Ian Jackson
  13 siblings, 1 reply; 23+ messages in thread
From: Juergen Gross @ 2017-02-09  9:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, haozhong.zhang, wei.liu2, zhangchen.fnst,
	ian.jackson, yi.y.sun

libxl__device_frontend_path() is used in libxl_device.c only. Make it
static.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/libxl/libxl_device.c   | 2 +-
 tools/libxl/libxl_internal.h | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index c72a2b8..5e96676 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);
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index b880801..29d6de5 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1206,7 +1206,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] 23+ messages in thread

* Re: [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c
  2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
@ 2017-02-09 10:18   ` Wei Liu
  2017-02-09 11:37   ` Ian Jackson
  1 sibling, 0 replies; 23+ messages in thread
From: Wei Liu @ 2017-02-09 10:18 UTC (permalink / raw)
  To: Juergen Gross
  Cc: haozhong.zhang, wei.liu2, zhangchen.fnst, ian.jackson, yi.y.sun,
	xen-devel

On Thu, Feb 09, 2017 at 10:30:14AM +0100, Juergen Gross wrote:
> The copyright of libxl.c is a little bit outdated.
> 
> Adjust it to reality.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

Reviewed-by: Wei Liu <wei.liu2@citrix.com>

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

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

* Re: [PATCH v2 00/12] libxl: split up libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (11 preceding siblings ...)
  2017-02-09  9:30 ` [PATCH v2 12/12] libxl: make one function static Juergen Gross
@ 2017-02-09 10:22 ` Wei Liu
  2017-02-09 11:41 ` Ian Jackson
  13 siblings, 0 replies; 23+ messages in thread
From: Wei Liu @ 2017-02-09 10:22 UTC (permalink / raw)
  To: Juergen Gross
  Cc: haozhong.zhang, wei.liu2, zhangchen.fnst, ian.jackson, yi.y.sun,
	xen-devel

On Thu, Feb 09, 2017 at 10:30:13AM +0100, Juergen Gross wrote:
> libxl.c has become rather large. Split it up into multiple files.
> 
> Changes are:
> - modification of Copyright comment (patch 1)
> - made two functions non-static: libxl__get_memory_target(),
>   xcinfo2xlinfo() (patch 2)
> - white space cleanup of libxl.c (patch 3)
> - moving functions into new or existing sources (patches 4-11):
>   just code movement, no functional changes besides needed Makefile
>   adjustments for new sources
> - made one function static: libxl__device_frontend_path() (patch 12)
> 
> Changes in V2:
> - address comments of Ian Jackson: add new patches 1-3, 12
> 
> Juergen Gross (12):
>   libxl: adjust copyright comment of libxl.c
>   libxl: make some functions global to prepare splitting up libxl.c
>   libxl: white space cleanup
>   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
>   libxl: make one function static
> 

Series:

Reviewed-by: Wei Liu <wei.liu2@citrix.com>

I'm a bit two-minded about the last patch, though.

Wei.

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

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

* Re: [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c
  2017-02-09  9:30 ` [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c Juergen Gross
@ 2017-02-09 11:36   ` Ian Jackson
  2017-02-09 11:42     ` Juergen Gross
  0 siblings, 1 reply; 23+ messages in thread
From: Ian Jackson @ 2017-02-09 11:36 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

Juergen Gross writes ("[PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c"):
> Splitting up libxl.c will require two functions to be globally visible.
> Add their prototypes to libxl_internal.h.

Thanks.  However,

> -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)

This function needs a libxl__ prefix adding to its name.

Ian.

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

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

* Re: [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c
  2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
  2017-02-09 10:18   ` Wei Liu
@ 2017-02-09 11:37   ` Ian Jackson
  1 sibling, 0 replies; 23+ messages in thread
From: Ian Jackson @ 2017-02-09 11:37 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

Juergen Gross writes ("[PATCH v2 01/12] libxl: adjust copyright comment of libxl.c"):
> The copyright of libxl.c is a little bit outdated.

Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>

If you felt like doing a similar thing to the other files that would
be nice (but of course not required for this series).

Regards,
Ian.

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

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

* Re: [PATCH v2 03/12] libxl: white space cleanup
  2017-02-09  9:30 ` [PATCH v2 03/12] libxl: white space cleanup Juergen Gross
@ 2017-02-09 11:37   ` Ian Jackson
  0 siblings, 0 replies; 23+ messages in thread
From: Ian Jackson @ 2017-02-09 11:37 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

Juergen Gross writes ("[PATCH v2 03/12] libxl: white space cleanup"):
> Before moving code to new sources clean up some white space issues in
> libxl.c.

Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>

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

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

* Re: [PATCH v2 00/12] libxl: split up libxl.c
  2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
                   ` (12 preceding siblings ...)
  2017-02-09 10:22 ` [PATCH v2 00/12] libxl: split up libxl.c Wei Liu
@ 2017-02-09 11:41 ` Ian Jackson
  13 siblings, 0 replies; 23+ messages in thread
From: Ian Jackson @ 2017-02-09 11:41 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

Juergen Gross writes ("[PATCH v2 00/12] libxl: split up 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

I have verified your assertion that these patches are just code
motion.

So for patches 4-11 inclusive:

Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>

Ian.

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

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

* Re: [PATCH v2 12/12] libxl: make one function static
  2017-02-09  9:30 ` [PATCH v2 12/12] libxl: make one function static Juergen Gross
@ 2017-02-09 11:42   ` Ian Jackson
  0 siblings, 0 replies; 23+ messages in thread
From: Ian Jackson @ 2017-02-09 11:42 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

Juergen Gross writes ("[PATCH v2 12/12] libxl: make one function static"):
> libxl__device_frontend_path() is used in libxl_device.c only. Make it
> static.

Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>

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

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

* Re: [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c
  2017-02-09 11:36   ` Ian Jackson
@ 2017-02-09 11:42     ` Juergen Gross
  2017-02-09 15:44       ` Wei Liu
  0 siblings, 1 reply; 23+ messages in thread
From: Juergen Gross @ 2017-02-09 11:42 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, wei.liu2, zhangchen.fnst, yi.y.sun, haozhong.zhang

On 09/02/17 12:36, Ian Jackson wrote:
> Juergen Gross writes ("[PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c"):
>> Splitting up libxl.c will require two functions to be globally visible.
>> Add their prototypes to libxl_internal.h.
> 
> Thanks.  However,
> 
>> -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)
> 
> This function needs a libxl__ prefix adding to its name.

Aah, of course!

Will send V3 after waiting for more comments for a while...


Juergen


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

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

* Re: [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c
  2017-02-09 11:42     ` Juergen Gross
@ 2017-02-09 15:44       ` Wei Liu
  2017-02-09 16:06         ` Juergen Gross
  0 siblings, 1 reply; 23+ messages in thread
From: Wei Liu @ 2017-02-09 15:44 UTC (permalink / raw)
  To: Juergen Gross
  Cc: haozhong.zhang, wei.liu2, zhangchen.fnst, Ian Jackson, yi.y.sun,
	xen-devel

On Thu, Feb 09, 2017 at 12:42:41PM +0100, Juergen Gross wrote:
> On 09/02/17 12:36, Ian Jackson wrote:
> > Juergen Gross writes ("[PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c"):
> >> Splitting up libxl.c will require two functions to be globally visible.
> >> Add their prototypes to libxl_internal.h.
> > 
> > Thanks.  However,
> > 
> >> -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)
> > 
> > This function needs a libxl__ prefix adding to its name.
> 
> Aah, of course!
> 
> Will send V3 after waiting for more comments for a while...
> 

If there are no more significant comments, you can just fold in
everything and provide a branch. No need to repost.

> 
> Juergen
> 

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

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

* Re: [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c
  2017-02-09 15:44       ` Wei Liu
@ 2017-02-09 16:06         ` Juergen Gross
  0 siblings, 0 replies; 23+ messages in thread
From: Juergen Gross @ 2017-02-09 16:06 UTC (permalink / raw)
  To: Wei Liu; +Cc: haozhong.zhang, yi.y.sun, Ian Jackson, zhangchen.fnst, xen-devel

On 09/02/17 16:44, Wei Liu wrote:
> On Thu, Feb 09, 2017 at 12:42:41PM +0100, Juergen Gross wrote:
>> On 09/02/17 12:36, Ian Jackson wrote:
>>> Juergen Gross writes ("[PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c"):
>>>> Splitting up libxl.c will require two functions to be globally visible.
>>>> Add their prototypes to libxl_internal.h.
>>>
>>> Thanks.  However,
>>>
>>>> -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)
>>>
>>> This function needs a libxl__ prefix adding to its name.
>>
>> Aah, of course!
>>
>> Will send V3 after waiting for more comments for a while...
>>
> 
> If there are no more significant comments, you can just fold in
> everything and provide a branch. No need to repost.

Okay. Please pull from

https://github.com/jgross1/xen.git libxl-split-v3


Thanks,

Juergen


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

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

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

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-09  9:30 [PATCH v2 00/12] libxl: split up libxl.c Juergen Gross
2017-02-09  9:30 ` [PATCH v2 01/12] libxl: adjust copyright comment of libxl.c Juergen Gross
2017-02-09 10:18   ` Wei Liu
2017-02-09 11:37   ` Ian Jackson
2017-02-09  9:30 ` [PATCH v2 02/12] libxl: make some functions global to prepare splitting up libxl.c Juergen Gross
2017-02-09 11:36   ` Ian Jackson
2017-02-09 11:42     ` Juergen Gross
2017-02-09 15:44       ` Wei Liu
2017-02-09 16:06         ` Juergen Gross
2017-02-09  9:30 ` [PATCH v2 03/12] libxl: white space cleanup Juergen Gross
2017-02-09 11:37   ` Ian Jackson
2017-02-09  9:30 ` [PATCH v2 04/12] libxl: carve out cpupool specific functions from libxl.c Juergen Gross
2017-02-09  9:30 ` [PATCH v2 05/12] libxl: carve out scheduler " Juergen Gross
2017-02-09  9:30 ` [PATCH v2 06/12] libxl: carve out disk " Juergen Gross
2017-02-09  9:30 ` [PATCH v2 07/12] libxl: carve out console " Juergen Gross
2017-02-09  9:30 ` [PATCH v2 08/12] libxl: carve out memory " Juergen Gross
2017-02-09  9:30 ` [PATCH v2 09/12] libxl: move device specific functions out of libxl.c Juergen Gross
2017-02-09  9:30 ` [PATCH v2 10/12] libxl: carve out tmem specific functions from libxl.c Juergen Gross
2017-02-09  9:30 ` [PATCH v2 11/12] libxl: carve out domain " Juergen Gross
2017-02-09  9:30 ` [PATCH v2 12/12] libxl: make one function static Juergen Gross
2017-02-09 11:42   ` Ian Jackson
2017-02-09 10:22 ` [PATCH v2 00/12] libxl: split up libxl.c Wei Liu
2017-02-09 11:41 ` Ian Jackson

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.