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

[Xen-devel] [PATCH 07/13] libxl: convert libxl_domain_destroy to an AO op



This change introduces some new structures, and breaks the mutual
dependency that libxl_domain_destroy and libxl__destroy_device_model
had. This is done by checking if the domid passed to
libxl_domain_destroy has a stubdom, and then having the bulk of the
destroy machinery in a separate function (libxl__destroy_domid) that
doesn't check for stubdom presence, since we check for it in the upper
level function. The reason behind this change is the need to use
structures for ao operations, and it was impossible to have two
different self-referencing structs.

All uses of libxl_domain_destroy have been changed, and either
replaced by the new libxl_domain_destroy ao function or by the
internal libxl__domain_destroy that can be used inside an already
running ao.

Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
---
 tools/libxl/libxl.c               |  180 +++++++++++-----------
 tools/libxl/libxl.h               |    3 +-
 tools/libxl/libxl_create.c        |   30 +++-
 tools/libxl/libxl_device.c        |  308 ++++++++++++++++++++++++++++---------
 tools/libxl/libxl_dm.c            |   83 +++++-----
 tools/libxl/libxl_dom.c           |  170 ++++++++++++++++++++
 tools/libxl/libxl_internal.h      |  224 +++++++++++++++++++++------
 tools/libxl/xl_cmdimpl.c          |   12 +-
 tools/python/xen/lowlevel/xl/xl.c |    2 +-
 9 files changed, 752 insertions(+), 260 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index d3b6a53..dabe92b 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1070,80 +1070,34 @@ void libxl_evdisable_disk_eject(libxl_ctx *ctx, 
libxl_evgen_disk_eject *evg) {
     GC_FREE;
 }    
 
-int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
-{
-    GC_INIT(ctx);
-    char *dom_path;
-    char *vm_path;
-    char *pid;
-    int rc, dm_present;
-
-    rc = libxl_domain_info(ctx, NULL, domid);
-    switch(rc) {
-    case 0:
-        break;
-    case ERROR_INVAL:
-        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "non-existant domain %d", domid);
-    default:
-        return rc;
-    }
-
-    switch (libxl__domain_type(gc, domid)) {
-    case LIBXL_DOMAIN_TYPE_HVM:
-        dm_present = 1;
-        break;
-    case LIBXL_DOMAIN_TYPE_PV:
-        pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, 
"/local/domain/%d/image/device-model-pid", domid));
-        dm_present = (pid != NULL);
-        break;
-    default:
-        abort();
-    }
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
+/* Callback for domain destruction */
 
-    if (libxl__device_pci_destroy_all(gc, domid) < 0)
-        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", 
domid);
-    rc = xc_domain_pause(ctx->xch, domid);
-    if (rc < 0) {
-        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed 
for %d", domid);
-    }
-    if (dm_present) {
-        if (libxl__destroy_device_model(gc, domid) < 0)
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl__destroy_device_model 
failed for %d", domid);
+static void domain_destroy_cb(libxl__egc *, libxl__domain_destroy_state *, 
int);
 
-        libxl__qmp_cleanup(gc, domid);
-    }
-    if (libxl__devices_destroy(gc, domid) < 0)
-        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 
-                   "libxl__devices_destroy failed for %d", domid);
+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;
 
-    vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/vm", 
dom_path));
-    if (vm_path)
-        if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
-            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", 
vm_path);
+    GCNEW(dds);
+    dds->ao = ao;
+    dds->domid = domid;
+    dds->callback = domain_destroy_cb;
+    libxl__domain_destroy(egc, dds);
 
-    if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
-        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", 
dom_path);
+    return AO_INPROGRESS;
+}
 
-    xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid));
+static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state 
*dds,
+                              int rc)
+{
+    STATE_AO_GC(dds->ao);
 
-    libxl__userdata_destroyall(gc, domid);
+    if (rc)
+        LOG(ERROR, "destruction of domain %u failed", dds->domid);
 
-    rc = xc_domain_destroy(ctx->xch, domid);
-    if (rc < 0) {
-        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_destroy 
failed for %d", domid);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
+    libxl__ao_complete(egc, ao, rc);
 }
 
 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, 
libxl_console_type type)
@@ -1271,6 +1225,26 @@ int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, 
int autopass)
 
 
/******************************************************************************/
 
