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

[Xen-devel] [PATCH v8 03/15] libxl: convert libxl_domain_destroy to an async 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.

Changes since v6:

 * Fixed typos.

Changes since v5:

 * Introduced a new struct, called libxl__ao_devices that will be used
   to simplify the addition/removal of multiple devices at the same
   time.

 * With this function we can use a generic callback for ao_device,
   libxl__ao_devices_callback, that will check if the device is the
   last one and call ao_devices->callback appropiately.

Changes since v4:

 * Fixed spelling mistakes.

 * Always use "force = 1" in device destruction in
   libxl__destroy_domid function.

 * Changed name of domain destroy callbacks to include "destroy".

 * Changed the use of rc to catch syscall errors.

 * Use libxl__remove_file instead of unlink.

 * Changed variable name of number of devices returned by
   libxl__xs_directory.

 * Simplify libxl__ao_device_check_last return.

 * Correctly propagate error returned from libxl__num_devices.

 * Add a comment about the use of libxl__device_destroy to destroy the
   console.

 * Fixed some uses of LIBXL__LOG.

Changes since v3:

 * Fixed python bindings.

Changes since v2:

 * Remove printfs.

 * Replace aorm with aodev.

 * Define an auxiliary libxl__ao_device *aodev to avoid using the long
   expression: drs->aorm[numdev]...

 * Added a common callback for both domain and stubdomain destruction
   that checks if both domains are finished and handles errors
   correctly.

 * Change libxl__ao_device_check_last logic a bit and add a comment
   describing how does it work.

 * Fixed spelling mistakes.

 * Use a do-while for xs transaction in device_remove_callback.

Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
---
 tools/libxl/libxl.c               |  176 +++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl.h               |    3 +-
 tools/libxl/libxl_create.c        |   29 +++++-
 tools/libxl/libxl_device.c        |  152 ++++++++++++++++++++++++++++----
 tools/libxl/libxl_dm.c            |   85 +++++++++----------
 tools/libxl/libxl_internal.h      |  116 ++++++++++++++++++++++++-
 tools/libxl/xl_cmdimpl.c          |   12 ++--
 tools/python/xen/lowlevel/xl/xl.c |    2 +-
 8 files changed, 490 insertions(+), 85 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index fd44fd7..7e6d5c9 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1216,11 +1216,133 @@ 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)
+/* 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)
 {
-    GC_INIT(ctx);
+    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)
+        LOG(ERROR, "destruction of domain %u failed", dds->domid);
+
+    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;
+        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;
+    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) {
+        LOG(ERROR, "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);
+    /*
+     * On suspend libxl__domain_save_device_model will have already
+     * unlinked the save file.
+     */
+    if (rc) {
+        LOG(ERROR, "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) {
+        LOG(ERROR, "unable to destroy guest with domid %u", dis->domid);
+        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);
+
+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;
-    char *vm_path;
     char *pid;
     int rc, dm_present;
 
@@ -1231,12 +1353,15 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
     case ERROR_INVAL:
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "non-existant domain %d", domid);
     default:
-        return rc;
+        goto out;
     }
 
     switch (libxl__domain_type(gc, domid)) {
     case LIBXL_DOMAIN_TYPE_HVM:
-        dm_present = 1;
+        if (!libxl_get_stubdom_id(CTX, domid))
+            dm_present = 1;
+        else
+            dm_present = 0;
         break;
     case LIBXL_DOMAIN_TYPE_PV:
         pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, 
"/local/domain/%d/image/device-model-pid", domid));
@@ -1267,7 +1392,37 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
 
         libxl__qmp_cleanup(gc, domid);
     }
-    if (libxl__devices_destroy(gc, domid) < 0)
+    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;
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (rc < 0)
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 
                    "libxl__devices_destroy failed for %d", domid);
 
@@ -1280,6 +1435,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
         LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "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, libxl__sprintf(gc,
+                                "/local/domain/0/device-model/%d", domid));
+    xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(gc,
+                                "/local/domain/%d/hvmloader", domid));
 
     libxl__userdata_destroyall(gc, domid);
 
@@ -1290,9 +1449,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
         goto out;
     }
     rc = 0;
+
 out:
-    GC_FREE;
-    return rc;
+    dis->callback(egc, dis, rc);
+    return;
 }
 
 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 75175c7..aef1be5 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -526,7 +526,8 @@ int libxl_domain_remus_start(libxl_ctx *ctx, 
libxl_domain_remus_info *info,
 
 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 2ddf5fb..b54717a 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -571,6 +571,12 @@ 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)
 {
@@ -996,16 +1002,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, ERROR_FAIL, 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 8316707..8daf69d 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, xs_transaction_t t,
         libxl__device *device, char **bents, char **fents)
 {
@@ -367,6 +409,37 @@ void libxl__prepare_ao_device(libxl__ao *ao, 
libxl__ao_device *aodev)
 {
     aodev->ao = ao;
     aodev->rc = 0;
+    aodev->active = 1;
+}
+
+void libxl__prepare_ao_devices(libxl__ao *ao, libxl__ao_devices *aodevs)
+{
+    AO_GC;
+
+    GCNEW_ARRAY(aodevs->array, aodevs->size);
+    for (int i = 0; i < aodevs->size; i++) {
+        aodevs->array[i].aodevs = aodevs;
+        libxl__prepare_ao_device(ao, &aodevs->array[i]);
+    }
+}
+
+void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__ao_devices *aodevs = aodev->aodevs;
+    int i, error = 0;
+
+    aodev->active = 0;
+    for (i = 0; i < aodevs->size; i++) {
+        if (aodevs->array[i].active)
+            return;
+
+        if (aodevs->array[i].rc)
+            error = aodevs->array[i].rc;
+    }
+
+    aodevs->callback(egc, aodevs, error);
+    return;
 }
 
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
@@ -383,16 +456,35 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device 
*dev)
     return 0;
 }
 
