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

[Xen-changelog] [xen-unstable] libxl: change ao_device_remove to ao_device


  • To: xen-changelog@xxxxxxxxxxxxxxxxxxx
  • From: Xen patchbot-unstable <patchbot@xxxxxxx>
  • Date: Mon, 23 Jul 2012 19:55:10 +0000
  • Delivery-date: Mon, 23 Jul 2012 19:55:22 +0000
  • List-id: "Change log for Mercurial \(receive only\)" <xen-changelog.lists.xen.org>

# HG changeset patch
# User Roger Pau Monne <roger.pau@xxxxxxxxxx>
# Date 1343045380 -3600
# Node ID 971c3ab60288c004aadda2fdad585d21d9ce8cf1
# Parent  9387f8c77f9aa859f1eee7d4a86a6e8585a555fd
libxl: change ao_device_remove to ao_device

Introduce a new structure to track state of device backends, that will
be used in following patches on this series.

This structure if used for both device creation and device
destruction and removes libxl__ao_device_remove.

Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Committed-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---


diff -r 9387f8c77f9a -r 971c3ab60288 tools/libxl/libxl.c
--- a/tools/libxl/libxl.c       Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/libxl/libxl.c       Mon Jul 23 13:09:40 2012 +0100
@@ -1503,6 +1503,31 @@ int libxl_vncviewer_exec(libxl_ctx *ctx,
 
 
/******************************************************************************/
 
+/* generic callback for devices that only need to set ao_complete */
+static void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    if (aodev->rc) {
+        if (aodev->dev) {
+            LOG(ERROR, "unable to %s %s with id %u",
+                        aodev->action == DEVICE_CONNECT ? "add" : "remove",
+                        libxl__device_kind_to_string(aodev->dev->kind),
+                        aodev->dev->devid);
+        } else {
+            LOG(ERROR, "unable to %s device",
+                       aodev->action == DEVICE_CONNECT ? "add" : "remove");
+        }
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, aodev->rc);
+    return;
+}
+
+/******************************************************************************/
+
 int libxl__device_disk_setdefault(libxl__gc *gc, libxl_device_disk *disk)
 {
     int rc;
@@ -1680,42 +1705,6 @@ int libxl_device_disk_add(libxl_ctx *ctx
     return rc;
 }
 
-int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
-                             libxl_device_disk *disk,
-                             const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
-    int rc;
-
-    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;
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_ABORT(rc);
-}
-
-int libxl_device_disk_destroy(libxl_ctx *ctx, uint32_t domid,
-                              libxl_device_disk *disk)
-{
-    GC_INIT(ctx);
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_from_disk(gc, domid, disk, &device);
-    if (rc != 0) goto out;
-
-    rc = libxl__device_destroy(gc, &device);
-out:
-    GC_FREE;
-    return rc;
-}
-
 static void libxl__device_disk_from_xs_be(libxl__gc *gc,
                                           const char *be_path,
                                           libxl_device_disk *disk)
@@ -2080,8 +2069,9 @@ int libxl__device_disk_local_detach(libx
             if (disk->vdev != NULL) {
                 libxl_device_disk_remove(gc->owner, LIBXL_TOOLSTACK_DOMID,
                         disk, 0);
+                /* fixme-ao */
                 rc = libxl_device_disk_destroy(gc->owner,
-                        LIBXL_TOOLSTACK_DOMID, disk);
+                        LIBXL_TOOLSTACK_DOMID, disk, 0);
             }
             break;
         default:
@@ -2249,42 +2239,6 @@ out:
     return rc;
 }
 
-int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid,
-                            libxl_device_nic *nic,
-                            const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
-    int rc;
-
-    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;
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_ABORT(rc);
-}
-
-int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_device_nic *nic)
-{
-    GC_INIT(ctx);
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_from_nic(gc, domid, nic, &device);
-    if (rc != 0) goto out;
-
-    rc = libxl__device_destroy(gc, &device);
-out:
-    GC_FREE;
-    return rc;
-}
-
 static void libxl__device_nic_from_xs_be(libxl__gc *gc,
                                          const char *be_path,
                                          libxl_device_nic *nic)
@@ -2611,42 +2565,6 @@ out:
     return rc;
 }
 