+/* generic callback for devices that only need to set ao_complete */
+static void libxl__device_cb(libxl__egc *egc, libxl__ao_device *aorm)
+{
+    STATE_AO_GC(aorm->ao);
+
+    if (aorm->rc) {
+        LOGE(ERROR, "unable to %s %s with id %u",
+                    aorm->action == DEVICE_CONNECT ? "add" : "remove",
+                    libxl__device_kind_to_string(aorm->dev->kind),
+                    aorm->dev->devid);
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, aorm->rc);
+    return;
+}
+
+/******************************************************************************/
+
 int libxl__device_disk_setdefault(libxl__gc *gc, libxl_device_disk *disk)
 {
     int rc;
@@ -1297,19 +1271,25 @@ int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t 
domid,
                              const libxl_asyncop_how *ao_how)
 {
     AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
+    libxl__device *device;
+    libxl__ao_device *aorm = 0;
     int rc;
 
-    rc = libxl__device_from_disk(gc, domid, disk, &device);
+    GCNEW(device);
+    rc = libxl__device_from_disk(gc, domid, disk, device);
     if (rc != 0) goto out;
 
-    rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    GCNEW(aorm);
+    libxl__init_ao_device(aorm, ao, NULL);
+    aorm->action = DEVICE_DISCONNECT;
+    aorm->dev = device;
+    aorm->callback = libxl__device_cb;
 
-    return AO_INPROGRESS;
+    libxl__initiate_device_remove(egc, aorm);
 
 out:
-    return AO_ABORT(rc);
+    if (rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
 }
 
 int libxl_device_disk_destroy(libxl_ctx *ctx, uint32_t domid,
@@ -1671,19 +1651,25 @@ int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t 
domid,
                             const libxl_asyncop_how *ao_how)
 {
     AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
+    libxl__device *device;
+    libxl__ao_device *aorm = 0;
     int rc;
 
-    rc = libxl__device_from_nic(gc, domid, nic, &device);
+    GCNEW(device);
+    rc = libxl__device_from_nic(gc, domid, nic, device);
     if (rc != 0) goto out;
 
-    rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    GCNEW(aorm);
+    libxl__init_ao_device(aorm, ao, NULL);
+    aorm->action = DEVICE_DISCONNECT;
+    aorm->dev = device;
+    aorm->callback = libxl__device_cb;
 
-    return AO_INPROGRESS;
+    libxl__initiate_device_remove(egc, aorm);
 
 out:
-    return AO_ABORT(rc);
+    if (rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
 }
 
 int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid,
@@ -2033,19 +2019,25 @@ int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t 
domid,
                             const libxl_asyncop_how *ao_how)
 {
     AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
+    libxl__device *device;
+    libxl__ao_device *aorm = 0;
     int rc;
 
-    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
+    GCNEW(device);
+    rc = libxl__device_from_vkb(gc, domid, vkb, device);
     if (rc != 0) goto out;
 
-    rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    GCNEW(aorm);
+    libxl__init_ao_device(aorm, ao, NULL);
+    aorm->action = DEVICE_DISCONNECT;
+    aorm->dev = device;
+    aorm->callback = libxl__device_cb;
 
-    return AO_INPROGRESS;
+    libxl__initiate_device_remove(egc, aorm);
 
 out:
-    return AO_ABORT(rc);
+    if (rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
 }
 
 int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid,
@@ -2166,19 +2158,25 @@ int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t 
domid,
                             const libxl_asyncop_how *ao_how)
 {
     AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
+    libxl__device *device;
+    libxl__ao_device *aorm = 0;
     int rc;
 
-    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
+    GCNEW(device);
+    rc = libxl__device_from_vfb(gc, domid, vfb, device);
     if (rc != 0) goto out;
 
-    rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    GCNEW(aorm);
+    libxl__init_ao_device(aorm, ao, NULL);
+    aorm->action = DEVICE_DISCONNECT;
+    aorm->dev = device;
+    aorm->callback = libxl__device_cb;
 
-    return AO_INPROGRESS;
+    libxl__initiate_device_remove(egc, aorm);
 
 out:
-    return AO_ABORT(rc);
+    if (rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
 }
 
 int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid,
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 979940a..2f4694e 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -530,7 +530,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, 
libxl_domain_suspend_info *info,
 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid);
-int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid);
+int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid,
+                         const libxl_asyncop_how *ao_how);
 int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, 
libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid);
 
 /* get max. number of cpus supported by hypervisor */
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 14721eb..bd8e6a6 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -584,6 +584,13 @@ static void domcreate_complete(libxl__egc *egc,
                                libxl__domain_create_state *dcs,
                                int rc);
 