-int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
+/* Callback for device destruction */
+
+static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                    int rc);
+
+void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
 {
+    STATE_AO_GC(drs->ao);
     libxl_ctx *ctx = libxl__gc_owner(gc);
+    uint32_t domid = drs->domid;
     char *path;
-    unsigned int num_kinds, num_devs;
+    unsigned int num_kinds, num_dev_xsentries;
     char **kinds = NULL, **devs = NULL;
-    int i, j;
-    libxl__device dev;
+    int i, j, numdev = 0, rc = 0;
+    libxl__device *dev;
+    libxl__ao_devices *aodevs = &drs->aodevs;
+    libxl__ao_device *aodev;
     libxl__device_kind kind;
 
+    aodevs->size = libxl__num_devices(gc, drs->domid);
+    if (aodevs->size < 0) {
+        LOG(ERROR, "unable to get number of devices for domain %u", 
drs->domid);
+        rc = aodevs->size;
+        goto out;
+    }
+
+    libxl__prepare_ao_devices(drs->ao, aodevs);
+    aodevs->callback = devices_remove_callback;
+
     path = libxl__sprintf(gc, "/local/domain/%d/device", domid);
     kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
     if (!kinds) {
@@ -408,19 +500,25 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
             continue;
 
         path = libxl__sprintf(gc, "/local/domain/%d/device/%s", domid, 
kinds[i]);
-        devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs);
+        devs = libxl__xs_directory(gc, XBT_NULL, path, &num_dev_xsentries);
         if (!devs)
             continue;
-        for (j = 0; j < num_devs; j++) {
+        for (j = 0; j < num_dev_xsentries; j++) {
             path = libxl__sprintf(gc, "/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) {
-                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) {
+                aodev = &aodevs->array[numdev];
+                dev->domid = domid;
+                dev->kind = kind;
+                dev->devid = atoi(devs[j]);
+                aodev->action = DEVICE_DISCONNECT;
+                aodev->dev = dev;
+                aodev->callback = libxl__ao_devices_callback;
+                aodev->force = drs->force;
+                libxl__initiate_device_remove(egc, aodev);
+                numdev++;
             }
         }
     }
@@ -428,17 +526,22 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
     /* console 0 frontend directory is not under /local/domain/<domid>/device 
*/
     path = libxl__sprintf(gc, "/local/domain/%d/console/backend", 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__device_destroy(gc, &dev);
+        libxl__parse_backend_path(gc, path, dev) == 0) {
+        dev->domid = domid;
+        dev->kind = LIBXL__DEVICE_KIND_CONSOLE;
+        dev->devid = 0;
+
+        /* Currently console devices can be destroyed synchronously by just
+         * removing xenstore entries, this is what libxl__device_destroy does.
+         */
+        libxl__device_destroy(gc, dev);
     }
 
 out:
-    return 0;
+    if (!numdev) drs->callback(egc, drs, rc);
+    return;
 }
 
 /* Callbacks for device related operations */
@@ -536,6 +639,7 @@ static void device_backend_callback(libxl__egc *egc, 
libxl__ev_devstate *ds,
     } else if (rc) {
         LOG(DEBUG, "unable to disconnect device with path %s",
                    libxl__device_backend_path(gc, aodev->dev));
+        rc = 0;
         goto out;
     }
 
@@ -578,6 +682,16 @@ out:
     return;
 }
 
+static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                    int rc)
+{
+    libxl__devices_remove_state *drs = CONTAINER_OF(aodevs, *drs, aodevs);
+    STATE_AO_GC(drs->ao);
+
+    drs->callback(egc, drs, rc);
+    return;
+}
+
 int libxl__wait_for_device_model(libxl__gc *gc,
                                  uint32_t domid, char *state,
                                  libxl__spawn_starting *spawning,
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index acba613..361b77d 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -694,6 +694,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);
@@ -914,12 +918,31 @@ 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);
+            return;
+        }
     }
     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);