-int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t domid,
-                            libxl_device_vkb *vkb,
-                            const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
-    int rc;
-
-    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;
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_ABORT(rc);
-}
-
-int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_device_vkb *vkb)
-{
-    GC_INIT(ctx);
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
-    if (rc != 0) goto out;
-
-    rc = libxl__device_destroy(gc, &device);
-out:
-    GC_FREE;
-    return rc;
-}
-
 
/******************************************************************************/
 
 int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb)
@@ -2744,41 +2662,66 @@ out:
     return rc;
 }
 
-int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t domid,
-                            libxl_device_vfb *vfb,
-                            const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    libxl__device device;
-    int rc;
-
-    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;
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_ABORT(rc);
-}
-
-int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid,
-                                  libxl_device_vfb *vfb)
-{
-    GC_INIT(ctx);
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
-    if (rc != 0) goto out;
-
-    rc = libxl__device_destroy(gc, &device);
-out:
-    GC_FREE;
-    return rc;
-}
+/******************************************************************************/
+
+/* Macro for defining device remove/destroy functions in a compact way */
+/* The following functions are defined:
+ * libxl_device_disk_remove
+ * libxl_device_disk_destroy
+ * libxl_device_nic_remove
+ * libxl_device_nic_destroy
+ * libxl_device_vkb_remove
+ * libxl_device_vkb_destroy
+ * libxl_device_vfb_remove
+ * libxl_device_vfb_destroy
+ */
+#define DEFINE_DEVICE_REMOVE(type, removedestroy, f)                    \
+    int libxl_device_##type##_##removedestroy(libxl_ctx *ctx,           \
+        uint32_t domid, libxl_device_##type *type,                      \
+        const libxl_asyncop_how *ao_how)                                \
+    {                                                                   \
+        AO_CREATE(ctx, domid, ao_how);                                  \
+        libxl__device *device;                                          \
+        libxl__ao_device *aodev;                                        \
+        int rc;                                                         \
+                                                                        \
+        GCNEW(device);                                                  \
+        rc = libxl__device_from_##type(gc, domid, type, device);        \
+        if (rc != 0) goto out;                                          \
+                                                                        \
+        GCNEW(aodev);                                                   \
+        libxl__prepare_ao_device(ao, aodev);                            \
+        aodev->action = DEVICE_DISCONNECT;                              \
+        aodev->dev = device;                                            \
+        aodev->callback = device_addrm_aocomplete;                      \
+        aodev->force = f;                                               \
+        libxl__initiate_device_remove(egc, aodev);                      \
+                                                                        \
+    out:                                                                \
+        if (rc) return AO_ABORT(rc);                                    \
+        return AO_INPROGRESS;                                           \
+    }
+
+/* Define all remove/destroy functions and undef the macro */
+
+/* disk */
+DEFINE_DEVICE_REMOVE(disk, remove, 0)
+DEFINE_DEVICE_REMOVE(disk, destroy, 1)
+
+/* nic */
+DEFINE_DEVICE_REMOVE(nic, remove, 0)
+DEFINE_DEVICE_REMOVE(nic, destroy, 1)
+
+/* vkb */
+DEFINE_DEVICE_REMOVE(vkb, remove, 0)
+DEFINE_DEVICE_REMOVE(vkb, destroy, 1)
+
+/* vfb */
+
+DEFINE_DEVICE_REMOVE(vfb, remove, 0)
+DEFINE_DEVICE_REMOVE(vfb, destroy, 1)
+
+#undef DEFINE_DEVICE_REMOVE
 
 
/******************************************************************************/
 
diff -r 9387f8c77f9a -r 971c3ab60288 tools/libxl/libxl.h
--- a/tools/libxl/libxl.h       Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/libxl/libxl.h       Mon Jul 23 13:09:40 2012 +0100
@@ -679,7 +679,8 @@ int libxl_device_disk_remove(libxl_ctx *
                              libxl_device_disk *disk,
                              const libxl_asyncop_how *ao_how);
 int libxl_device_disk_destroy(libxl_ctx *ctx, uint32_t domid,
-                              libxl_device_disk *disk);
+                              libxl_device_disk *disk,
+                              const libxl_asyncop_how *ao_how);
 
 libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int 
*num);
 int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
@@ -696,7 +697,9 @@ int libxl_device_nic_add(libxl_ctx *ctx,
 int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_nic *nic,
                             const libxl_asyncop_how *ao_how);