+/* If creation is not successful, this callback will be executed
+ * when domain destruction is finished */
+
+static void domcreate_destruction_cb(libxl__egc *egc,
+                                    libxl__domain_destroy_state *dds,
+                                    int rc);
+
 static void initiate_domain_create(libxl__egc *egc,
                                    libxl__domain_create_state *dcs)
 {
@@ -848,16 +855,31 @@ static void domcreate_complete(libxl__egc *egc,
 
     if (rc) {
         if (dcs->guest_domid) {
-            int rc2 = libxl_domain_destroy(CTX, dcs->guest_domid);
-            if (rc2)
-                LOG(ERROR, "unable to destroy domain %d following"
-                    " failed creation", dcs->guest_domid);
+            dcs->dds.ao = ao;
+            dcs->dds.domid = dcs->guest_domid;
+            dcs->dds.callback = domcreate_destruction_cb;
+            libxl__domain_destroy(egc, &dcs->dds);
+            return;
         }
         dcs->guest_domid = -1;
     }
     dcs->callback(egc, dcs, rc, dcs->guest_domid);
 }
 
+static void domcreate_destruction_cb(libxl__egc *egc,
+                                     libxl__domain_destroy_state *dds,
+                                     int rc)
+{
+    STATE_AO_GC(dds->ao);
+    libxl__domain_create_state *dcs = CONTAINER_OF(dds, *dcs, dds);
+
+    if (rc)
+        LOG(ERROR, "unable to destroy domain %u following failed creation",
+                   dds->domid);
+
+    dcs->callback(egc, dcs, rc, dcs->guest_domid);
+}
+
 /*----- application-facing domain creation interface -----*/
 
 typedef struct {
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 1e34135..577324c 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -58,6 +58,48 @@ int libxl__parse_backend_path(libxl__gc *gc,
     return libxl__device_kind_from_string(strkind, &dev->backend_kind);
 }
 
+static int libxl__num_devices(libxl__gc *gc, uint32_t domid)
+{
+    char *path;
+    unsigned int num_kinds, num_devs;
+    char **kinds = NULL, **devs = NULL;
+    int i, j, rc = 0;
+    libxl__device dev;
+    libxl__device_kind kind;
+    int numdevs = 0;
+
+    path = GCSPRINTF("/local/domain/%d/device", domid);
+    kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
+    if (!kinds) {
+        if (errno != ENOENT) {
+            LOGE(ERROR, "unable to get xenstore device listing %s", path);
+            rc = ERROR_FAIL;
+            goto out;
+        }
+        num_kinds = 0;
+    }
+    for (i = 0; i < num_kinds; i++) {
+        if (libxl__device_kind_from_string(kinds[i], &kind))
+            continue;
+
+        path = GCSPRINTF("/local/domain/%d/device/%s", domid, kinds[i]);
+        devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs);
+        if (!devs)
+            continue;
+        for (j = 0; j < num_devs; j++) {
+            path = GCSPRINTF("/local/domain/%d/device/%s/%s/backend",
+                             domid, kinds[i], devs[j]);
+            path = libxl__xs_read(gc, XBT_NULL, path);
+            if (path && libxl__parse_backend_path(gc, path, &dev) == 0) {
+                numdevs++;
+            }
+        }
+    }
+out:
+    if (rc) return rc;
+    return numdevs;
+}
+
 int libxl__device_generic_add(libxl__gc *gc, libxl__device *device,
                              char **bents, char **fents)
 {
@@ -624,49 +666,70 @@ int libxl__device_disk_dev_number(const char *virtpath, 
int *pdisk,
     return -1;
 }
 
+/* Device destruction */
 
-typedef struct {
-    libxl__ao *ao;
-    libxl__ev_devstate ds;
-} libxl__ao_device_remove;
-
-static void device_remove_cleanup(libxl__gc *gc,
-                                  libxl__ao_device_remove *aorm) {
+static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aorm)
+{
     if (!aorm) return;
     libxl__ev_devstate_cancel(gc, &aorm->ds);
 }
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
-                                   int rc) {
-    libxl__ao_device_remove *aorm = CONTAINER_OF(ds, *aorm, ds);
-    libxl__gc *gc = &aorm->ao->gc;
-    libxl__ao_complete(egc, aorm->ao, rc);
-    device_remove_cleanup(gc, aorm);
+void libxl__init_ao_device(libxl__ao_device *aorm, libxl__ao *ao,
+                           libxl__ao_device **base)
+{
+    aorm->ao = ao;
+    aorm->state = DEVICE_ACTIVE;
+    aorm->rc = 0;
+    aorm->base = base;
+}
+
+int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
+                                libxl__ao_device *list, int num, int *last)
+{
+    int i, ret = 0;
+
+    device->state = DEVICE_FINISHED;
+    *last = 1;
+    for (i = 0; i < num; i++) {
+        if (list[i].state != DEVICE_FINISHED && *last) {
+            *last = 0;
+        }
+        if (list[i].rc)
+            ret = list[i].rc;
+    }
+    return ret;
 }
 
-int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao,
-                                  libxl__device *dev)
+/* Common callbacks for device add/remove */
+
+static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+                                    int rc);
+
+void libxl__initiate_device_remove(libxl__egc *egc, libxl__ao_device *aorm)
 {
-    AO_GC;
+    STATE_AO_GC(aorm->ao);
     libxl_ctx *ctx = libxl__gc_owner(gc);
-    xs_transaction_t t;
-    char *be_path = libxl__device_backend_path(gc, dev);
+    xs_transaction_t t = 0;
+    char *be_path = libxl__device_backend_path(gc, aorm->dev);
     char *state_path = libxl__sprintf(gc, "%s/state", be_path);
-    char *state = libxl__xs_read(gc, XBT_NULL, state_path);
+    char *state;
     int rc = 0;
-    libxl__ao_device_remove *aorm = 0;
 
+retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+    if (aorm->force)
+        libxl__xs_path_cleanup(gc, t,
+                               libxl__device_frontend_path(gc, aorm->dev));
+        /* Remove frontend xs paths to force backend disconnection */
+    state = libxl__xs_read(gc, t, state_path);
     if (!state)
         goto out_ok;
-    if (atoi(state) != 4) {
+    if (atoi(state) == XenbusStateClosed) {
         libxl__device_destroy_tapdisk(gc, be_path);
-        xs_rm(ctx->xsh, XBT_NULL, be_path);
         goto out_ok;
     }
 
-retry_transaction:
-    t = xs_transaction_start(ctx->xsh);
-    xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/online", be_path), "0", 
strlen("0"));
+    xs_write(ctx->xsh, t, GCSPRINTF("%s/online", be_path), "0", strlen("0"));
     xs_write(ctx->xsh, t, state_path, "5", strlen("5"));
     if (!xs_transaction_end(ctx->xsh, t, 0)) {
         if (errno == EAGAIN)
@@ -676,60 +739,67 @@ retry_transaction:
             goto out_fail;
         }
     }
+    /* mark transaction as ended, to prevent double closing it on out_ok */
+    t = 0;
 
     libxl__device_destroy_tapdisk(gc, be_path);
 
-    aorm = libxl__zalloc(gc, sizeof(*aorm));
-    aorm->ao = ao;
     libxl__ev_devstate_init(&aorm->ds);
-
-    rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_remove_callback,
+    rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_backend_callback,
                                  state_path, XenbusStateClosed,
                                  LIBXL_DESTROY_TIMEOUT * 1000);
-    if (rc) goto out_fail;
+    if (rc) {
+        LOGE(ERROR, "unable to remove device %s", be_path);
+        goto out_fail;
+    }
 
-    return 0;
+    return;
 
  out_fail:
     assert(rc);
-    device_remove_cleanup(gc, aorm);
-    return rc;
+    aorm->rc = rc;
+    aorm->callback(egc, aorm);
+    return;
 
  out_ok:
-    libxl__ao_complete(egc, ao, 0);
-    return 0;
+    if (t) xs_transaction_end(ctx->xsh, t, 0);
+    aorm->callback(egc, aorm);
+    return;
 }
 