@@ -1115,55 +1138,27 @@ static void device_model_spawn_outcome(libxl__egc *egc,
 
 int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid)
 {
-    libxl_ctx *ctx = libxl__gc_owner(gc);
     char *pid;
     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)) {
+        LOG(ERROR, "could not find device-model's pid for dom %u", domid);
+        ret = ERROR_FAIL;
+        goto out;
+    }
+    ret = kill(atoi(pid), SIGHUP);
+    if (ret < 0 && errno == ESRCH) {
+        LOG(ERROR, "Device Model already exited");
+        ret = 0;
+    } else if (ret == 0) {
+        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;
-        }
+        LOGE(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));
 
 out:
     return ret;
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 61fd100..7aa46b8 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -868,7 +868,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);
 
 /*
@@ -1971,6 +1970,7 @@ typedef enum {
 } libxl__device_action;
 
 typedef struct libxl__ao_device libxl__ao_device;
+typedef struct libxl__ao_devices libxl__ao_devices;
 typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*);
 
 /* This functions sets the necessary libxl__ao_device struct values to use
@@ -1989,6 +1989,20 @@ typedef void libxl__device_callback(libxl__egc*, 
libxl__ao_device*);
  */
 _hidden void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev);
 
+/* Prepare a bunch of devices for addition/removal. Every ao_device in
+ * ao_devices is set to 'active', and the ao_device 'base' field is set to
+ * the one pointed by aodevs.
+ */
+_hidden void libxl__prepare_ao_devices(libxl__ao *ao,
+                                       libxl__ao_devices *aodevs);
+
+/* Generic callback to use when adding/removing several devices, this will
+ * check if the given aodev is the last one, and call the callback in the
+ * parent libxl__ao_devices struct, passing the appropriate error if found.
+ */
+_hidden void libxl__ao_devices_callback(libxl__egc *egc,
+                                        libxl__ao_device *aodev);
+
 struct libxl__ao_device {
     /* filled in by user */
     libxl__ao *ao;
@@ -1997,8 +2011,25 @@ struct libxl__ao_device {
     int force;
     libxl__device_callback *callback;
     /* private for implementation */
+    int active;
     int rc;
     libxl__ev_devstate backend_ds;
+    /* Used internally to have a reference to the upper libxl__ao_devices
+     * struct when present */
+    libxl__ao_devices *aodevs;
+};
+
+/* Helper struct to simply the plug/unplug of multiple devices at the same
+ * time.
+ *
+ * This structure holds several devices, and the callback is only called
+ * when all the devices inside of the array have finished.
+ */
+typedef void libxl__devices_callback(libxl__egc*, libxl__ao_devices*, int rc);
+struct libxl__ao_devices {
+    libxl__ao_device *array;
+    int size;
+    libxl__devices_callback *callback;
 };
 
 /* Arranges that dev will be removed to the guest, and the
@@ -2013,6 +2044,86 @@ struct libxl__ao_device {
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*----- Domain destruction -----*/
+
+/* Domain destruction has been split into two functions:
+ *
+ * libxl__domain_destroy is the main destroy function, which detects
+ * stubdoms and calls libxl__destroy_domid on the domain and its
+ * 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;
+    int force; /* libxl_device_TYPE_destroy rather than _remove */
+    /* private */
+    libxl__ao_devices aodevs;
+    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;
+};
+
+struct libxl__domain_destroy_state {
+    /* filled by the user */
+    libxl__ao *ao;
+    uint32_t domid;
+    libxl__domain_destroy_cb *callback;
+    /* Private */
+    int rc;
+    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 its 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. */
@@ -2046,6 +2157,7 @@ typedef struct {
     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*);
@@ -2073,6 +2185,8 @@ struct libxl__domain_create_state {
         /* If we're not doing stubdom, we use only dmss.dm,
          * for the non-stubdom device model. */
     libxl__save_helper_state shs;
+    /* necessary if the domain creation failed and we have to destroy it */
+    libxl__domain_destroy_state dds;
 };
 
 /*----- Domain suspend (save) functions -----*/
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 5040210..b3d8b7a 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1401,7 +1401,7 @@ static int handle_domain_death(uint32_t *r_domid,
     case LIBXL_ACTION_ON_SHUTDOWN_DESTROY:
         LOG("Domain %d needs to be cleaned up: destroying the domain",
             *r_domid);
-        libxl_domain_destroy(ctx, *r_domid);
+        libxl_domain_destroy(ctx, *r_domid, 0);
         *r_domid = INVALID_DOMID;
         break;
 
@@ -2011,7 +2011,7 @@ start:
 error_out:
     release_lock();
     if (libxl_domid_valid_guest(domid)) {
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
         domid = INVALID_DOMID;
     }
 
@@ -2576,7 +2576,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); }
 }
 
@@ -2850,7 +2850,7 @@ static int save_domain(const char *p, const char 
*filename, int checkpoint,
     if (checkpoint)
         libxl_domain_resume(ctx, domid, 1);
     else
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
 
     exit(0);
 }
@@ -3107,7 +3107,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);
 
@@ -3260,7 +3260,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 1db777d..4ff3120 100644
--- a/tools/python/xen/lowlevel/xl/xl.c
+++ b/tools/python/xen/lowlevel/xl/xl.c
@@ -437,7 +437,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®.