-int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_nic 
*nic);
+int libxl_device_nic_destroy(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_nic *nic,
+                             const libxl_asyncop_how *ao_how);
 
 libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int 
*num);
 int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid,
@@ -707,14 +710,18 @@ int libxl_device_vkb_add(libxl_ctx *ctx,
 int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_vkb *vkb,
                             const libxl_asyncop_how *ao_how);
-int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb 
*vkb);
+int libxl_device_vkb_destroy(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_vkb *vkb,
+                             const libxl_asyncop_how *ao_how);
 
 /* Framebuffer */
 int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb 
*vfb);
 int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_vfb *vfb,
                             const libxl_asyncop_how *ao_how);
-int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb 
*vfb);
+int libxl_device_vfb_destroy(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_vfb *vfb,
+                             const libxl_asyncop_how *ao_how);
 
 /* PCI Passthrough */
 int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev);
diff -r 9387f8c77f9a -r 971c3ab60288 tools/libxl/libxl_device.c
--- a/tools/libxl/libxl_device.c        Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/libxl/libxl_device.c        Mon Jul 23 13:09:40 2012 +0100
@@ -361,11 +361,16 @@ int libxl__device_disk_dev_number(const 
     return -1;
 }
 
+/* Device AO operations */
 
-typedef struct {
-    libxl__ao *ao;
-    libxl__ev_devstate ds;
-} libxl__ao_device_remove;
+void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev)
+{
+    aodev->ao = ao;
+    aodev->rc = 0;
+    aodev->dev = NULL;
+    /* Initialize timer for QEMU Bodge */
+    libxl__ev_time_init(&aodev->timeout);
+}
 
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
@@ -441,36 +446,81 @@ out:
 
 /* Callbacks for device related operations */
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+/*
+ * device_backend_callback is the main callback entry point, for both device
+ * addition and removal. It gets called if we reach the desired state
+ * (XenbusStateClosed or XenbusStateInitWait). After that, all this
+ * functions get called in the order displayed below.
+ *
+ * If new device types are added, they should only need to modify the
+ * specific hotplug scripts call, which can be found in each OS specific
+ * file. If this new devices don't need a hotplug script, no modification
+ * should be needed.
+ */
+
+/* This callback is part of the Qemu devices Badge */
+static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                const struct timeval *requested_abs);
+
+static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
                                    int rc);
 
-static void device_remove_cleanup(libxl__gc *gc,
-                                  libxl__ao_device_remove *aorm);
+static void device_backend_cleanup(libxl__gc *gc,
+                                   libxl__ao_device *aodev);
 