-int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
-{
-    libxl_ctx *ctx = libxl__gc_owner(gc);
-    char *be_path = libxl__device_backend_path(gc, dev);
-    char *fe_path = libxl__device_frontend_path(gc, dev);
-
-    xs_rm(ctx->xsh, XBT_NULL, be_path);
-    xs_rm(ctx->xsh, XBT_NULL, fe_path);
+/* Callback for device destruction */
 
-    libxl__device_destroy_tapdisk(gc, be_path);
-
-    return 0;
-}
+static void device_remove_callback(libxl__egc *egc, libxl__ao_device *aorm);
 
-int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
+void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
 {
-    libxl_ctx *ctx = libxl__gc_owner(gc);
+    STATE_AO_GC(drs->ao);
     char *path;
     unsigned int num_kinds, num_devs;
     char **kinds = NULL, **devs = NULL;
-    int i, j;
-    libxl__device dev;
+    int i, j, rc = 0, numdev = 0;
+    libxl__device *dev;
     libxl__device_kind kind;
 
-    path = libxl__sprintf(gc, "/local/domain/%d/device", domid);
+    drs->num_devices = libxl__num_devices(gc, drs->domid);
+    if (drs->num_devices < 0) {
+        LOGE(ERROR, "unable to get number of devices for domain %u",
+                    drs->domid);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    GCNEW_ARRAY(drs->aorm, drs->num_devices);
+    for (i = 0; i < drs->num_devices; i++) {
+        libxl__init_ao_device(&drs->aorm[i], drs->ao, &drs->aorm);
+    }
+
+    path = GCSPRINTF("/local/domain/%d/device", drs->domid);
     kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
     if (!kinds) {
         if (errno != ENOENT) {
-            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get xenstore"
-                             " device listing %s", path);
+            LOGE(ERROR, "unable to get xenstore device listing %s", path);
+            rc = ERROR_FAIL;
             goto out;
         }
         num_kinds = 0;
@@ -738,38 +808,136 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
         if (libxl__device_kind_from_string(kinds[i], &kind))
             continue;
 
-        path = libxl__sprintf(gc, "/local/domain/%d/device/%s", domid, 
kinds[i]);
+        path = GCSPRINTF("/local/domain/%d/device/%s", drs->domid, kinds[i]);
         devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs);
         if (!devs)
             continue;
         for (j = 0; j < num_devs; j++) {
-            path = libxl__sprintf(gc, "/local/domain/%d/device/%s/%s/backend",
-                                  domid, kinds[i], devs[j]);
+            path = GCSPRINTF("/local/domain/%d/device/%s/%s/backend",
+                             drs->domid, kinds[i], devs[j]);
             path = libxl__xs_read(gc, XBT_NULL, path);
-            if (path && libxl__parse_backend_path(gc, path, &dev) == 0) {
-                dev.domid = domid;
-                dev.kind = kind;
-                dev.devid = atoi(devs[j]);
-
-                libxl__device_destroy(gc, &dev);
+            GCNEW(dev);
+            if (path && libxl__parse_backend_path(gc, path, dev) == 0) {
+                dev->domid = drs->domid;
+                dev->kind = kind;
+                dev->devid = atoi(devs[j]);
+                drs->aorm[numdev].action = DEVICE_DISCONNECT;
+                drs->aorm[numdev].dev = dev;
+                drs->aorm[numdev].callback = device_remove_callback;
+                libxl__initiate_device_remove(egc, &drs->aorm[numdev]);
+                numdev++;
             }
         }
     }
 
     /* console 0 frontend directory is not under /local/domain/<domid>/device 
*/
-    path = libxl__sprintf(gc, "/local/domain/%d/console/backend", domid);
+    path = GCSPRINTF("/local/domain/%d/console/backend", drs->domid);
     path = libxl__xs_read(gc, XBT_NULL, path);
+    GCNEW(dev);
     if (path && strcmp(path, "") &&
-        libxl__parse_backend_path(gc, path, &dev) == 0) {
-        dev.domid = domid;
-        dev.kind = LIBXL__DEVICE_KIND_CONSOLE;
-        dev.devid = 0;
+        libxl__parse_backend_path(gc, path, dev) == 0) {
+        dev->domid = drs->domid;
+        dev->kind = LIBXL__DEVICE_KIND_CONSOLE;
+        dev->devid = 0;
 
-        libxl__device_destroy(gc, &dev);
+        libxl__device_destroy(gc, dev);
     }
 
 out:
-    return 0;
+    if (!numdev) drs->callback(egc, drs, rc);
+    return;
+}
+
+static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+                                    int rc)
+{
+    libxl__ao_device *aorm = CONTAINER_OF(ds, *aorm, ds);
+    STATE_AO_GC(aorm->ao);
+
+    device_backend_cleanup(gc, aorm);
+
+    if (rc == ERROR_TIMEDOUT && aorm->action == DEVICE_DISCONNECT &&
+        !aorm->force) {
+        aorm->force = 1;
+        libxl__initiate_device_remove(egc, aorm);
+        return;
+    }
+
+    /* Some devices (vkbd) fail to disconnect properly,
+     * but we shouldn't alarm the user if it's during
+     * domain destruction.
+     */
+    if (rc && aorm->action == DEVICE_CONNECT) {
+        LOG(ERROR, "unable to connect device with path %s",
+                   libxl__device_backend_path(gc, aorm->dev));
+        goto out;
+    } else if(rc) {
+        LOG(DEBUG, "unable to disconnect device with path %s",
+                   libxl__device_backend_path(gc, aorm->dev));
+        goto out;
+    }
+
+out:
+    aorm->rc = rc;
+    aorm->callback(egc, aorm);
+    return;
+}
+
+static void device_remove_callback(libxl__egc *egc, libxl__ao_device *aorm)
+{
+    STATE_AO_GC(aorm->ao);
+    libxl__devices_remove_state *drs = CONTAINER_OF(aorm->base, *drs, aorm);
+    char *be_path = libxl__device_backend_path(gc, aorm->dev);
+    char *fe_path = libxl__device_frontend_path(gc, aorm->dev);
+    xs_transaction_t t = 0;
+    int rc = 0, last = 1;
+
+retry_transaction:
+    t = xs_transaction_start(CTX->xsh);
+    if (aorm->action == DEVICE_DISCONNECT) {
+        libxl__xs_path_cleanup(gc, t, fe_path);
+        libxl__xs_path_cleanup(gc, t, be_path);
+    }
+    if (!xs_transaction_end(CTX->xsh, t, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+out:
+    rc = libxl__ao_device_check_last(gc, aorm, drs->aorm,
+                                     drs->num_devices, &last);
+    if (last)
+        drs->callback(egc, drs, rc);
+    return;
+}
+
+int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *fe_path = libxl__device_frontend_path(gc, dev);
+    xs_transaction_t t = 0;
+    int rc = 0;
+
+retry_transaction:
+    t = xs_transaction_start(CTX->xsh);
+    libxl__xs_path_cleanup(gc, t, be_path);
+    libxl__xs_path_cleanup(gc, t, fe_path);
+    if (!xs_transaction_end(CTX->xsh, t, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+out:
+    libxl__device_destroy_tapdisk(gc, be_path);
+    return rc;
 }
 
 int libxl__wait_for_device_model(libxl__gc *gc,
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 95fd0ac..4019309 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -673,6 +673,10 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
                                 libxl__dm_spawn_state *stubdom_dmss,
                                 int rc);
 
+static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
+                                           libxl__destroy_domid_state *dis,
+                                           int rc);
+
 void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss)
 {
     STATE_AO_GC(sdss->dm.spawn.ao);
@@ -891,12 +895,30 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
 
  out:
     if (rc) {
-        if (dm_domid)
-            libxl_domain_destroy(CTX, dm_domid);
+        if (dm_domid) {
+            sdss->dis.ao = ao;
+            sdss->dis.domid = dm_domid;
+            sdss->dis.callback = spaw_stubdom_pvqemu_destroy_cb;
+            libxl__destroy_domid(egc, &sdss->dis);
+        }
     }
     sdss->callback(egc, &sdss->dm, rc);
 }
 
+static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
+                                           libxl__destroy_domid_state *dis,
+                                           int rc)
+{
+    libxl__stub_dm_spawn_state *sdss = CONTAINER_OF(dis, *sdss, dis);
+    STATE_AO_GC(sdss->dis.ao);
+
+    if (rc)
+        LOG(ERROR, "destruction of domain %u after failed creation failed",
+                   sdss->pvqemu.guest_domid);
+
+    sdss->callback(egc, &sdss->dm, rc);
+}
+
 /* callbacks passed to libxl__spawn_spawn */
 static void device_model_confirm(libxl__egc *egc, libxl__spawn_state *spawn,
                                  const char *xsdata);
@@ -1089,48 +1111,25 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t 
domid)
     int ret;
 
     pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, 
"/local/domain/%d/image/device-model-pid", domid));
-    if (!pid) {
-        int stubdomid = libxl_get_stubdom_id(ctx, domid);
-        const char *savefile;
-
-        if (!stubdomid) {
-            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't find device 
model's pid");
-            ret = ERROR_INVAL;
-            goto out;
-        }
-        LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device model is a stubdom, 
domid=%d", stubdomid);
-        ret = libxl_domain_destroy(ctx, stubdomid);
-        if (ret)
-            goto out;
-
-        savefile = libxl__device_model_savefile(gc, domid);
-        ret = unlink(savefile);
-        /*
-         * On suspend libxl__domain_save_device_model will have already
-         * unlinked the save file.
-         */
-        if (ret && errno == ENOENT) ret = 0;
-        if (ret) {
-            LIBXL__LOG_ERRNO(ctx, XTL_ERROR,
-                             "failed to remove device-model savefile %s\n",
-                             savefile);
-            goto out;
-        }
+    if (!pid || !atoi(pid)) {
+        LOGE(ERROR, "Couldn't find device model's pid");
+        ret = ERROR_INVAL;
+        goto out;
+    }
+    ret = kill(atoi(pid), SIGHUP);
+    if (ret < 0 && errno == ESRCH) {
+        LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model already exited");
+        ret = 0;
+    } else if (ret == 0) {
+        LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model signaled");
+        ret = 0;
     } else {
-        ret = kill(atoi(pid), SIGHUP);
-        if (ret < 0 && errno == ESRCH) {
-            LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model already exited");
-            ret = 0;
-        } else if (ret == 0) {
-            LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model signaled");
-            ret = 0;
-        } else {
-            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to kill Device 
Model [%d]",
-                    atoi(pid));
-            ret = ERROR_FAIL;
-            goto out;
-        }
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to kill Device Model 
[%d]",
+                atoi(pid));
+        ret = ERROR_FAIL;
+        goto out;
     }
+
     xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, 
"/local/domain/0/device-model/%d", domid));
     xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/hvmloader", 
domid));
 
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 6064d44..1e73f64 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -1125,6 +1125,176 @@ out:
     return rc;
 }
 