-int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao,
-                                  libxl__device *dev)
+static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
+
+void libxl__initiate_device_remove(libxl__egc *egc,
+                                   libxl__ao_device *aodev)
 {
-    AO_GC;
+    STATE_AO_GC(aodev->ao);
     xs_transaction_t t = 0;
-    char *be_path = libxl__device_backend_path(gc, dev);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
     char *state_path = libxl__sprintf(gc, "%s/state", be_path);
     char *online_path = GCSPRINTF("%s/online", be_path);
     const char *state;
+    libxl_dominfo info;
+    uint32_t domid = aodev->dev->domid;
+    int rc = 0;
 
-    int rc = 0;
-    libxl__ao_device_remove *aorm = 0;
+    libxl_dominfo_init(&info);
+    rc = libxl_domain_info(CTX, &info, domid);
+    if (rc) {
+        LOG(ERROR, "unable to get info for domain %d", domid);
+        goto out;
+    }
+    if (QEMU_BACKEND(aodev->dev) &&
+        (info.paused || info.dying || info.shutdown)) {
+        /*
+         * TODO: 4.2 Bodge due to QEMU, see comment on top of
+         * libxl__initiate_device_remove in libxl_internal.h
+         */
+        rc = libxl__ev_time_register_rel(gc, &aodev->timeout,
+                                         device_qemu_timeout,
+                                         LIBXL_QEMU_BODGE_TIMEOUT * 1000);
+        if (rc) {
+            LOG(ERROR, "unable to register timeout for Qemu device %s",
+                       be_path);
+            goto out;
+        }
+        return;
+    }
 
     for (;;) {
         rc = libxl__xs_transaction_start(gc, &t);
         if (rc) {
             LOG(ERROR, "unable to start transaction");
-            goto out_fail;
+            goto out;
         }
 
+        if (aodev->force)
+            libxl__xs_path_cleanup(gc, t,
+                                   libxl__device_frontend_path(gc, 
aodev->dev));
+
         rc = libxl__xs_read_checked(gc, t, state_path, &state);
         if (rc) {
             LOG(ERROR, "unable to read device state from path %s", state_path);
-            goto out_fail;
+            goto out;
         }
 
         /*
@@ -481,53 +531,118 @@ int libxl__initiate_device_remove(libxl_
             rc = libxl__xs_write_checked(gc, t, online_path, "0");
             if (rc) {
                 LOG(ERROR, "unable to write to xenstore path %s", online_path);
-                goto out_fail;
+                goto out;
             }
             rc = libxl__xs_write_checked(gc, t, state_path, "5");
             if (rc) {
                 LOG(ERROR, "unable to write to xenstore path %s", state_path);
-                goto out_fail;
+                goto out;
             }
         }
 
         rc = libxl__xs_transaction_commit(gc, &t);
         if (!rc) break;
-        if (rc < 0) goto out_fail;
+        if (rc < 0) goto out;
     }
 
     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, &aodev->backend_ds,
+                                 device_backend_callback,
                                  state_path, XenbusStateClosed,
                                  LIBXL_DESTROY_TIMEOUT * 1000);
-    if (rc) goto out_fail;
+    if (rc) {
+        LOG(ERROR, "unable to remove device %s", be_path);
+        goto out;
+    }
 
-    libxl__ao_complete(egc, ao, 0);
-    return 0;
+    libxl_dominfo_dispose(&info);
+    return;
 
- out_fail:
-    assert(rc);
+out:
+    aodev->rc = rc;
+    libxl_dominfo_dispose(&info);
     libxl__xs_transaction_abort(gc, &t);
-    device_remove_cleanup(gc, aorm);
-    return rc;
+    device_hotplug_done(egc, aodev);
+    return;
 }
 
-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);
+static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                const struct timeval *requested_abs)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(ev, *aodev, timeout);
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char *state_path = GCSPRINTF("%s/state", be_path);
+    int rc = 0;
+
+    libxl__ev_time_deregister(gc, &aodev->timeout);
+
+    rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6");
+    if (rc) goto out;
+
+out:
+    aodev->rc = rc;
+    device_hotplug_done(egc, aodev);
 }
 
-static void device_remove_cleanup(libxl__gc *gc,
-                                  libxl__ao_device_remove *aorm) {
-    if (!aorm) return;
-    libxl__ev_devstate_cancel(gc, &aorm->ds);
+static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+                                   int rc) {
+    libxl__ao_device *aodev = CONTAINER_OF(ds, *aodev, backend_ds);
+    STATE_AO_GC(aodev->ao);
+
+    device_backend_cleanup(gc, aodev);
+
+    if (rc == ERROR_TIMEDOUT && aodev->action == DEVICE_DISCONNECT &&
+        !aodev->force) {
+        aodev->force = 1;
+        libxl__initiate_device_remove(egc, aodev);
+        return;
+    }
+
+    if (rc) {
+        LOG(ERROR, "unable to disconnect device with path %s",
+                   libxl__device_backend_path(gc, aodev->dev));
+        goto out;
+    }
+
+out:
+    aodev->rc = rc;
+    device_hotplug_done(egc, aodev);
+    return;
+}
+
+static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
+{
+    if (!aodev) return;
+    libxl__ev_devstate_cancel(gc, &aodev->backend_ds);
+}
+
+static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char *fe_path = libxl__device_frontend_path(gc, aodev->dev);
+    xs_transaction_t t = 0;
+    int rc;
+
+    if (aodev->action == DEVICE_DISCONNECT) {
+        for (;;) {
+            rc = libxl__xs_transaction_start(gc, &t);
+            if (rc) goto out;
+
+            libxl__xs_path_cleanup(gc, t, fe_path);
+            libxl__xs_path_cleanup(gc, t, be_path);
+
+            rc = libxl__xs_transaction_commit(gc, &t);
+            if (!rc) break;
+            if (rc < 0) goto out;
+        }
+    }
+
+out:
+    aodev->callback(egc, aodev);
+    return;
 }
 
 int libxl__wait_for_device_model(libxl__gc *gc,
diff -r 9387f8c77f9a -r 971c3ab60288 tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/libxl/libxl_internal.h      Mon Jul 23 13:09:40 2012 +0100
@@ -74,6 +74,7 @@
 
 #define LIBXL_DESTROY_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
+#define LIBXL_QEMU_BODGE_TIMEOUT 2
 #define LIBXL_XENCONSOLE_LIMIT 1048576
 #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
 #define LIBXL_MAXMEM_CONSTANT 1024
@@ -350,6 +351,12 @@ typedef struct {
     libxl__device_kind kind;
 } libxl__device;
 
+/* Used to know if backend of given device is QEMU */
+#define QEMU_BACKEND(dev) (\
+    (dev)->backend_kind == LIBXL__DEVICE_KIND_QDISK || \
+    (dev)->backend_kind == LIBXL__DEVICE_KIND_VFB || \
+    (dev)->backend_kind == LIBXL__DEVICE_KIND_VKBD)
+
 #define XC_PCI_BDF             "0x%x, 0x%x, 0x%x, 0x%x"
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 #define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
@@ -899,13 +906,6 @@ _hidden const char *libxl__device_nic_de
                                               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.
@@ -2007,6 +2007,135 @@ _hidden void libxl__bootloader_init(libx
  * 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 -----*/
+
+/* 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*);
+
+/* This functions sets the necessary libxl__ao_device struct values to use
+ * safely inside functions. It marks the operation as "active"
+ * since we need to be sure that all device status structs are set
+ * to active before start queueing events, or we might call
+ * ao_complete before all devices had finished
+ *
+ * libxl__initiate_device_{remove/addition} should not be called without
+ * calling libxl__prepare_ao_device first, since it initializes the private
+ * fields of the struct libxl__ao_device to what this functions expect.
+ *
+ * Once _prepare has been called on a libxl__ao_device, it is safe to just
+ * discard this struct, there's no need to call any destroy function.
+ * _prepare can also be called multiple times with the same libxl__ao_device.
+ */
+_hidden void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev);
+
+struct libxl__ao_device {
+    /* filled in by user */
+    libxl__ao *ao;
+    libxl__device_action action;
+    libxl__device *dev;
+    int force;
+    libxl__device_callback *callback;
+    /* private for implementation */
+    int rc;
+    libxl__ev_devstate backend_ds;
+    /* Bodge for Qemu devices */
+    libxl__ev_time timeout;
+};
+
+/*
+ * Algorithm for handling device removal (including domain
+ * destruction).  This is somewhat subtle because we may already have
+ * killed the domain and caused the death of qemu.
+ *
+ * In current versions of qemu there is no mechanism for ensuring that
+ * the resources used by its devices (both emulated and any PV devices
+ * provided by qemu) are freed (eg, fds closed) before it shuts down,
+ * and no confirmation from a terminating qemu back to the toolstack.
+ *
+ * This will need to be fixed in Xen 4.3.  In the meantime (Xen 4.2)
+ * we implement a bodge.
+ *
+ *      WE WANT TO UNPLUG         WE WANT TO SHUT DOWN OR DESTROY
+ *                    |                           |
+ *                    |             LIBXL SENDS SIGHUP TO QEMU
+ *                    |      .....................|........................
+ *                    |      : XEN 4.3+ PLANNED   |                       :
+ *                    |      :      QEMU TEARS DOWN ALL DEVICES           :
+ *                    |      :      FREES RESOURCES (closing fds)         :
+ *                    |      :      SETS PV BACKENDS TO STATE 5,          :
+ *                    |      :       waits for PV frontends to shut down  :
+ *                    |      :       SETS PV BACKENDS TO STATE 6          :
+ *                    |      :                    |                       :
+ *                    |      :      QEMU NOTIFIES TOOLSTACK (via          :
+ *                    |      :       xenstore) that it is exiting         :
+ *                    |      :      QEMU EXITS (parent may be init)       :
+ *                    |      :                    |                       :
+ *                    |      :        TOOLSTACK WAITS FOR QEMU            :
+ *                    |      :        notices qemu has finished           :
+ *                    |      :....................|.......................:
+ *                    |      .--------------------'
+ *                    V      V
+ *                  for each device
+ *                 we want to unplug/remove
+ *       ..................|...........................................
+ *       :                 V                       XEN 4.2 RACY BODGE :
+ *       :      device is provided by    qemu                         :
+ *       :            |            `-----------.                      :
+ *       :   something|                        V                      :
+ *       :    else, eg|             domain (that is domain for which  :
+ *       :     blkback|              this PV device is the backend,   :
+ *       :            |              which might be the stub dm)      :
+ *       :            |                is still alive?                :
+ *       :            |                  |        |                   :
+ *       :            |                  |alive   |dead               :
+ *       :            |<-----------------'        |                   :
+ *       :            |    hopefully qemu is      |                   :
+ *       :            |       still running       |                   :
+ *       :............|.................          |                   :
+ *             ,----->|                :     we may be racing         :
+ *             |    backend state?     :      with qemu's death       :
+ *             ^      |         |      :          |                   :
+ *     xenstore|      |other    |6     :      WAIT 2.0s               :
+ *     conflict|      |         |      :       TIMEOUT                :
+ *             |   WRITE B.E.   |      :          |                   :
+ *             |    STATE:=5    |      :     hopefully qemu has       :
+ *             `---'  |         |      :      gone by now and         :
+ *                    |ok       |      :      freed its resources     :
+ *                    |         |      :          |                   :
+ *              WAIT FOR        |      :     SET B.E.                 :
+ *              STATE==6        |      :      STATE:=6                :
+ *              /     |         |      :..........|...................:
+ *      timeout/    ok|         |                 |
+ *            /       |         |                 |
+ *           |    RUN HOTPLUG <-'<----------------'
+ *           |      SCRIPT
+ *           |        |
+ *           `---> NUKE
+ *                  BACKEND
+ *                    |
+ *                   DONE.
+ */
+
+/* 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
+ * aodev->callback will be called.
+ *
+ * The libxl__ao_device passed to this function should be
+ * prepared using libxl__prepare_ao_device prior to calling
+ * this function.
+ *
+ * Once finished, aodev->callback will be executed.
+ */
+_hidden void libxl__initiate_device_remove(libxl__egc *egc,
+                                           libxl__ao_device *aodev);
+
 /*----- Domain creation -----*/
 
 typedef struct libxl__domain_create_state libxl__domain_create_state;
diff -r 9387f8c77f9a -r 971c3ab60288 tools/libxl/xl_cmdimpl.c
--- a/tools/libxl/xl_cmdimpl.c  Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/libxl/xl_cmdimpl.c  Mon Jul 23 13:09:40 2012 +0100
@@ -5415,7 +5415,7 @@ int main_blockdetach(int argc, char **ar
     if (libxl_device_disk_remove(ctx, domid, &disk, 0)) {
         fprintf(stderr, "libxl_device_disk_remove failed.\n");
     } else
-        libxl_device_disk_destroy(ctx, domid, &disk);
+        libxl_device_disk_destroy(ctx, domid, &disk, 0);
     return 0;
 }
 
diff -r 9387f8c77f9a -r 971c3ab60288 tools/ocaml/libs/xl/xenlight_stubs.c
--- a/tools/ocaml/libs/xl/xenlight_stubs.c      Mon Jul 23 13:09:39 2012 +0100
+++ b/tools/ocaml/libs/xl/xenlight_stubs.c      Mon Jul 23 13:09:40 2012 +0100
@@ -351,7 +351,7 @@ value stub_xl_device_vkb_destroy(value i
        device_vkb_val(&gc, &lg, &c_info, info);
 
        INIT_CTX();
-       ret = libxl_device_vkb_destroy(ctx, Int_val(domid), &c_info);
+       ret = libxl_device_vkb_destroy(ctx, Int_val(domid), &c_info, 0);
        if (ret != 0)
                failwith_xl("vkb_hard_shutdown", &lg);
        FREE_CTX();
@@ -405,7 +405,7 @@ value stub_xl_device_vfb_destroy(value i
        device_vfb_val(&gc, &lg, &c_info, info);
 
        INIT_CTX();
-       ret = libxl_device_vfb_destroy(ctx, Int_val(domid), &c_info);
+       ret = libxl_device_vfb_destroy(ctx, Int_val(domid), &c_info, 0);
        if (ret != 0)
                failwith_xl("vfb_hard_shutdown", &lg);
        FREE_CTX();

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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