+/* Callbacks for libxl__domain_destroy */
+static void stubdom_callback(libxl__egc *egc, libxl__destroy_domid_state *dis,
+                             int rc);
+static void domain_callback(libxl__egc *egc, libxl__destroy_domid_state *dis,
+                            int rc);
+
+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_callback;
+        libxl__destroy_domid(egc, &dds->stubdom);
+    } else {
+        dds->stubdom_finished = 1;
+    }
+
+    dds->domain.ao = ao;
+    dds->domain.domid = dds->domid;
+    dds->domain.callback = domain_callback;
+    libxl__destroy_domid(egc, &dds->domain);
+}
+
+static void stubdom_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)
+        LOG(ERROR, "unable to destroy stubdom with domid %u", dis->domid);
+
+    dds->stubdom_finished = 1;
+    savefile = libxl__device_model_savefile(gc, dis->domid);
+    rc = unlink(savefile);
+    /*
+     * On suspend libxl__domain_save_device_model will have already
+     * unlinked the save file.
+     */
+    if (rc && errno == ENOENT) rc = 0;
+    if (rc) {
+        LOGEV(ERROR, errno, "failed to remove device-model savefile %s",
+                            savefile);
+    }
+
+    if (dds->domain_finished)
+        dds->callback(egc, dds, rc);
+}
+
+static void domain_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)
+        LOG(ERROR, "unable to destroy guest with domid %u", dis->domid);
+
+    dds->domain_finished = 1;
+    if (dds->stubdom_finished)
+        dds->callback(egc, dds, rc);
+}
+
+/* Callbacks for libxl__domain_clean */
+
+/* Device destruction callback */
+static void devices_destroy_cb(libxl__egc *egc,
+                               libxl__devices_remove_state *drs,
+                               int rc);
+
+void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
+{
+    STATE_AO_GC(dis->ao);
+    int rc;
+
+    rc = libxl_domain_info(CTX, NULL, dis->domid);
+    switch (rc) {
+    case 0:
+        break;
+    case ERROR_INVAL:
+        LOGEV(ERROR, rc, "non-existant domain %d", dis->domid);
+    default:
+        goto out;
+    }
+
+    switch (libxl__domain_type(gc, dis->domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        dis->dm_present = 1;
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        dis->pid = libxl__xs_read(gc, XBT_NULL,
+                        GCSPRINTF("/local/domain/%d/image/device-model-pid",
+                        dis->domid));
+        dis->dm_present = (dis->pid != NULL);
+        break;
+    default:
+        abort();
+    }
+
+    dis->dom_path = libxl__xs_get_dompath(gc, dis->domid);
+    if (!dis->dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl__device_pci_destroy_all(gc, dis->domid) < 0)
+        LOG(ERROR, "pci shutdown failed for domid %d", dis->domid);
+    rc = xc_domain_pause(CTX->xch, dis->domid);
+    if (rc < 0) {
+        LOGEV(ERROR, rc, "xc_domain_pause failed for %d", dis->domid);
+    }
+    if (dis->dm_present) {
+        rc = libxl__destroy_device_model(gc, dis->domid);
+        if (rc < 0)
+            LOG(ERROR, "libxl__destroy_device_model failed for %d",
+                        dis->domid);
+        libxl__qmp_cleanup(gc, dis->domid);
+    }
+    dis->drs.ao = ao;
+    dis->drs.domid = dis->domid;
+    dis->drs.callback = devices_destroy_cb;
+    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);
+
+    if (rc < 0)
+        LOG(DEBUG, "libxl__devices_destroy failed for %d", dis->domid);
+
+    dis->vm_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vm",
+                                                          dis->dom_path));
+    if (dis->vm_path)
+        if (!xs_rm(CTX->xsh, XBT_NULL, dis->vm_path))
+            LOG(ERROR, "xs_rm failed for %s", dis->vm_path);
+
+    if (!xs_rm(CTX->xsh, XBT_NULL, dis->dom_path))
+        LOG(ERROR, "xs_rm failed for %s", dis->dom_path);
+
+    xs_rm(CTX->xsh, XBT_NULL, libxl__xs_libxl_path(gc, dis->domid));
+
+    libxl__userdata_destroyall(gc, dis->domid);
+
+    rc = xc_domain_destroy(CTX->xch, dis->domid);
+    if (rc < 0) {
+        LOGEV(ERROR, rc, "xc_domain_destroy failed for %d", dis->domid);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = 0;
+
+out:
+    dis->callback(egc, dis, rc);
+    return;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 0ddfe72..e324da2 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -807,7 +807,6 @@ _hidden char *libxl__device_frontend_path(libxl__gc *gc, 
libxl__device *device);
 _hidden int libxl__parse_backend_path(libxl__gc *gc, const char *path,
                                       libxl__device *dev);
 _hidden int libxl__device_destroy(libxl__gc *gc, libxl__device *dev);
-_hidden int libxl__devices_destroy(libxl__gc *gc, uint32_t domid);
 _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state);
 
 /*
@@ -838,13 +837,6 @@ _hidden const char *libxl__device_nic_devname(libxl__gc 
*gc,
                                               uint32_t devid,
                                               libxl_nic_type type);
 
-/* Arranges that dev will be removed from its guest.  When
- * this is done, the ao will be completed.  An error
- * return from libxl__initiate_device_remove means that the ao
- * will _not_ be completed and the caller must do so. */
-_hidden int libxl__initiate_device_remove(libxl__egc*, libxl__ao*,
-                                          libxl__device *dev);
-
 /*
  * libxl__ev_devstate - waits a given time for a device to
  * reach a given state.  Follows the libxl_ev_* conventions.
@@ -1085,43 +1077,6 @@ static inline int libxl__spawn_inuse(libxl__spawn_state 
*ss)
 _hidden int libxl__spawn_record_pid(libxl__gc*, libxl__spawn_state*,
                                     pid_t innerchild);
 
-/*----- device model creation -----*/
-
-/* First layer; wraps libxl__spawn_spawn. */
-
-typedef struct libxl__dm_spawn_state libxl__dm_spawn_state;
-
-typedef void libxl__dm_spawn_cb(libxl__egc *egc, libxl__dm_spawn_state*,
-                                int rc /* if !0, error was logged */);
-
-struct libxl__dm_spawn_state {
-    /* mixed - spawn.ao must be initialised by user; rest is private: */
-    libxl__spawn_state spawn;
-    /* filled in by user, must remain valid: */
-    uint32_t guest_domid; /* domain being served */
-    libxl_domain_config *guest_config;
-    libxl__domain_build_state *build_state; /* relates to guest_domid */
-    libxl__dm_spawn_cb *callback;
-};
-
-_hidden void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state*);
-
-/* Stubdom device models. */
-
-typedef struct {
-    /* Mixed - user must fill in public parts EXCEPT callback,
-     * which may be undefined on entry.  (See above for details) */
-    libxl__dm_spawn_state dm; /* the stub domain device model */
-    /* filled in by user, must remain valid: */
-    libxl__dm_spawn_cb *callback; /* called as callback(,&sdss->dm,) */
-    /* private to libxl__spawn_stub_dm: */
-    libxl_domain_config dm_config;
-    libxl__domain_build_state dm_state;
-    libxl__dm_spawn_state pvqemu;
-} libxl__stub_dm_spawn_state;
-
-_hidden void libxl__spawn_stub_dm(libxl__egc *egc, 
libxl__stub_dm_spawn_state*);
-
 
 /*
  * libxl__wait_for_offspring - Wait for child state
@@ -1813,6 +1768,183 @@ _hidden void 
libxl__bootloader_init(libxl__bootloader_state *bl);
  * If callback is passed rc==0, will have updated st->info appropriately */
 _hidden void libxl__bootloader_run(libxl__egc*, libxl__bootloader_state *st);
 
+/*----- device addition/removal -----*/
+
+/* During the init/destruction process, the device can be in several states:
+ *
+ * DEVICE_UNKNOWN: device in unknown state (default value when struct is
+ * initialized).
+ *
+ * DEVICE_WAIT_BACKEND: waiting for the backend to switch to XenbusStateInit or
+ * XenbusStateClosed.
+ *
+ * DEVICE_WAIT_HOTPLUG: waiting for hotplug script to finish execution.
+ *
+ * DEVICE_FINISHED: device is connected/disconnected.
+ */
+typedef enum {
+    DEVICE_ACTIVE,
+    DEVICE_FINISHED
+} libxl__device_state;
+
+/* Action to perform (either connect or disconnect) */
+typedef enum {
+    DEVICE_CONNECT,
+    DEVICE_DISCONNECT
+} libxl__device_action;
+
+typedef struct libxl__ao_device libxl__ao_device;
+typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*);
+
+_hidden void libxl__init_ao_device(libxl__ao_device *aorm, libxl__ao *ao,
+                                   libxl__ao_device **base);
+_hidden int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device 
*device,
+                                        libxl__ao_device *list,
+                                        int num, int *last);
+
+struct libxl__ao_device {
+    libxl__ao *ao;
+    /* State in which the device is */
+    libxl__device_state state;
+    /* action being performed */
+    libxl__device_action action;
+    libxl__device *dev;
+    int force;
+    libxl__device_callback *callback;
+    /* private for implementation */
+    int rc;
+    libxl__ev_devstate ds;
+    void *base;
+};
+
+/* Arranges that dev will be removed to the guest, and the
+ * hotplug scripts will be executed (if necessary). When
+ * this is done (or an error happens), the callback in
+ * aorm->callback will be called.
+ */
+_hidden void libxl__initiate_device_remove(libxl__egc *egc,
+                                           libxl__ao_device *aorm);
+
+/*----- Domain destruction -----*/
+
+/* Domain destruction has been splitted in two functions:
+ *
+ * libxl__domain_destroy is the main destroy function, it detects
+ * stubdoms and calls libxl__destroy_domid on the domain and it's
+ * stubdom if present, creating a different libxl__destroy_domid_state
+ * for each one of them.
+ *
+ * libxl__destroy_domid actually destroys the domain, but it
+ * doesn't check for stubdomains, since that would involve
+ * recursion, which we want to avoid.
+ */
+
+typedef struct libxl__domain_destroy_state libxl__domain_destroy_state;
+typedef struct libxl__destroy_domid_state libxl__destroy_domid_state;
+typedef struct libxl__devices_remove_state libxl__devices_remove_state;
+
+typedef void libxl__domain_destroy_cb(libxl__egc *egc,
+                                      libxl__domain_destroy_state *dds,
+                                      int rc);
+
+typedef void libxl__domid_destroy_cb(libxl__egc *egc,
+                                     libxl__destroy_domid_state *dis,
+                                     int rc);
+
+typedef void libxl__devices_remove_callback(libxl__egc *egc,
+                                            libxl__devices_remove_state *drs,
+                                            int rc);
+
+struct libxl__devices_remove_state {
+    /* filled in by user */
+    libxl__ao *ao;
+    uint32_t domid;
+    libxl__devices_remove_callback *callback;
+    /* private */
+    libxl__ao_device *aorm;
+    int num_devices;
+};
+
+struct libxl__destroy_domid_state {
+    /* filled in by user */
+    libxl__ao *ao;
+    uint32_t domid;
+    libxl__domid_destroy_cb *callback;
+    /* private to implementation */
+    libxl__devices_remove_state drs;
+    char *dom_path;
+    char *vm_path;
+    char *pid;
+    int dm_present;
+};
+
+struct libxl__domain_destroy_state {
+    /* filled by the user */
+    libxl__ao *ao;
+    uint32_t domid;
+    libxl__domain_destroy_cb *callback;
+    /* Private */
+    uint32_t stubdomid;
+    libxl__destroy_domid_state stubdom;
+    int stubdom_finished;
+    libxl__destroy_domid_state domain;
+    int domain_finished;
+};
+
+/* 
+ * Entry point for domain destruction 
+ * This function checks for stubdom presence and then calls
+ * libxl__destroy_domid on the passed domain and it's stubdom if found.
+ */
+_hidden void libxl__domain_destroy(libxl__egc *egc,
+                                   libxl__domain_destroy_state *dds);
+
+/* Used to destroy a domain with the passed id (it doesn't check for stubs) */
+_hidden void libxl__destroy_domid(libxl__egc *egc,
+                                  libxl__destroy_domid_state *dis);
+
+/* Entry point for devices destruction */
+_hidden void libxl__devices_destroy(libxl__egc *egc,
+                                    libxl__devices_remove_state *drs);
+
+/*----- device model creation -----*/
+
+/* First layer; wraps libxl__spawn_spawn. */
+
+typedef struct libxl__dm_spawn_state libxl__dm_spawn_state;
+
+typedef void libxl__dm_spawn_cb(libxl__egc *egc, libxl__dm_spawn_state*,
+                                int rc /* if !0, error was logged */);
+
+struct libxl__dm_spawn_state {
+    /* mixed - spawn.ao must be initialised by user; rest is private: */
+    libxl__spawn_state spawn;
+    /* filled in by user, must remain valid: */
+    uint32_t guest_domid; /* domain being served */
+    libxl_domain_config *guest_config;
+    libxl__domain_build_state *build_state; /* relates to guest_domid */
+    libxl__dm_spawn_cb *callback;
+};
+
+_hidden void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state*);
+
+/* Stubdom device models. */
+
+typedef struct {
+    /* Mixed - user must fill in public parts EXCEPT callback,
+     * which may be undefined on entry.  (See above for details) */
+    libxl__dm_spawn_state dm; /* the stub domain device model */
+    /* filled in by user, must remain valid: */
+    libxl__dm_spawn_cb *callback; /* called as callback(,&sdss->dm,) */
+    /* private to libxl__spawn_stub_dm: */
+    libxl_domain_config dm_config;
+    libxl__domain_build_state dm_state;
+    libxl__dm_spawn_state pvqemu;
+    libxl__destroy_domid_state dis;
+} libxl__stub_dm_spawn_state;
+
+_hidden void libxl__spawn_stub_dm(libxl__egc *egc, 
libxl__stub_dm_spawn_state*);
+
 /*----- Domain creation -----*/
 
 typedef struct libxl__domain_create_state libxl__domain_create_state;
@@ -1835,6 +1967,8 @@ struct libxl__domain_create_state {
     libxl__stub_dm_spawn_state dmss;
         /* If we're not doing stubdom, we use only dmss.dm,
          * for the non-stubdom device model. */
+    /* necessary if the domain creation failed and we have to destroy it */
+    libxl__domain_destroy_state dds;
 };
 
 
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index efaf3de..3c02b69 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1333,7 +1333,7 @@ static int handle_domain_death(libxl_ctx *ctx, uint32_t 
domid,
         /* fall-through */
     case LIBXL_ACTION_ON_SHUTDOWN_DESTROY:
         LOG("Domain %d needs to be cleaned up: destroying the domain", domid);
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
         break;
 
     case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY:
@@ -1899,7 +1899,7 @@ start:
 error_out:
     release_lock();
     if (libxl_domid_valid_guest(domid))
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
 
 out:
     if (logfile != 2)
@@ -2390,7 +2390,7 @@ static void destroy_domain(const char *p)
         fprintf(stderr, "Cannot destroy privileged domain 0.\n\n");
         exit(-1);
     }
-    rc = libxl_domain_destroy(ctx, domid);
+    rc = libxl_domain_destroy(ctx, domid, 0);
     if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n",rc); exit(-1); }
 }
 
@@ -2664,7 +2664,7 @@ static int save_domain(const char *p, const char 
*filename, int checkpoint,
     if (checkpoint)
         libxl_domain_unpause(ctx, domid);
     else
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
 
     exit(0);
 }
@@ -2896,7 +2896,7 @@ static void migrate_domain(const char *domain_spec, const 
char *rune,
     }
 
     fprintf(stderr, "migration sender: Target reports successful startup.\n");
-    libxl_domain_destroy(ctx, domid); /* bang! */
+    libxl_domain_destroy(ctx, domid, 0); /* bang! */
     fprintf(stderr, "Migration successful.\n");
     exit(0);
 
@@ -3014,7 +3014,7 @@ static void migrate_receive(int debug, int daemonize, int 
monitor)
     if (rc) {
         fprintf(stderr, "migration target: Failure, destroying our copy.\n");
 
-        rc2 = libxl_domain_destroy(ctx, domid);
+        rc2 = libxl_domain_destroy(ctx, domid, 0);
         if (rc2) {
             fprintf(stderr, "migration target: Failed to destroy our copy"
                     " (code %d).\n", rc2);
diff --git a/tools/python/xen/lowlevel/xl/xl.c 
b/tools/python/xen/lowlevel/xl/xl.c
index c4f7c52..e144670 100644
--- a/tools/python/xen/lowlevel/xl/xl.c
+++ b/tools/python/xen/lowlevel/xl/xl.c
@@ -447,7 +447,7 @@ static PyObject *pyxl_domain_destroy(XlObject *self, 
PyObject *args)
     int domid;
     if ( !PyArg_ParseTuple(args, "i", &domid) )
         return NULL;
-    if ( libxl_domain_destroy(self->ctx, domid) ) {
+    if ( libxl_domain_destroy(self->ctx, domid, 0) ) {
         PyErr_SetString(xl_error_obj, "cannot destroy domain");
         return NULL;
     }
-- 
1.7.7.5 (Apple Git-26)


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


 


Rackspace

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