All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 01/10] execute hotplug scripts from libxl
@ 2012-05-30 13:07   ` Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device Roger Pau Monne
                       ` (9 more replies)
  0 siblings, 10 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel

This series have been splitted in several patches, to make them easier 
to review. Also the amount of changes introduced is quite important, 
since apart from all the hotplug necessary functions and 
modifications, libxl_domain_destroy has been converted to an async op. 
This was necessary in order to have async operations during device 
removal.

Also, as an important change, disk and nics are added at different 
points for HVM and device model based guests, since we need the disk 
in order to start Qemu, but the nic hotplug scripts should be called 
at a later point, when Qemu has created the corresponding tap device.

Acked:

[PATCH v5 02/10] libxl: move device model creation prototypes
[PATCH v5 03/10] libxl: convert libxl_domain_destroy to an async op
[PATCH v5 06/10] libxl: add option to choose who executes hotplug
[PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy

Pending:

[PATCH v5 01/10] libxl: change libxl__ao_device_remove to
[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
[PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async
[PATCH v5 07/10] libxl: set nic type to VIF by default
[PATCH v5 08/10] libxl: call hotplug scripts for disk devices from
[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from

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

* [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 10:53       ` Ian Jackson
  2012-05-30 13:07     ` [PATCH v5 02/10] libxl: move device model creation prototypes Roger Pau Monne
                       ` (8 subsequent siblings)
  9 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

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.

Changes sinve v4:

 * Added a more detailed comment in _prepare and _initiate header.

 * Removed an unnecessary state check from
   libxl_initiate_device_remove.

Changes since v2:

 * Remove unnecessary comments in libxl__ao_device.

 * Change libxl__device_cb to device_addrm_aocomplete.

 * Rename aorm parameter in device_addrm_aocomplete to aodev.

 * Use a macro to define {nic,disk,vkb,vfb}_{remove,destroy}
   functions.

 * Rename libxl__init_ao_device to libxl__prepare_ao_device and add a
   comment explaining why we need to set active to 1.

 * Replace al uses of aorm with aodev.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |  211 ++++++++++++++----------------------------
 tools/libxl/libxl.h          |   15 ++-
 tools/libxl/libxl_device.c   |  110 +++++++++++++---------
 tools/libxl/libxl_internal.h |   62 +++++++++++--
 4 files changed, 202 insertions(+), 196 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 0e281a6..c4e31e1 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1317,6 +1317,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 device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    if (aodev->rc) {
+        LOGE(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);
+        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;
@@ -1486,42 +1506,6 @@ out:
     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)
@@ -1964,42 +1948,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)
@@ -2326,42 +2274,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)
@@ -2459,41 +2371,56 @@ 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 */
+#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(aodev, ao, NULL);                      \
+        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 --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 9c03f15..6bd028f 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -642,7 +642,8 @@ int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
                              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,
@@ -666,7 +667,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
 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,
@@ -677,14 +680,18 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb);
 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 --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 2006406..d898a89 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -356,11 +356,16 @@ int libxl__device_disk_dev_number(const char *virtpath, int *pdisk,
     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_device *aodev, libxl__ao *ao,
+                              libxl__ao_device **base)
+{
+    aodev->ao = ao;
+    aodev->active = 1;
+    aodev->rc = 0;
+    aodev->base = base;
+}
 
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
@@ -436,34 +441,27 @@ out:
 
 /* Callbacks for device related operations */
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+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)
+void libxl__initiate_device_remove(libxl__egc *egc,
+                                   libxl__ao_device *aodev)
 {
-    AO_GC;
+    STATE_AO_GC(aodev->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, aodev->dev);
     char *state_path = libxl__sprintf(gc, "%s/state", be_path);
-    char *state = libxl__xs_read(gc, XBT_NULL, state_path);
     int rc = 0;
-    libxl__ao_device_remove *aorm = 0;
-
-    if (!state)
-        goto out_ok;
-    if (atoi(state) != 4) {
-        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);
+    if (aodev->force)
+        libxl__xs_path_cleanup(gc, t,
+                               libxl__device_frontend_path(gc, aodev->dev));
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%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)) {
@@ -474,42 +472,68 @@ 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);
+    libxl__ev_devstate_init(&aodev->ds);
 
-    rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_remove_callback,
+    rc = libxl__ev_devstate_wait(gc, &aodev->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_fail;
+    }
 
-    return 0;
+    return;
 
  out_fail:
     assert(rc);
-    device_remove_cleanup(gc, aorm);
-    return rc;
-
- out_ok:
-    libxl__ao_complete(egc, ao, 0);
-    return 0;
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
 }
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+static void device_backend_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);
+    libxl__ao_device *aodev = CONTAINER_OF(ds, *aodev, 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;
+    }
+
+    /* Some devices (vkbd) fail to disconnect properly,
+     * but we shouldn't alarm the user if it's during
+     * domain destruction.
+     */
+    if (rc && aodev->action == DEVICE_CONNECT) {
+        LOG(ERROR, "unable to connect device with path %s",
+                   libxl__device_backend_path(gc, aodev->dev));
+        goto out;
+    } else if (rc) {
+        LOG(DEBUG, "unable to disconnect device with path %s",
+                   libxl__device_backend_path(gc, aodev->dev));
+        goto out;
+    }
+
+out:
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
 }
 
-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_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
+{
+    if (!aodev) return;
+    libxl__ev_devstate_cancel(gc, &aodev->ds);
 }
 
 int libxl__wait_for_device_model(libxl__gc *gc,
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index bbc2149..5baf1f0 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -848,13 +848,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.
@@ -1837,6 +1830,61 @@ _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 -----*/
+
+/* 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_device *aodev, libxl__ao *ao,
+                                      libxl__ao_device **base);
+
+struct libxl__ao_device {
+    /* filled in by user */
+    libxl__ao *ao;
+    /* action being performed */
+    libxl__device_action action;
+    libxl__device *dev;
+    int force;
+    libxl__device_callback *callback;
+    /* private for implementation */
+    int active;
+    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
+ * 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.
+ */
+_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;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 02/10] libxl: move device model creation prototypes
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 03/10] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Move prototypes regarding device model creation, since they will
depend on domain destruction in future patches.

This patch is pure code motion.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl_internal.h |   75 ++++++++++++++++++++---------------------
 1 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5baf1f0..5605440 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1088,44 +1088,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
  * gc: allocation pool
@@ -1885,6 +1847,43 @@ struct libxl__ao_device {
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*----- 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*);
+
 /*----- Domain creation -----*/
 
 typedef struct libxl__domain_create_state libxl__domain_create_state;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 03/10] libxl: convert libxl_domain_destroy to an async op
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 02/10] libxl: move device model creation prototypes Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

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 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@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c               |  167 +++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl.h               |    3 +-
 tools/libxl/libxl_create.c        |   29 ++++++-
 tools/libxl/libxl_device.c        |  160 +++++++++++++++++++++++++++++++----
 tools/libxl/libxl_dm.c            |   83 +++++++++---------
 tools/libxl/libxl_internal.h      |   94 ++++++++++++++++++++-
 tools/libxl/xl_cmdimpl.c          |   12 ++--
 tools/python/xen/lowlevel/xl/xl.c |    2 +-
 8 files changed, 469 insertions(+), 81 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index c4e31e1..4044b9e 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1112,11 +1112,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;
 
@@ -1127,7 +1249,7 @@ 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)) {
@@ -1160,7 +1282,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);
 
@@ -1183,9 +1335,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, libxl_console_type type)
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 6bd028f..d5dc2a0 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -526,7 +526,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info,
 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel);
 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 e5999c0..1df116e 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -586,6 +586,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)
 {
@@ -860,16 +866,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 d898a89..882e647 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)
 {
@@ -367,6 +409,23 @@ void libxl__prepare_ao_device(libxl__ao_device *aodev, libxl__ao *ao,
     aodev->base = base;
 }
 
+int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
+                                libxl__ao_device *list, int num)
+{
+    int i, error = 0;
+
+    device->active = 0;
+    for (i = 0; i < num; i++) {
+        if (list[i].active)
+            return +1;
+
+        if (list[i].rc)
+            error = list[i].rc;
+    }
+
+    return error;
+}
+
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
@@ -381,16 +440,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 device_remove_callback(libxl__egc *egc, libxl__ao_device *aodev);
+
+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_device *aodev;
     libxl__device_kind kind;
 
+    drs->num_devices = libxl__num_devices(gc, drs->domid);
+    if (drs->num_devices < 0) {
+        LOG(ERROR, "unable to get number of devices for domain %u", drs->domid);
+        rc = drs->num_devices;
+        goto out;
+    }
+
+    GCNEW_ARRAY(drs->aodev, drs->num_devices);
+    for (i = 0; i < drs->num_devices; i++) {
+        libxl__prepare_ao_device(&drs->aodev[i], drs->ao, &drs->aodev);
+    }
+
     path = libxl__sprintf(gc, "/local/domain/%d/device", domid);
     kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
     if (!kinds) {
@@ -406,19 +484,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 = &drs->aodev[numdev];
+                dev->domid = domid;
+                dev->kind = kind;
+                dev->devid = atoi(devs[j]);
+                aodev->action = DEVICE_DISCONNECT;
+                aodev->dev = dev;
+                aodev->callback = device_remove_callback;
+                aodev->force = drs->force;
+                libxl__initiate_device_remove(egc, aodev);
+                numdev++;
             }
         }
     }
@@ -426,17 +510,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 +625,39 @@ static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
     libxl__ev_devstate_cancel(gc, &aodev->ds);
 }
 
+static void device_remove_callback(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__devices_remove_state *drs = CONTAINER_OF(aodev->base, *drs, aodev);
+    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 = 0, ret = 0;
+
+    if (aodev->action == DEVICE_DISCONNECT) {
+        do {
+            t = xs_transaction_start(CTX->xsh);
+            libxl__xs_path_cleanup(gc, t, fe_path);
+            libxl__xs_path_cleanup(gc, t, be_path);
+            ret = !xs_transaction_end(CTX->xsh, t, 0);
+        } while (ret && errno == EAGAIN);
+
+        if (ret) {
+            LOGE(ERROR, "unable to finish transaction");
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+out:
+    rc = libxl__ao_device_check_last(gc, aodev, drs->aodev,
+                                     drs->num_devices);
+    if (rc > 0) return;
+
+    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 d987347..99059dc 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);
@@ -893,12 +897,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);
@@ -1091,48 +1114,24 @@ 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)) {
+        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));
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5605440..5c15ca5 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -817,7 +817,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);
 
 /*
@@ -1820,6 +1819,16 @@ typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*);
 _hidden void libxl__prepare_ao_device(libxl__ao_device *aodev, libxl__ao *ao,
                                       libxl__ao_device **base);
 
+/* Check if there are devices that have pending events in the array
+ * pointed to by the "list" parameter. Return values can be:
+ * < 0: All done, but error(s) found.
+ * 0: All done
+ * > 0: Not all done
+ * The passed libxl__ao_device struct in "device" is marked as finished.
+ */
+_hidden int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
+                                        libxl__ao_device *list, int num);
+
 struct libxl__ao_device {
     /* filled in by user */
     libxl__ao *ao;
@@ -1847,6 +1856,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_device *aodev;
+    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. */
@@ -1880,6 +1969,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*);
@@ -1906,6 +1996,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 ca988d6..3220e89 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1389,7 +1389,7 @@ static int handle_domain_death(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:
@@ -1987,7 +1987,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)
@@ -2550,7 +2550,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); }
 }
 
@@ -2824,7 +2824,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);
 }
@@ -3084,7 +3084,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);
 
@@ -3237,7 +3237,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)

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

* [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (2 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 03/10] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 11:38       ` Ian Jackson
                         ` (2 more replies)
  2012-05-30 13:07     ` [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
                       ` (5 subsequent siblings)
  9 siblings, 3 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

This patch converts libxl_device_disk_add to an ao operation that
waits for device backend to reach state XenbusStateInitWait and then
marks the operation as completed. This is not really useful now, but
will be used by latter patches that will launch hotplug scripts after
we reached the desired xenbus state.

As usual, libxl_device_disk_add callers have been modified, and the
internal function libxl__device_disk_add has been used if the call was
inside an already running ao.

Changes since v4:

 * Added more comments about libxl__device_disk_add and
   libxl__add_disks.

 * Removed stray hunk in Makefile.

 * Fixed _prepare call libxl__add_disks (separate into a different
   loop).

 * Moved some code to check if disks have finished to a macro that
   generates a custom function, which will also be used for vif
   interfaces.

Changes since v2:

 * Remove state read from libxl__initiate_device_add

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |   50 ++++++++++++++++++++++++--------
 tools/libxl/libxl.h          |    4 ++-
 tools/libxl/libxl_create.c   |   44 ++++++++++++++++++++++------
 tools/libxl/libxl_device.c   |   65 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_dm.c       |   63 +++++++++++++++++++++++++++++++---------
 tools/libxl/libxl_internal.h |   52 +++++++++++++++++++++++++++++++++
 tools/libxl/xl_cmdimpl.c     |    2 +-
 7 files changed, 242 insertions(+), 38 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 4044b9e..b674557 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1540,13 +1540,31 @@ static int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
     return 0;
 }
 
-int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
+int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid,
+                          libxl_device_disk *disk,
+                          const libxl_asyncop_how *ao_how)
 {
-    GC_INIT(ctx);
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *device;
+
+    GCNEW(device);
+    libxl__prepare_ao_device(device, ao, NULL);
+    device->callback = device_addrm_aocomplete;
+    libxl__device_disk_add(egc, domid, disk, device);
+
+    return AO_INPROGRESS;
+}
+
+void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
+                            libxl_device_disk *disk,
+                            libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl_ctx *ctx = CTX;
     flexarray_t *front;
     flexarray_t *back;
     char *dev;
-    libxl__device device;
+    libxl__device *device;
     int major, minor, rc;
 
     rc = libxl__device_disk_setdefault(gc, disk);
@@ -1570,7 +1588,8 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
         goto out_free;
     }
 
-    rc = libxl__device_from_disk(gc, domid, disk, &device);
+    GCNEW(device);
+    rc = libxl__device_from_disk(gc, domid, disk, device);
     if (rc != 0) {
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported"
                " virtual disk identifier %s", disk->vdev);
@@ -1588,7 +1607,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
             flexarray_append(back, "params");
             flexarray_append(back, dev);
 
-            assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD);
+            assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
             break;
         case LIBXL_DISK_BACKEND_TAP:
             dev = libxl__blktap_devpath(gc, disk->pdev_path, disk->format);
@@ -1609,7 +1628,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
             flexarray_append(back, "params");
             flexarray_append(back, libxl__sprintf(gc, "%s:%s",
                           libxl__device_disk_string_of_format(disk->format), disk->pdev_path));
-            assert(device.backend_kind == LIBXL__DEVICE_KIND_QDISK);
+            assert(device->backend_kind == LIBXL__DEVICE_KIND_QDISK);
             break;
         default:
             LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk backend type: %d\n", disk->backend);
@@ -1641,22 +1660,27 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
     flexarray_append(front, "state");
     flexarray_append(front, libxl__sprintf(gc, "%d", 1));
     flexarray_append(front, "virtual-device");
-    flexarray_append(front, libxl__sprintf(gc, "%d", device.devid));
+    flexarray_append(front, libxl__sprintf(gc, "%d", device->devid));
     flexarray_append(front, "device-type");
     flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk");
 
-    libxl__device_generic_add(gc, &device,
+    libxl__device_generic_add(gc, device,
                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
                              libxl__xs_kvs_of_flexarray(gc, front, front->count));
 
+    aodev->dev = device;
+    aodev->action = DEVICE_CONNECT;
+    libxl__initiate_device_add(egc, aodev);
+
     rc = 0;
 
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    GC_FREE;
-    return rc;
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
 }
 
 static void libxl__device_disk_from_xs_be(libxl__gc *gc,
@@ -1859,11 +1883,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
     ret = 0;
 
     libxl_device_disk_remove(ctx, domid, disks + i, 0);
-    libxl_device_disk_add(ctx, domid, disk);
+    /* fixme-ao */
+    libxl_device_disk_add(ctx, domid, disk, 0);
     stubdomid = libxl_get_stubdom_id(ctx, domid);
     if (stubdomid) {
         libxl_device_disk_remove(ctx, stubdomid, disks + i, 0);
-        libxl_device_disk_add(ctx, stubdomid, disk);
+        /* fixme-ao */
+        libxl_device_disk_add(ctx, stubdomid, disk, 0);
     }
 out:
     for (i = 0; i < num; i++)
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index d5dc2a0..ff0078d 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -638,7 +638,9 @@ void libxl_vminfo_list_free(libxl_vminfo *list, int nr);
  */
 
 /* Disks */
-int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
+int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid,
+                          libxl_device_disk *disk,
+                          const libxl_asyncop_how *ao_how);
 int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
                              libxl_device_disk *disk,
                              const libxl_asyncop_how *ao_how);
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 1df116e..2dc1cee 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -577,6 +577,14 @@ static void domcreate_bootloader_done(libxl__egc *egc,
                                       libxl__bootloader_state *bl,
                                       int rc);
 
+static void domcreate_launch_dm(libxl__egc *egc,
+                                libxl__domain_create_state *dcs,
+                                int rc);
+
+DEFINE_DEVICES_CALLBACK(domcreate_disk_connected,
+                        libxl__domain_create_state,
+                        devices, num_devices, domcreate_launch_dm)
+
 static void domcreate_console_available(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);
 
@@ -677,7 +685,6 @@ static void domcreate_bootloader_done(libxl__egc *egc,
 {
     libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
     STATE_AO_GC(bl->ao);
-    int i;
 
     /* convenience aliases */
     const uint32_t domid = dcs->guest_domid;
@@ -716,15 +723,34 @@ static void domcreate_bootloader_done(libxl__egc *egc,
 
     store_libxl_entry(gc, domid, &d_config->b_info);
 
-    for (i = 0; i < d_config->num_disks; i++) {
-        ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]);
-        if (ret) {
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
-                       "cannot add disk %d to domain: %d", i, ret);
-            ret = ERROR_FAIL;
-            goto error_out;
-        }
+    dcs->num_devices = d_config->num_disks;
+    libxl__add_disks(egc, ao, domid, d_config, &dcs->devices,
+                     domcreate_disk_connected);
+
+    return;
+
+ error_out:
+    assert(ret);
+    domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_launch_dm(libxl__egc *egc,
+                                libxl__domain_create_state *dcs, int rc)
+{
+    STATE_AO_GC(dcs->ao);
+    int i, ret = 0;
+
+    /* convenience aliases */
+    const uint32_t domid = dcs->guest_domid;
+    libxl_domain_config *const d_config = dcs->guest_config;
+    libxl__domain_build_state *const state = &dcs->build_state;
+    libxl_ctx *const ctx = CTX;
+
+    if (rc) {
+        LOG(ERROR, "error connecting disk devices");
+        goto error_out;
     }
+
     for (i = 0; i < d_config->num_vifs; i++) {
         ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
         if (ret) {
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 882e647..0beb4bb 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -426,6 +426,41 @@ int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
     return error;
 }
 
+/******************************************************************************/
+
+/* Macro for defining the functions that will add a bunch of disks when
+ * inside an async op.
+ *
+ * This macro is added to prevent repetition of code.
+ */
+#define DEFINE_DEVICES_ADD(type)                                              \
+    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
+                              libxl_domain_config *d_config,                  \
+                              libxl__ao_device **devices,                     \
+                              libxl__device_callback *callback)               \
+    {                                                                         \
+        AO_GC;                                                                \
+        GCNEW_ARRAY(*devices, d_config->num_##type##s);                       \
+        libxl__ao_device *aodev = *devices;                                   \
+        int i;                                                                \
+                                                                              \
+        for (i = 0; i < d_config->num_##type##s; i++) {                       \
+            libxl__prepare_ao_device(&aodev[i], ao, devices);                 \
+            aodev[i].callback = callback;                                     \
+        }                                                                     \
+                                                                              \
+        for (i = 0; i < d_config->num_##type##s; i++) {                       \
+            libxl__device_##type##_add(egc, domid, &d_config->type##s[i],     \
+                                       &aodev[i]);                            \
+        }                                                                     \
+    }
+
+DEFINE_DEVICES_ADD(disk)
+
+#undef DEFINE_DEVICES_ADD
+
+/******************************************************************************/
+
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
@@ -536,6 +571,36 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
 static void device_backend_cleanup(libxl__gc *gc,
                                    libxl__ao_device *aodev);
 
+void libxl__initiate_device_add(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
+    int rc = 0;
+
+    if (aodev->dev->backend_kind == LIBXL__DEVICE_KIND_QDISK) {
+        aodev->callback(egc, aodev);
+        return;
+    }
+
+    libxl__ev_devstate_init(&aodev->ds);
+    rc = libxl__ev_devstate_wait(gc, &aodev->ds, device_backend_callback,
+                                 state_path, XenbusStateInitWait,
+                                 LIBXL_INIT_TIMEOUT * 1000);
+    if (rc) {
+        LOGE(ERROR, "unable to initialize device %s", be_path);
+        goto out_fail;
+    }
+
+    return;
+
+out_fail:
+    assert(rc);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
+}
+
 void libxl__initiate_device_remove(libxl__egc *egc,
                                    libxl__ao_device *aodev)
 {
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 99059dc..dbd8431 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -673,6 +673,13 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
                                 libxl__dm_spawn_state *stubdom_dmss,
                                 int rc);
 
+static void spawn_stub_launch_dm(libxl__egc *egc,
+                                 libxl__stub_dm_spawn_state *sdss, int rc);
+
+DEFINE_DEVICES_CALLBACK(spawn_stub_disk_connected,
+                        libxl__stub_dm_spawn_state,
+                        devices, num_devices, spawn_stub_launch_dm)
+
 static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
                                            libxl__destroy_domid_state *dis,
                                            int rc);
@@ -681,8 +688,7 @@ void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss)
 {
     STATE_AO_GC(sdss->dm.spawn.ao);
     libxl_ctx *ctx = libxl__gc_owner(gc);
-    int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret;
-    libxl__device_console *console;
+    int ret;
     libxl_device_vfb vfb;
     libxl_device_vkb vkb;
     char **args;
@@ -801,22 +807,52 @@ retry_transaction:
         if (errno == EAGAIN)
             goto retry_transaction;
 
-    for (i = 0; i < dm_config->num_disks; i++) {
-        ret = libxl_device_disk_add(ctx, dm_domid, &dm_config->disks[i]);
-        if (ret)
-            goto out_free;
-    }
+    sdss->num_devices = dm_config->num_disks;
+    libxl__add_disks(egc, ao, dm_domid, dm_config, &sdss->devices,
+                     spawn_stub_disk_connected);
+
+    free(args);
+    return;
+
+out_free:
+    free(args);
+out:
+    assert(ret);
+    spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret);
+}
+
+static void spawn_stub_launch_dm(libxl__egc *egc,
+                                 libxl__stub_dm_spawn_state *sdss, int rc)
+{
+    STATE_AO_GC(sdss->dm.spawn.ao);
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret = 0;
+    libxl__device_console *console;
+
+    /* convenience aliases */
+    libxl_domain_config *const dm_config = &sdss->dm_config;
+    libxl_domain_config *const guest_config = sdss->dm.guest_config;
+    const int guest_domid = sdss->dm.guest_domid;
+    libxl__domain_build_state *const d_state = sdss->dm.build_state;
+    libxl__domain_build_state *const stubdom_state = &sdss->dm_state;
+    uint32_t dm_domid = sdss->pvqemu.guest_domid;
+
+    if (rc) {
+        LOG(ERROR, "error connecting disk devices");
+        goto out;
+     }
+
     for (i = 0; i < dm_config->num_vifs; i++) {
         ret = libxl_device_nic_add(ctx, dm_domid, &dm_config->vifs[i]);
         if (ret)
-            goto out_free;
+            goto out;
     }
     ret = libxl_device_vfb_add(ctx, dm_domid, &dm_config->vfbs[0]);
     if (ret)
-        goto out_free;
+        goto out;
     ret = libxl_device_vkb_add(ctx, dm_domid, &dm_config->vkbs[0]);
     if (ret)
-        goto out_free;
+        goto out;
 
     if (guest_config->b_info.u.hvm.serial)
         num_console++;
@@ -824,7 +860,7 @@ retry_transaction:
     console = libxl__calloc(gc, num_console, sizeof(libxl__device_console));
     if (!console) {
         ret = ERROR_NOMEM;
-        goto out_free;
+        goto out;
     }
 
     for (i = 0; i < num_console; i++) {
@@ -860,7 +896,7 @@ retry_transaction:
         ret = libxl__device_console_add(gc, dm_domid, &console[i],
                         i == STUBDOM_CONSOLE_LOGGING ? stubdom_state : NULL);
         if (ret)
-            goto out_free;
+            goto out;
     }
 
     sdss->pvqemu.spawn.ao = ao;
@@ -871,11 +907,8 @@ retry_transaction:
 
     libxl__spawn_local_dm(egc, &sdss->pvqemu);
 
-    free(args);
     return;
 
-out_free:
-    free(args);
 out:
     assert(ret);
     spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5c15ca5..6df68a6 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -70,6 +70,7 @@
 #include "_libxl_types_internal.h"
 #include "_libxl_types_internal_json.h"
 
+#define LIBXL_INIT_TIMEOUT 10
 #define LIBXL_DESTROY_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
 #define LIBXL_XENCONSOLE_LIMIT 1048576
@@ -1844,6 +1845,21 @@ struct libxl__ao_device {
     void *base;
 };
 
+/* Internal AO operation to connect a disk device, called by
+ * libxl_device_disk_add and libxl__add_disks. This function calls
+ * libxl__initiate_device_add */
+_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
+                                    libxl_device_disk *disk,
+                                    libxl__ao_device *aodev);
+
+/* Arranges that dev will be added 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.
+ */
+_hidden void libxl__initiate_device_add(libxl__egc*, libxl__ao_device *aodev);
+
+
 /* 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
@@ -1936,6 +1952,36 @@ _hidden void libxl__destroy_domid(libxl__egc *egc,
 _hidden void libxl__devices_destroy(libxl__egc *egc,
                                     libxl__devices_remove_state *drs);
 
+/* Helper function to add a bunch of disks. This should be used when
+ * the caller is inside an async op. "devices" will be prepared by this
+ * function, so there's no need to call _prepare before calling this
+ * function.
+ *
+ * The "callback" will be called for each device, and the user is responsible
+ * for calling libxl__ao_device_check_last on the callback.
+ */
+void libxl__add_disks(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                      libxl_domain_config *d_config,
+                      libxl__ao_device **devices,
+                      libxl__device_callback *callback);
+
+/* Macro to define callbacks of libxl__add_*, checks if device is last
+ * and calls the function passed as a parameter to this macro with the
+ * following syntax; func(libxl__egc *, parent_type *, int rc) */
+#define DEFINE_DEVICES_CALLBACK(callback_name, parent_type, array_name,       \
+                                array_size_name, func_to_call)                \
+    static void callback_name(libxl__egc *egc, libxl__ao_device *aodev)       \
+    {                                                                         \
+        STATE_AO_GC(aodev->ao);                                               \
+        parent_type *p = CONTAINER_OF(aodev->base, *p, array_name);           \
+        int rc;                                                               \
+                                                                              \
+        rc = libxl__ao_device_check_last(gc, aodev, p->array_name,            \
+                                         p->array_size_name);                 \
+        if (rc > 0) return;                                                   \
+        func_to_call(egc, p, rc);                                             \
+    }
+
 /*----- device model creation -----*/
 
 /* First layer; wraps libxl__spawn_spawn. */
@@ -1970,6 +2016,9 @@ typedef struct {
     libxl__domain_build_state dm_state;
     libxl__dm_spawn_state pvqemu;
     libxl__destroy_domid_state dis;
+    /* used to store the state of devices being connected */
+    libxl__ao_device *devices;
+    int num_devices;
 } libxl__stub_dm_spawn_state;
 
 _hidden void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state*);
@@ -1998,6 +2047,9 @@ struct libxl__domain_create_state {
          * for the non-stubdom device model. */
     /* necessary if the domain creation failed and we have to destroy it */
     libxl__domain_destroy_state dds;
+    /* used to store the state of devices being connected */
+    libxl__ao_device *devices;
+    int num_devices;
 };
 
 /*
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 3220e89..a7fa0b9 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5343,7 +5343,7 @@ int main_blockattach(int argc, char **argv)
         return 0;
     }
 
-    if (libxl_device_disk_add(ctx, fe_domid, &disk)) {
+    if (libxl_device_disk_add(ctx, fe_domid, &disk, 0)) {
         fprintf(stderr, "libxl_device_disk_add failed.\n");
     }
     return 0;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (3 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 14:26       ` Ian Jackson
  2012-05-30 13:07     ` [PATCH v5 06/10] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
                       ` (4 subsequent siblings)
  9 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

This patch converts libxl_device_nic_add to an ao operation that
waits for device backend to reach state XenbusStateInitWait and then
marks the operation as completed. This is not really useful now, but
will be used by latter patches that will launch hotplug scripts after
we reached the desired xenbus state.

Calls to libxl_device_nic_add have also been moved to occur after the
device model has been launched, so when hotplug scripts are called
from this functions the interfaces already exists.

As usual, libxl_device_nic_add callers have been modified, and the
internal function libxl__device_disk_add has been used if the call was
inside an already running ao.

Changes since v4:

 * Used the macro defined in previous patch to define the generic
   callback to wait for nics to be connected.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |   39 ++++++++++++++++++++++++------
 tools/libxl/libxl.h          |    3 +-
 tools/libxl/libxl_create.c   |   53 +++++++++++++++++++++++++++++++++++------
 tools/libxl/libxl_device.c   |    9 ++++---
 tools/libxl/libxl_dm.c       |   40 +++++++++++++++++++++++++++++--
 tools/libxl/libxl_internal.h |   18 ++++++++++++++
 tools/libxl/xl_cmdimpl.c     |    2 +-
 7 files changed, 139 insertions(+), 25 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index b674557..88869f6 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2026,12 +2026,27 @@ static int libxl__device_from_nic(libxl__gc *gc, uint32_t domid,
     return 0;
 }
 
-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how)
 {
-    GC_INIT(ctx);
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *device;
+
+    GCNEW(device);
+    libxl__prepare_ao_device(device, ao, NULL);
+    device->callback = device_addrm_aocomplete;
+    libxl__device_nic_add(egc, domid, nic, device);
+
+    return AO_INPROGRESS;
+}
+
+void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                           libxl_device_nic *nic, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
     flexarray_t *front;
     flexarray_t *back;
-    libxl__device device;
+    libxl__device *device;
     char *dompath, **l;
     unsigned int nb, rc;
 
@@ -2062,7 +2077,8 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
         }
     }
 
-    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_free;
 
     flexarray_append(back, "frontend-id");
@@ -2103,6 +2119,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
     flexarray_append(back, libxl__strdup(gc, nic->bridge));
     flexarray_append(back, "handle");
     flexarray_append(back, libxl__sprintf(gc, "%d", nic->devid));
+    flexarray_append(back, "type");
+    flexarray_append(back, libxl__strdup(gc,
+                                     libxl_nic_type_to_string(nic->nictype)));
 
     flexarray_append(front, "backend-id");
     flexarray_append(front, libxl__sprintf(gc, "%d", nic->backend_domid));
@@ -2113,18 +2132,22 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
     flexarray_append(front, "mac");
     flexarray_append(front, libxl__sprintf(gc,
                                     LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
-    libxl__device_generic_add(gc, &device,
+    libxl__device_generic_add(gc, device,
                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
                              libxl__xs_kvs_of_flexarray(gc, front, front->count));
 
-    /* FIXME: wait for plug */
+    aodev->dev = device;
+    aodev->action = DEVICE_CONNECT;
+    libxl__initiate_device_add(egc, aodev);
+
     rc = 0;
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    GC_FREE;
-    return rc;
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
 }
 
 static void libxl__device_nic_from_xs_be(libxl__gc *gc,
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index ff0078d..51f2e60 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -666,7 +666,8 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk);
 int libxl_device_disk_local_detach(libxl_ctx *ctx, libxl_device_disk *disk);
 
 /* Network Interfaces */
-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how);
 int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_nic *nic,
                             const libxl_asyncop_how *ao_how);
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 2dc1cee..1dc8247 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -585,6 +585,13 @@ DEFINE_DEVICES_CALLBACK(domcreate_disk_connected,
                         libxl__domain_create_state,
                         devices, num_devices, domcreate_launch_dm)
 
+static void domcreate_attach_pci(libxl__egc *egc,
+                                 libxl__domain_create_state *dcs, int rc);
+
+DEFINE_DEVICES_CALLBACK(domcreate_nic_connected,
+                        libxl__domain_create_state,
+                        devices, num_devices, domcreate_attach_pci)
+
 static void domcreate_console_available(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);
 
@@ -752,13 +759,11 @@ static void domcreate_launch_dm(libxl__egc *egc,
     }
 
     for (i = 0; i < d_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
-        if (ret) {
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
-                       "cannot add nic %d to domain: %d", i, ret);
-            ret = ERROR_FAIL;
-            goto error_out;
-        }
+        /* We have to init the nic here, because we still haven't
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &d_config->vifs[i]);
     }
     switch (d_config->c_info.type) {
     case LIBXL_DOMAIN_TYPE_HVM:
@@ -831,7 +836,6 @@ static void domcreate_devmodel_started(libxl__egc *egc,
 {
     libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm);
     STATE_AO_GC(dmss->spawn.ao);
-    int i;
     libxl_ctx *ctx = CTX;
     int domid = dcs->guest_domid;
 
@@ -851,6 +855,39 @@ static void domcreate_devmodel_started(libxl__egc *egc,
         }
     }
 
+    /* Plug nic interfaces */
+    if (!ret && d_config->num_vifs > 0) {
+        /* Attach nics */
+        dcs->num_devices = d_config->num_vifs;
+        libxl__add_nics(egc, ao, domid, d_config, &dcs->devices,
+                        domcreate_nic_connected);
+        return;
+    }
+
+    domcreate_attach_pci(egc, dcs, 0);
+    return;
+
+error_out:
+    assert(ret);
+    domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_attach_pci(libxl__egc *egc,
+                                 libxl__domain_create_state *dcs, int rc)
+{
+    STATE_AO_GC(dcs->ao);
+    int i, ret = 0;
+    libxl_ctx *ctx = CTX;
+    int domid = dcs->guest_domid;
+
+    /* convenience aliases */
+    libxl_domain_config *const d_config = dcs->guest_config;
+
+    if (rc) {
+        LOG(ERROR, "error connecting nic devices");
+        goto error_out;
+    }
+
     for (i = 0; i < d_config->num_pcidevs; i++)
         libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);
 
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 0beb4bb..de7904a 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -433,8 +433,8 @@ int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
  *
  * This macro is added to prevent repetition of code.
  */
-#define DEFINE_DEVICES_ADD(type)                                              \
-    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
+#define DEFINE_DEVICES_ADD(type, name)                                        \
+    void libxl__add_##name##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
                               libxl_domain_config *d_config,                  \
                               libxl__ao_device **devices,                     \
                               libxl__device_callback *callback)               \
@@ -450,12 +450,13 @@ int libxl__ao_device_check_last(libxl__gc *gc, libxl__ao_device *device,
         }                                                                     \
                                                                               \
         for (i = 0; i < d_config->num_##type##s; i++) {                       \
-            libxl__device_##type##_add(egc, domid, &d_config->type##s[i],     \
+            libxl__device_##name##_add(egc, domid, &d_config->type##s[i],     \
                                        &aodev[i]);                            \
         }                                                                     \
     }
 
-DEFINE_DEVICES_ADD(disk)
+DEFINE_DEVICES_ADD(disk, disk)
+DEFINE_DEVICES_ADD(vif, nic)
 
 #undef DEFINE_DEVICES_ADD
 
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index dbd8431..9522a9b 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -680,6 +680,14 @@ DEFINE_DEVICES_CALLBACK(spawn_stub_disk_connected,
                         libxl__stub_dm_spawn_state,
                         devices, num_devices, spawn_stub_launch_dm)
 
+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__stub_dm_spawn_state *sdss,
+                              int rc);
+
+DEFINE_DEVICES_CALLBACK(stubdom_nics_connected,
+                        libxl__stub_dm_spawn_state,
+                        devices, num_devices, stubdom_pvqemu_cb)
+
 static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
                                            libxl__destroy_domid_state *dis,
                                            int rc);
@@ -843,9 +851,11 @@ static void spawn_stub_launch_dm(libxl__egc *egc,
      }
 
     for (i = 0; i < dm_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, dm_domid, &dm_config->vifs[i]);
-        if (ret)
-            goto out;
+         /* We have to init the nic here, because we still haven't
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &dm_config->vifs[i]);
     }
     ret = libxl_device_vfb_add(ctx, dm_domid, &dm_config->vfbs[0]);
     if (ret)
@@ -922,9 +932,33 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
         CONTAINER_OF(stubdom_dmss, *sdss, pvqemu);
     STATE_AO_GC(sdss->dm.spawn.ao);
     uint32_t dm_domid = sdss->pvqemu.guest_domid;
+    libxl_domain_config *d_config = stubdom_dmss->guest_config;
 
     if (rc) goto out;
 
+    if (!rc && d_config->num_vifs > 0) {
+        sdss->num_devices = d_config->num_vifs;
+        libxl__add_nics(egc, ao, dm_domid, d_config, &sdss->devices,
+                        stubdom_nics_connected);
+        return;
+    }
+
+out:
+    stubdom_pvqemu_cb(egc, sdss, rc);
+}
+
+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__stub_dm_spawn_state *sdss,
+                              int rc)
+{
+    STATE_AO_GC(sdss->dm.spawn.ao);
+    uint32_t dm_domid = sdss->pvqemu.guest_domid;
+
+    if (rc) {
+        LOGE(ERROR, "error connecting nics devices");
+        goto out;
+    }
+
     rc = libxl_domain_unpause(CTX, dm_domid);
     if (rc) goto out;
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 6df68a6..49085b4 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1852,6 +1852,11 @@ _hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
                                     libxl_device_disk *disk,
                                     libxl__ao_device *aodev);
 
+/* Internal AO operation to connect a nic device */
+_hidden void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                                   libxl_device_nic *nic,
+                                   libxl__ao_device *aodev);
+
 /* Arranges that dev will be added to the guest, and the
  * hotplug scripts will be executed (if necessary). When
  * this is done (or an error happens), the callback in
@@ -1965,6 +1970,19 @@ void libxl__add_disks(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
                       libxl__ao_device **devices,
                       libxl__device_callback *callback);
 
+/* Helper function to add a bunch of nics. This should be used when
+ * the caller is inside an async op. "devices" will be prepared by this
+ * function, so there's no need to call _prepare before calling this
+ * function.
+ *
+ * The "callback" will be called for each device, and the user is responsible
+ * for calling libxl__ao_device_check_last on the callback.
+ */
+void libxl__add_nics(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                     libxl_domain_config *d_config,
+                     libxl__ao_device **devices,
+                     libxl__device_callback callback);
+
 /* Macro to define callbacks of libxl__add_*, checks if device is last
  * and calls the function passed as a parameter to this macro with the
  * following syntax; func(libxl__egc *, parent_type *, int rc) */
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index a7fa0b9..1f9b857 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5232,7 +5232,7 @@ int main_networkattach(int argc, char **argv)
         return 0;
     }
 
-    if (libxl_device_nic_add(ctx, domid, &nic)) {
+    if (libxl_device_nic_add(ctx, domid, &nic, 0)) {
         fprintf(stderr, "libxl_device_nic_add failed.\n");
         return 1;
     }
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 06/10] libxl: add option to choose who executes hotplug scripts
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (4 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 07/10] libxl: set nic type to VIF by default Roger Pau Monne
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Add and option to xl.conf file to decide if hotplug scripts are
executed from the toolstack (xl) or from udev as it used to be in the
past.

This option is only introduced in this patch, but it has no effect
since the code to call hotplug scripts from libxl is introduced in a
latter patch.

This choice will be saved in "libxl/disable_udev", as specified in the
DISABLE_UDEV_PATH constant.

Changes since v2:

 * Change atoi(...) to !!atoi(...) to prevent returning negative
   values from xenstore (which will be handled as errors).

 * Check for errors on the return value of libxl__hotplug_settings.

Changes since v1:

 * Used an auxiliary function to check for the current setting.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 docs/man/xl.conf.pod.5       |    8 ++++++++
 tools/examples/xl.conf       |    5 +++++
 tools/libxl/libxl_create.c   |   36 +++++++++++++++++++++++++++++++++++-
 tools/libxl/libxl_internal.c |   19 +++++++++++++++++++
 tools/libxl/libxl_internal.h |    3 +++
 tools/libxl/libxl_types.idl  |    1 +
 tools/libxl/xl.c             |    4 ++++
 tools/libxl/xl.h             |    1 +
 tools/libxl/xl_cmdimpl.c     |    1 +
 9 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/docs/man/xl.conf.pod.5 b/docs/man/xl.conf.pod.5
index 8bd45ea..72825a0 100644
--- a/docs/man/xl.conf.pod.5
+++ b/docs/man/xl.conf.pod.5
@@ -55,6 +55,14 @@ default.
 
 Default: C<1>
 
+=item B<run_hotplug_scripts=BOOLEAN>
+
+If disabled hotplug scripts will be called from udev, as it used to
+be in the previous releases. With the default option, hotplug scripts
+will be launched by xl directly.
+
+Default: C<1>
+
 =item B<lockfile="PATH">
 
 Sets the path to the lock file used by xl to serialise certain
diff --git a/tools/examples/xl.conf b/tools/examples/xl.conf
index 56d3b3b..75b00e0 100644
--- a/tools/examples/xl.conf
+++ b/tools/examples/xl.conf
@@ -12,3 +12,8 @@
 
 # default output format used by "xl list -l"
 #output_format="json"
+
+# default option to run hotplug scripts from xl
+# if disabled the old behaviour will be used, and hotplug scripts will be
+# launched by udev.
+#run_hotplug_scripts=1
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 1dc8247..317654f 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -400,7 +400,7 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info,
                        uint32_t *domid)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
-    int flags, ret, rc;
+    int flags, ret, rc, nb_vm;
     char *uuid_string;
     char *dom_path, *vm_path, *libxl_path;
     struct xs_permissions roperm[2];
@@ -521,6 +521,40 @@ retry_transaction:
             libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path),
                         rwperm, ARRAY_SIZE(rwperm));
 
+    if (libxl_list_vm(ctx, &nb_vm) < 0) {
+        LOG(ERROR, "cannot get number of running guests");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    int hotplug_setting = libxl__hotplug_settings(gc, t);
+    if (hotplug_setting < 0) {
+        LOG(ERROR, "unable to get current hotplug scripts execution setting");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (libxl_defbool_val(info->run_hotplug_scripts) != hotplug_setting &&
+        (nb_vm - 1)) {
+        LOG(ERROR, "cannot change hotplug execution option once set, "
+                    "please shutdown all guests before changing it");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl_defbool_val(info->run_hotplug_scripts)) {
+        rc = libxl__xs_write(gc, t, DISABLE_UDEV_PATH, "1");
+        if (rc) {
+            LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH);
+            goto out;
+        }
+    } else {
+        rc = xs_rm(ctx->xsh, t, DISABLE_UDEV_PATH);
+        if (rc) {
+            LOGE(ERROR, "unable to delete %s", DISABLE_UDEV_PATH);
+            goto out;
+        }
+    }
+
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name));
 
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index 8139520..bc56f21 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -346,6 +346,25 @@ libxl_device_model_version libxl__device_model_version_running(libxl__gc *gc,
     return value;
 }
 
+int libxl__hotplug_settings(libxl__gc *gc, xs_transaction_t t)
+{
+    int rc = 0;
+    char *val;
+
+    val = libxl__xs_read(gc, t, DISABLE_UDEV_PATH);
+    if (!val && errno != ENOENT) {
+        LOGE(ERROR, "cannot read %s from xenstore", DISABLE_UDEV_PATH);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (!val) val = "0";
+
+    rc = !!atoi(val);
+
+out:
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 49085b4..5a2a87a 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -86,6 +86,7 @@
 #define STUBDOM_CONSOLE_SERIAL 3
 #define STUBDOM_SPECIAL_CONSOLES 3
 #define TAP_DEVICE_SUFFIX "-emu"
+#define DISABLE_UDEV_PATH "libxl/disable_udev"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
@@ -1408,6 +1409,8 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
 _hidden libxl_device_model_version
 libxl__device_model_version_running(libxl__gc *gc, uint32_t domid);
 
+/* Check how executes hotplug script currently */
+int libxl__hotplug_settings(libxl__gc *gc, xs_transaction_t t);
 
 /*
  * Calling context and GC for event-generating functions:
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 5b81ee9..3c8636c 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -218,6 +218,7 @@ libxl_domain_create_info = Struct("domain_create_info",[
     ("xsdata",       libxl_key_value_list),
     ("platformdata", libxl_key_value_list),
     ("poolid",       uint32),
+    ("run_hotplug_scripts",libxl_defbool),
     ], dir=DIR_IN)
 
 MemKB = UInt(64, init_val = "LIBXL_MEMKB_DEFAULT")
diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c
index 69f8737..02a84eb 100644
--- a/tools/libxl/xl.c
+++ b/tools/libxl/xl.c
@@ -38,6 +38,7 @@ xentoollog_logger_stdiostream *logger;
 int dryrun_only;
 int force_execution;
 int autoballoon = 1;
+libxl_defbool run_hotplug_scripts;
 char *lockfile;
 char *default_vifscript = NULL;
 char *default_bridge = NULL;
@@ -69,6 +70,9 @@ static void parse_global_config(const char *configfile,
     if (!xlu_cfg_get_long (config, "autoballoon", &l, 0))
         autoballoon = l;
 
+    libxl_defbool_setdefault(&run_hotplug_scripts, true);
+    xlu_cfg_get_defbool(config, "run_hotplug_scripts", &run_hotplug_scripts, 0);
+
     if (!xlu_cfg_get_string (config, "lockfile", &buf, 0))
         lockfile = strdup(buf);
     else {
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 2af9428..59f931f 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -139,6 +139,7 @@ int xl_child_pid(xlchildnum); /* returns 0 if child struct is not in use */
 
 /* global options */
 extern int autoballoon;
+extern libxl_defbool run_hotplug_scripts;
 extern int dryrun_only;
 extern char *lockfile;
 extern char *default_vifscript;
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 1f9b857..b8e5773 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -594,6 +594,7 @@ static void parse_config_data(const char *config_source,
         }
     }
 
+    c_info->run_hotplug_scripts = run_hotplug_scripts;
     c_info->type = LIBXL_DOMAIN_TYPE_PV;
     if (!xlu_cfg_get_string (config, "builder", &buf, 0) &&
         !strncmp(buf, "hvm", strlen(buf)))
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 07/10] libxl: set nic type to VIF by default
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (5 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 06/10] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Set the default value for nic interfaces to VIF, since it used to be
IOEMU, even for PV guests.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 88869f6..ef99fa6 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2008,7 +2008,7 @@ int libxl__device_nic_setdefault(libxl__gc *gc, libxl_device_nic *nic)
                                   libxl__xen_script_dir_path()) < 0 )
         return ERROR_FAIL;
     if (!nic->nictype)
-        nic->nictype = LIBXL_NIC_TYPE_IOEMU;
+        nic->nictype = LIBXL_NIC_TYPE_VIF;
     return 0;
 }
 
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (6 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 07/10] libxl: set nic type to VIF by default Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 14:40       ` Ian Jackson
  2012-05-30 13:07     ` [PATCH v5 09/10] libxl: call hotplug scripts for nic " Roger Pau Monne
  2012-05-30 13:07     ` [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
  9 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since most of the needed work is already done in previous patches,
this patch only contains the necessary code to call hotplug scripts
for disk devices, that should be called when the device is added or
removed from a guest.

We will chain the launch of the disk hotplug scripts after the
device_backend_callback callback, or directly from
libxl__initiate_device_{add,remove} if the device is already in the
desired state.

Changes since v4:

 * Init args and env to NULL.

 * Correctly propagate errors from libxl__get_hotplug_script_info.

 * Replaced if in libxl__ev_child_inuse with asserts.

 * Renamed fork_cb to child_death_cb.

 * Move deregistration of device_hotplug_timeout_cb to the top of the
   function.

 * Removed "pid" field from libxl__ao_device struct.

 * Moved arraysize declaration.

 * Fixed diff complain about no newline at the end of libxl_netbsd.c.

Changes since v2:

 * Added array size check with assert.

 * Added NetBSD code (so compilation is not broken).

 * Removed a check for null in device_hotplug_timeout_cb.

Changes since v1:

 * Moved all the event related code that was inside libxl_linux.c into
   libxl_device.c, so the flow of the device addition/removal event is
   all in the same file.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/hotplug/Linux/xen-backend.rules     |    6 +-
 tools/hotplug/Linux/xen-hotplug-common.sh |    6 ++
 tools/libxl/libxl.c                       |   10 +++
 tools/libxl/libxl_device.c                |  115 +++++++++++++++++++++++++++++
 tools/libxl/libxl_internal.h              |   19 +++++
 tools/libxl/libxl_linux.c                 |  100 +++++++++++++++++++++++++
 tools/libxl/libxl_netbsd.c                |    9 ++
 7 files changed, 262 insertions(+), 3 deletions(-)

diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules
index 405387f..d55ff11 100644
--- a/tools/hotplug/Linux/xen-backend.rules
+++ b/tools/hotplug/Linux/xen-backend.rules
@@ -1,11 +1,11 @@
-SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="tap*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="vbd*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
-SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
+SUBSYSTEM=="xen-backend", ACTION=="remove", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
 SUBSYSTEM=="xen", KERNEL=="blktap[0-9]*", NAME="xen/%k", MODE="0600"
 SUBSYSTEM=="blktap2", KERNEL=="blktap[0-9]*", NAME="xen/blktap-2/%k", MODE="0600"
diff --git a/tools/hotplug/Linux/xen-hotplug-common.sh b/tools/hotplug/Linux/xen-hotplug-common.sh
index 8f6557d..4a7bc73 100644
--- a/tools/hotplug/Linux/xen-hotplug-common.sh
+++ b/tools/hotplug/Linux/xen-hotplug-common.sh
@@ -15,6 +15,12 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
+# Hack to prevent the execution of hotplug scripts from udev if the domain
+# has been launched from libxl
+if [ -n "${UDEV_CALL}" ] && \
+   xenstore-read "libxl/disable_udev" >/dev/null 2>&1; then
+    exit 0
+fi
 
 dir=$(dirname "$0")
 . "$dir/hotplugpath.sh"
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index ef99fa6..f7a137f 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1607,6 +1607,11 @@ void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
             flexarray_append(back, "params");
             flexarray_append(back, dev);
 
+            flexarray_append(back, "script");
+            flexarray_append(back, GCSPRINTF("%s/%s",
+                                             libxl__xen_script_dir_path(),
+                                             "block"));
+
             assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
             break;
         case LIBXL_DISK_BACKEND_TAP:
@@ -1622,6 +1627,11 @@ void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
                 libxl__device_disk_string_of_format(disk->format),
                 disk->pdev_path));
 
+            flexarray_append(back, "script");
+            flexarray_append(back, GCSPRINTF("%s/%s",
+                                             libxl__xen_script_dir_path(),
+                                             "blktap"));
+
             /* now create a phy device to export the device to the guest */
             goto do_backend_phy;
         case LIBXL_DISK_BACKEND_QDISK:
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index de7904a..7db379a 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -572,6 +572,15 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
 static void device_backend_cleanup(libxl__gc *gc,
                                    libxl__ao_device *aodev);
 
+static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev);
+
+static void device_hotplug_child_death_cb(libxl__egc *egc,
+                                          libxl__ev_child *child,
+                                          pid_t pid, int status);
+
+static void device_hotplug_timeout_cb(libxl__egc *egc, libxl__ev_time *ev,
+                                      const struct timeval *requested_abs);
+
 void libxl__initiate_device_add(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
@@ -679,6 +688,9 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
         goto out;
     }
 
+    device_hotplug(egc, aodev);
+    return;
+
 out:
     aodev->rc = rc;
     aodev->callback(egc, aodev);
@@ -691,6 +703,109 @@ static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
     libxl__ev_devstate_cancel(gc, &aodev->ds);
 }
 
+static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char **args = NULL, **env = NULL;
+    int rc = 0;
+    int hotplug;
+    pid_t pid;
+
+    /* Check if we have to execute hotplug scripts for this device
+     * and return the necessary args/env vars for execution */
+    hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args, &env,
+                                             aodev->action);
+    switch (hotplug) {
+    case 0:
+        /* no hotplug script to execute */
+        goto out;
+    case 1:
+        /* execute hotplug script */
+        break;
+    default:
+        /* everything else is an error */
+        LOG(ERROR, "unable to get args/env to execute hotplug script for "
+                   "device %s", libxl__device_backend_path(gc, aodev->dev));
+        rc = hotplug;
+        goto out;
+    }
+
+    /* Set hotplug timeout */
+    libxl__ev_time_init(&aodev->ev);
+    rc = libxl__ev_time_register_rel(gc, &aodev->ev, device_hotplug_timeout_cb,
+                                     LIBXL_HOTPLUG_TIMEOUT * 1000);
+    if (rc) {
+        LOG(ERROR, "unable to register timeout for hotplug device %s", be_path);
+        goto out;
+    }
+
+    aodev->what = GCSPRINTF("%s %s", args[0], args[1]);
+    LOG(DEBUG, "calling hotplug script: %s %s", args[0], args[1]);
+    libxl__ev_child_init(&aodev->child);
+
+    /* fork and execute hotplug script */
+    pid = libxl__ev_child_fork(gc, &aodev->child, device_hotplug_child_death_cb);
+    if (pid == -1) {
+        LOG(ERROR, "unable to fork");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (!pid) {
+        /* child */
+        libxl__exec(gc, -1, -1, -1, args[0], args, env);
+        /* notreached */
+        abort();
+    }
+
+    assert(libxl__ev_child_inuse(&aodev->child));
+
+    return;
+
+out:
+    libxl__ev_time_deregister(gc, &aodev->ev);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
+}
+
+static void device_hotplug_child_death_cb(libxl__egc *egc,
+                                          libxl__ev_child *child,
+                                          pid_t pid, int status)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(child, *aodev, child);
+    STATE_AO_GC(aodev->ao);
+
+    libxl__ev_time_deregister(gc, &aodev->ev);
+
+    if (status) {
+        libxl_report_child_exitstatus(CTX, aodev->rc ? LIBXL__LOG_ERROR
+                                                     : LIBXL__LOG_WARNING,
+                                      aodev->what, pid, status);
+        aodev->rc = ERROR_FAIL;
+    }
+    aodev->callback(egc, aodev);
+}
+
+static void device_hotplug_timeout_cb(libxl__egc *egc, libxl__ev_time *ev,
+                                      const struct timeval *requested_abs)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(ev, *aodev, ev);
+    STATE_AO_GC(aodev->ao);
+
+    libxl__ev_time_deregister(gc, &aodev->ev);
+
+    assert(libxl__ev_child_inuse(&aodev->child));
+    LOG(DEBUG, "killing hotplug script %s because of timeout", aodev->what);
+    if (kill(aodev->child.pid, SIGKILL)) {
+        LOGEV(ERROR, errno, "unable to kill hotplug script %s [%ld]",
+                            aodev->what, (unsigned long)aodev->child.pid);
+    }
+
+    return;
+}
+
 static void device_remove_callback(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5a2a87a..9dd2404 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -72,6 +72,7 @@
 
 #define LIBXL_INIT_TIMEOUT 10
 #define LIBXL_DESTROY_TIMEOUT 10
+#define LIBXL_HOTPLUG_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
 #define LIBXL_XENCONSOLE_LIMIT 1048576
 #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
@@ -1846,6 +1847,10 @@ struct libxl__ao_device {
     int rc;
     libxl__ev_devstate ds;
     void *base;
+    /* device hotplug execution */
+    char *what;
+    libxl__ev_time ev;
+    libxl__ev_child child;
 };
 
 /* Internal AO operation to connect a disk device, called by
@@ -1880,6 +1885,20 @@ _hidden void libxl__initiate_device_add(libxl__egc*, libxl__ao_device *aodev);
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*
+ * libxl__get_hotplug_script_info returns the args and env that should
+ * be passed to the hotplug script for the requested device.
+ *
+ * Since a device might not need to execute any hotplug script, this function
+ * can return the following values:
+ * < 0: Error
+ * 0: No need to execute hotplug script
+ * 1: Execute hotplug script
+ */
+_hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                           char ***args, char ***env,
+                                           libxl__device_action action);
+
 /*----- Domain destruction -----*/
 
 /* Domain destruction has been split into two functions:
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 925248b..60a966f 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -25,3 +25,103 @@ int libxl__try_phy_backend(mode_t st_mode)
 
     return 1;
 }
+
+/* Hotplug scripts helpers */
+
+static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    const char *type = libxl__device_kind_to_string(dev->backend_kind);
+    char **env;
+    int nr = 0;
+
+    script = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF("%s/%s", be_path, "script"));
+    if (!script) {
+        LOGEV(ERROR, errno, "unable to read script from %s", be_path);
+        return NULL;
+    }
+
+    const int arraysize = 9;
+    GCNEW_ARRAY(env, arraysize);
+    env[nr++] = "script";
+    env[nr++] = script;
+    env[nr++] = "XENBUS_TYPE";
+    env[nr++] = libxl__strdup(gc, type);
+    env[nr++] = "XENBUS_PATH";
+    env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
+    env[nr++] = "XENBUS_BASE_PATH";
+    env[nr++] = "backend";
+    env[nr++] = NULL;
+    assert(nr == arraysize);
+
+    return env;
+}
+
+/* Hotplug scripts caller functions */
+
+static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
+                               char ***args, char ***env,
+                               libxl__device_action action)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    int nr = 0, rc = 0;
+
+    script = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF("%s/%s", be_path, "script"));
+    if (!script) {
+        LOGEV(ERROR, errno, "unable to read script from %s", be_path);
+        rc = ERROR_FAIL;
+        goto error;
+    }
+
+    *env = get_hotplug_env(gc, dev);
+    if (!*env) {
+        rc = ERROR_FAIL;
+        goto error;
+    }
+
+    const int arraysize = 3;
+    GCNEW_ARRAY(*args, arraysize);
+    (*args)[nr++] = script;
+    (*args)[nr++] = action == DEVICE_CONNECT ? "add" : "remove";
+    (*args)[nr++] = NULL;
+    assert(nr == arraysize);
+
+    rc = 0;
+
+error:
+    return rc;
+}
+
+int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                   char ***args, char ***env,
+                                   libxl__device_action action)
+{
+    char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
+    int rc;
+
+    /* Check if we have to run hotplug scripts */
+    if (!disable_udev) {
+        rc = 0;
+        goto out;
+    }
+
+    switch (dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+        rc = libxl__hotplug_disk(gc, dev, args, env, action);
+        if (!rc) rc = 1;
+        break;
+    default:
+        /* If no need to execute any hotplug scripts,
+         * call the callback manually
+         */
+        rc = 0;
+        break;
+    }
+
+out:
+    return rc;
+}
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index 9e0ed6d..d41a046 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -24,3 +24,12 @@ int libxl__try_phy_backend(mode_t st_mode)
 
     return 0;
 }
+
+/* Hotplug scripts caller functions */
+
+int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                   char ***args, char ***env,
+                                   libxl__device_action action)
+{
+    return 0;
+}
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (7 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 14:48       ` Ian Jackson
  2012-05-30 13:07     ` [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
  9 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since most of the needed work is already done in previous patches,
this patch only contains the necessary code to call hotplug scripts
for nic devices, that should be called when the device is added or
removed from a guest.

Added another parameter to libxl__get_hotplug_script_info, that is
used to know the number of times hotplug scripts have been called for
that device. This is currently used by IOEMU nics on Linux.

Changes since v4:

 * Add num_exec to NetBSD dummy function.

 * Better comment in the prototype of libxl__get_hotplug_script_info.

 * Remove nasty use of goto.

Changes since v2:

 * Change libxl__nic_type to return the value in a parameter passed by
   the caller.

 * Rename vif_execute to num_exec, to represent the number of times
   hotplug scripts have been called for that device.

Changes since v1:

 * Move event code to libxl_device.c (as in previous patch).

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/hotplug/Linux/xen-backend.rules |    6 +-
 tools/libxl/libxl_device.c            |   46 +++++++++++++++++-
 tools/libxl/libxl_internal.h          |   14 +++++-
 tools/libxl/libxl_linux.c             |   84 +++++++++++++++++++++++++++++++-
 tools/libxl/libxl_netbsd.c            |    3 +-
 5 files changed, 144 insertions(+), 9 deletions(-)

diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules
index d55ff11..c591a3f 100644
--- a/tools/hotplug/Linux/xen-backend.rules
+++ b/tools/hotplug/Linux/xen-backend.rules
@@ -2,8 +2,8 @@ SUBSYSTEM=="xen-backend", KERNEL=="tap*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scr
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ENV{UDEV_CALL}="1", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ENV{UDEV_CALL}="1", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
 SUBSYSTEM=="xen-backend", ACTION=="remove", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
@@ -13,4 +13,4 @@ KERNEL=="blktap-control", NAME="xen/blktap-2/control", MODE="0600"
 KERNEL=="gntdev", NAME="xen/%k", MODE="0600"
 KERNEL=="pci_iomul", NAME="xen/%k", MODE="0600"
 KERNEL=="tapdev[a-z]*", NAME="xen/blktap-2/tapdev%m", MODE="0600"
-SUBSYSTEM=="net", KERNEL=="vif*-emu", ACTION=="add", RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap"
+SUBSYSTEM=="net", KERNEL=="vif*-emu", ACTION=="add", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap"
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 7db379a..841f9ac 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -100,6 +100,29 @@ out:
     return numdevs;
 }
 
+int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
+{
+    char *snictype, *be_path;
+    int rc = 0;
+
+    be_path = libxl__device_backend_path(gc, dev);
+    snictype = libxl__xs_read(gc, XBT_NULL,
+                              GCSPRINTF("%s/%s", be_path, "type"));
+    if (!snictype) {
+        LOGE(ERROR, "unable to read nictype from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = libxl_nic_type_from_string(snictype, nictype);
+    if (rc) {
+        LOGE(ERROR, "unable to parse nictype from %s", be_path);
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
 int libxl__device_generic_add(libxl__gc *gc, libxl__device *device,
                              char **bents, char **fents)
 {
@@ -715,7 +738,8 @@ static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
     /* Check if we have to execute hotplug scripts for this device
      * and return the necessary args/env vars for execution */
     hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args, &env,
-                                             aodev->action);
+                                             aodev->action,
+                                             aodev->num_exec);
     switch (hotplug) {
     case 0:
         /* no hotplug script to execute */
@@ -776,6 +800,8 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
 {
     libxl__ao_device *aodev = CONTAINER_OF(child, *aodev, child);
     STATE_AO_GC(aodev->ao);
+    libxl_nic_type nictype;
+    int rc;
 
     libxl__ev_time_deregister(gc, &aodev->ev);
 
@@ -784,7 +810,25 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
                                                      : LIBXL__LOG_WARNING,
                                       aodev->what, pid, status);
         aodev->rc = ERROR_FAIL;
+        goto out;
     }
+
+    if (aodev->dev->backend_kind == LIBXL__DEVICE_KIND_VIF &&
+        aodev->num_exec == 0) {
+        rc = libxl__nic_type(gc, aodev->dev, &nictype);
+        if (rc) {
+            LOG(ERROR, "unable to get type of nic device");
+            aodev->rc = rc;
+            goto out;
+        }
+        if (nictype == LIBXL_NIC_TYPE_IOEMU) {
+            aodev->num_exec++;
+            device_hotplug(egc, aodev);
+            return;
+        }
+    }
+
+out:
     aodev->callback(egc, aodev);
 }
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 9dd2404..b938756 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -821,6 +821,8 @@ _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__wait_for_backend(libxl__gc *gc, char *be_path, char *state);
+_hidden int libxl__nic_type(libxl__gc *gc, libxl__device *dev,
+                            libxl_nic_type *nictype);
 
 /*
  * For each aggregate type which can be used as an input we provide:
@@ -1849,6 +1851,7 @@ struct libxl__ao_device {
     void *base;
     /* device hotplug execution */
     char *what;
+    int num_exec;
     libxl__ev_time ev;
     libxl__ev_child child;
 };
@@ -1894,10 +1897,19 @@ _hidden void libxl__initiate_device_remove(libxl__egc *egc,
  * < 0: Error
  * 0: No need to execute hotplug script
  * 1: Execute hotplug script
+ *
+ * The last parameter, "num_exec" refeers to the number of times hotplug
+ * scripts have been called for this device. This is currently used for
+ * IOEMU nic interfaces on Linux, since we need to call hotplug scripts twice
+ * for the same device, the first one to add the vif interface, and the second
+ * time to add the tap interface, so:
+ * num_exec == 0: execute hotplug for vif interface.
+ * num_exec == 1: execute hotplug for the associated tap interface.
  */
 _hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                            char ***args, char ***env,
-                                           libxl__device_action action);
+                                           libxl__device_action action,
+                                           int num_exec);
 
 /*----- Domain destruction -----*/
 
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 60a966f..3cd8f40 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -35,6 +35,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
     const char *type = libxl__device_kind_to_string(dev->backend_kind);
     char **env;
     int nr = 0;
+    libxl_nic_type nictype;
 
     script = libxl__xs_read(gc, XBT_NULL,
                             GCSPRINTF("%s/%s", be_path, "script"));
@@ -43,7 +44,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
         return NULL;
     }
 
-    const int arraysize = 9;
+    const int arraysize = 13;
     GCNEW_ARRAY(env, arraysize);
     env[nr++] = "script";
     env[nr++] = script;
@@ -53,14 +54,86 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
     env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
     env[nr++] = "XENBUS_BASE_PATH";
     env[nr++] = "backend";
+    if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
+        if (libxl__nic_type(gc, dev, &nictype)) {
+            LOG(ERROR, "unable to get nictype");
+            return NULL;
+        }
+        switch (nictype) {
+        case LIBXL_NIC_TYPE_IOEMU:
+            env[nr++] = "INTERFACE";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid, dev->devid,
+                                                      LIBXL_NIC_TYPE_IOEMU));
+        case LIBXL_NIC_TYPE_VIF:
+            env[nr++] = "vif";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid, dev->devid,
+                                                      LIBXL_NIC_TYPE_VIF));
+            break;
+        default:
+            return NULL;
+        }
+    }
+
     env[nr++] = NULL;
-    assert(nr == arraysize);
+    assert(nr <= arraysize);
 
     return env;
 }
 
 /* Hotplug scripts caller functions */
 
+static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
+                               char ***args, char ***env,
+                               libxl__device_action action, int num_exec)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    int nr = 0, rc = 0;
+    libxl_nic_type nictype;
+
+    script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
+                                                             "script"));
+    if (!script) {
+        LOGE(ERROR, "unable to read script from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__nic_type(gc, dev, &nictype);
+    if (rc) {
+        LOG(ERROR, "error when fetching nic type");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    *env = get_hotplug_env(gc, dev);
+    if (!env) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    const int arraysize = 4;
+    GCNEW_ARRAY(*args, arraysize);
+    (*args)[nr++] = script;
+
+    if (nictype == LIBXL_NIC_TYPE_IOEMU && num_exec) {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "add" : "remove";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=tap");
+        (*args)[nr++] = NULL;
+    } else {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "online" : "offline";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=vif");
+        (*args)[nr++] = NULL;
+    }
+    assert(nr == arraysize);
+    rc = 0;
+
+out:
+    return rc;
+}
+
 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
                                char ***args, char ***env,
                                libxl__device_action action)
@@ -98,7 +171,8 @@ error:
 
 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
     int rc;
@@ -114,6 +188,10 @@ int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
         rc = libxl__hotplug_disk(gc, dev, args, env, action);
         if (!rc) rc = 1;
         break;
+    case LIBXL__DEVICE_KIND_VIF:
+        rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
+        if (!rc) rc = 1;
+        break;
     default:
         /* If no need to execute any hotplug scripts,
          * call the callback manually
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index d41a046..702eb1e 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -29,7 +29,8 @@ int libxl__try_phy_backend(mode_t st_mode)
 
 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     return 0;
 }
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
                       ` (8 preceding siblings ...)
  2012-05-30 13:07     ` [PATCH v5 09/10] libxl: call hotplug scripts for nic " Roger Pau Monne
@ 2012-05-30 13:07     ` Roger Pau Monne
  2012-06-07 14:50       ` Ian Jackson
  9 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-05-30 13:07 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since the hotplug script that was in charge of cleaning the backend is
no longer launched, we need to clean the backend by ourselves, so use
libxl__xs_path_cleanup instead of xs_rm.

Changes sinve v2:

 * Changed the goto construction to a do-while loop.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl_device.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 841f9ac..77c85b9 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -487,16 +487,26 @@ DEFINE_DEVICES_ADD(vif, nic)
 
 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_transaction_t t = 0;
+    int rc = 0;
 
-    xs_rm(ctx->xsh, XBT_NULL, be_path);
-    xs_rm(ctx->xsh, XBT_NULL, fe_path);
+    do {
+        t = xs_transaction_start(CTX->xsh);
+        libxl__xs_path_cleanup(gc, t, fe_path);
+        libxl__xs_path_cleanup(gc, t, be_path);
+        rc = !xs_transaction_end(CTX->xsh, t, 0);
+    } while (rc && errno == EAGAIN);
+    if (rc) {
+        LOGE(ERROR, "unable to finish transaction");
+        goto out;
+    }
 
     libxl__device_destroy_tapdisk(gc, be_path);
 
-    return 0;
+out:
+    return rc;
 }
 
 /* Callback for device destruction */
-- 
1.7.7.5 (Apple Git-26)

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

* Re: [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device
  2012-05-30 13:07     ` [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device Roger Pau Monne
@ 2012-06-07 10:53       ` Ian Jackson
  2012-06-11 10:09         ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 10:53 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device"):
> Introduce a new structure to track state of device backends, that will
> be used in following patches on this series.
...
> +_hidden void libxl__prepare_ao_device(libxl__ao_device *aodev, libxl__ao *ao,
> +                                      libxl__ao_device **base);

The doc comment doesn't seem to explain base.  What is it used for ?

I see only this:

> +void libxl__prepare_ao_device(libxl__ao_device *aodev, libxl__ao *ao,
> +                              libxl__ao_device **base)
...
> +    aodev->base = base;

but:

> +struct libxl__ao_device {
...
> +    /* private for implementation */
...
> +    void *base;
> +};

Why is it void* here when it's only ever set to a libxl__ao_device** ?


> +void libxl__initiate_device_remove(libxl__egc *egc,
> +                                   libxl__ao_device *aodev)
...
> -    libxl__ev_devstate_init(&aorm->ds);
> +    libxl__ev_devstate_init(&aodev->ds);
> 
> -    rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_remove_callback,
> +    rc = libxl__ev_devstate_wait(gc, &aodev->ds, device_backend_callback,
>                                   state_path, XenbusStateClosed,
>                                   LIBXL_DESTROY_TIMEOUT * 1000);

libxl__ev_devstate_init is not needed before _wait.  (Admittedly
that's there in the code before you touched it.)  In general foo_init
is not needed before foo_do_the_thing_and_call_me_back.

Given the use of `backend' in function names to refer to what is
manipulated with aodev->ds, perhaps aodev->ds should be called
aodev->backend_ds ?

I was briefly confused about whether `device_backend_cleanup' was a
general cleanup function for a libxl__ao_device (which it isn't).  And
there is of course a frontend state too, which we don't explicitly
deal with here.

How do the frontend and backend directories get removed from
xenstore ?  (I have a feeling I have asked this before but I don't
remember the answer.  Perhaps it could be a comment in the code in
some appropriate place?)


> +/* This functions sets the necessary libxl__ao_device struct values to use
> + * safely inside functions. It marks the operation as "active"

This `active' business is not used in this patch.  The variable and
its initialisation and commentary should be introduced in the same
patch as its use.

So either the ancillary functions which use `active' need to be
brought forward and documented here, or the introduction of `active'
should be postponed.

> +struct libxl__ao_device {
> +    /* filled in by user */
> +    libxl__ao *ao;
> +    /* action being performed */
> +    libxl__device_action action;
> +    libxl__device *dev;
> +    int force;
> +    libxl__device_callback *callback;
> +    /* private for implementation */
> +    int active;
...

This is a bit confusing.  I would remove the comment `/* action being
performed */' because it seems to refer to all the following variables
(and to disapply `/* filled in by user */' which does in fact apply).
And the only thing it seems to be actually trying to document is that
the variable `action' is the action, which is a bit pointless.

Thanks,
Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
@ 2012-06-07 11:38       ` Ian Jackson
  2012-06-11 12:33         ` Roger Pau Monne
  2012-06-07 14:20       ` Ian Jackson
  2012-06-07 14:25       ` Ian Jackson
  2 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 11:38 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> This patch converts libxl_device_disk_add to an ao operation that

In the subject line `asyn' should be `async'.


> @@ -1859,11 +1883,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
>      ret = 0;
> 
>      libxl_device_disk_remove(ctx, domid, disks + i, 0);
> -    libxl_device_disk_add(ctx, domid, disk);
> +    /* fixme-ao */
> +    libxl_device_disk_add(ctx, domid, disk, 0);

Is there going to be a later patch in a future version of the series
that fixes these ?


> +/* Macro to define callbacks of libxl__add_*, checks if device is last
> + * and calls the function passed as a parameter to this macro with the
> + * following syntax; func(libxl__egc *, parent_type *, int rc) */
> +#define DEFINE_DEVICES_CALLBACK(callback_name, parent_type, array_name, \
> +                                array_size_name, func_to_call)          \
> +    static void callback_name(libxl__egc *egc, libxl__ao_device *aodev) \
> +    {                                                                   \
> +        STATE_AO_GC(aodev->ao);                                         \
> +        parent_type *p = CONTAINER_OF(aodev->base, *p, array_name);     \
> +        int rc;                                                         \
> +                                                                        \
> +        rc = libxl__ao_device_check_last(gc, aodev, p->array_name,      \
> +                                         p->array_size_name);           \
> +        if (rc > 0) return;                                             \
> +        func_to_call(egc, p, rc);                                       \
> +    }

This is acceptable IMO and better than the repetition.  However the
use of a macro for this, so far from the invocation sites, is indeed
less than perfect.

Looking at the content of this macro, the only thing it needs from the
parent is array_name and array_size_name.  If you invented

    typedef struct libxl__ao_devices libxl__ao_devices;
    struct libxl__ao_devices {
        libxl__ao_device *array;
        int size;
        void (*callback)(libxl__egc*, libxl__ao_devices*, int rc);
    };

Then aodev->base could be of type libxl__ao_devices* and the macro
above could be a function.  And indeed it would have type
suitable for simply filling into aodev->callback.  Would that work ?

Doing this would also perhaps mean DEFINE_DEVICES_ADD's generated
libxl__add_FOOs functions could become one single function.  AFAICT
the only macroish things it does are: (1) accessing
d_config->num_FOOs, which could be passed in as a parameter;
(2) passing d_config->FOOs[i] to libxl__device_FOO_add, which could be
dealt with by making libxl__device_FOO_add take a void* for the config
instead, and passing the start of the d_config->FOOs array, plus the
element size, and the add function, as arguments.

Sorry to mess you about.


Whether you retain this as a macro or make it a function,

> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 2dc1cee..1dc8247 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -585,6 +585,13 @@ DEFINE_DEVICES_CALLBACK(domcreate_disk_connected,
>                          libxl__domain_create_state,
>                          devices, num_devices, domcreate_launch_dm)
> 
> +static void domcreate_attach_pci(libxl__egc *egc,
> +                                 libxl__domain_create_state *dcs, int rc);
> +
> +DEFINE_DEVICES_CALLBACK(domcreate_nic_connected,
> +                        libxl__domain_create_state,
> +                        devices, num_devices, domcreate_attach_pci)
> +
>  static void domcreate_console_available(libxl__egc *egc,
>                                          libxl__domain_create_state *dcs);
> 

These seem not to be in linear execution order ?  These kind of
arrangements with a chain of callbacks should really have both the
declarations and the definitions in linear order.  Sadly that means
writing out the declarations of domcreate_nic_connected etc. here in
the declarations section but I think that's a price worth paying.
(This is something you'd have to do anyway if you replace the macro
with a function as I suggest.)


Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
  2012-06-07 11:38       ` Ian Jackson
@ 2012-06-07 14:20       ` Ian Jackson
  2012-06-07 16:42         ` Roger Pau Monne
  2012-06-07 14:25       ` Ian Jackson
  2 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:20 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> This patch converts libxl_device_disk_add to an ao operation that
> waits for device backend to reach state XenbusStateInitWait and then
> marks the operation as completed. This is not really useful now, but
> will be used by latter patches that will launch hotplug scripts after
> we reached the desired xenbus state.

Just spotted:

> +void libxl__initiate_device_add(libxl__egc *egc, libxl__ao_device *aodev)
> +{
...
> +    libxl__ev_devstate_init(&aodev->ds);
> +    rc = libxl__ev_devstate_wait(gc, &aodev->ds, device_backend_callback,
> +                                 state_path, XenbusStateInitWait,
> +                                 LIBXL_INIT_TIMEOUT * 1000);

Another unneeded _init.

I won't comment on any more of these I find.

Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
  2012-06-07 11:38       ` Ian Jackson
  2012-06-07 14:20       ` Ian Jackson
@ 2012-06-07 14:25       ` Ian Jackson
  2012-06-07 16:55         ` Roger Pau Monne
  2 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:25 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> This patch converts libxl_device_disk_add to an ao operation that
> waits for device backend to reach state XenbusStateInitWait and then
> marks the operation as completed. This is not really useful now, but
> will be used by latter patches that will launch hotplug scripts after
> we reached the desired xenbus state.

And:

> +/* Internal AO operation to connect a disk device, called by
> + * libxl_device_disk_add and libxl__add_disks. This function calls
> + * libxl__initiate_device_add */
> +_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
> +                                    libxl_device_disk *disk,
> +                                    libxl__ao_device *aodev);
> +
> +/* Arranges that dev will be added 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.
> + */
> +_hidden void libxl__initiate_device_add(libxl__egc*, libxl__ao_device *aodev);

I don't think these comments are coherent.

I think a function which "Arranges that dev will be added to the
guest" is one which does everything necessary - ie, the outermost
entrypoint.

And you're using `internal' here to mean `internal to libxl'.  I think
that's clear from the name (which has `__').  Whereas on first reading
it sounds like you mean `internal to the device adding machinery' -
but `libxl__device_disk_add' is the main entrypoint to that
machinery.

And `libxl__initiate_device_add' is the internal helper function.

I think these comments need to be clarified and perhaps
libxl__initiate_device_add needs to be renamed to be clear about what
exactly it is for.  Eg
   /* Initiates the device-kind-independent operations blah blah
   hidden void libxl__initiate_device_add_core(libxl__egc*,
                                   libxl__ao_device *aodev);
or something.

Please do reply suggesting alternative wording

Ian.

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

* Re: [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation
  2012-05-30 13:07     ` [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
@ 2012-06-07 14:26       ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:26 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation"):
> This patch converts libxl_device_nic_add to an ao operation that
> waits for device backend to reach state XenbusStateInitWait and then
> marks the operation as completed. This is not really useful now, but
> will be used by latter patches that will launch hotplug scripts after
> we reached the desired xenbus state.
> 
> Calls to libxl_device_nic_add have also been moved to occur after the
> device model has been launched, so when hotplug scripts are called
> from this functions the interfaces already exists.

This is now a lot smaller, excellent.

> -int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
> +int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
> +                         const libxl_asyncop_how *ao_how)
>  {
> -    GC_INIT(ctx);
> +    AO_CREATE(ctx, domid, ao_how);
> +    libxl__ao_device *device;

Can we call that variable `aodev' ?  Elsewhere `device' is a
libxl_device_FOO.


Ian.

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

* Re: [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl
  2012-05-30 13:07     ` [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
@ 2012-06-07 14:40       ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:40 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl"):
> Since most of the needed work is already done in previous patches,
> this patch only contains the necessary code to call hotplug scripts
> for disk devices, that should be called when the device is added or
> removed from a guest.
...

> +static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
...
> +out:
> +    libxl__ev_time_deregister(gc, &aodev->ev);
> +    aodev->rc = rc;
> +    aodev->callback(egc, aodev);

This little set of things - deregistering the timeout, and calling the
callback, occur a few times.  It would also be a good idea to check
that the child has been reaped, or we may reenter this confusingly
later.

Perhaps it would be a good idea to have:

  static void device_hotplug_done(blah blah)
  {
      libxl__ev_time_deregister(gc, &aodev->ev);
      assert(!libxl__ev_child_inuse(&aodev->child));
      aodev->callback(egc, aodev);
  }

And this could be used on all of the completion paths.  (You'll have
to initialise the ev_child at the top of device_hotplug of course.)

That way the whole thing has one entry and one exit.

> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 5a2a87a..9dd2404 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -72,6 +72,7 @@
> 
>  #define LIBXL_INIT_TIMEOUT 10
>  #define LIBXL_DESTROY_TIMEOUT 10
> +#define LIBXL_HOTPLUG_TIMEOUT 10
>  #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
>  #define LIBXL_XENCONSOLE_LIMIT 1048576
>  #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
> @@ -1846,6 +1847,10 @@ struct libxl__ao_device {
>      int rc;
>      libxl__ev_devstate ds;
>      void *base;
> +    /* device hotplug execution */
> +    char *what;

`const char *what;' ?

Ian.

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

* Re: [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl
  2012-05-30 13:07     ` [PATCH v5 09/10] libxl: call hotplug scripts for nic " Roger Pau Monne
@ 2012-06-07 14:48       ` Ian Jackson
  2012-06-11 14:34         ` Roger Pau Monne
  2012-06-22 11:47         ` [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages] Ian Jackson
  0 siblings, 2 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:48 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl"):
> Since most of the needed work is already done in previous patches,
> this patch only contains the necessary code to call hotplug scripts
> for nic devices, that should be called when the device is added or
> removed from a guest.

> @@ -1894,10 +1897,19 @@ _hidden void libxl__initiate_device_remove(libxl__egc *egc,
>   * < 0: Error
>   * 0: No need to execute hotplug script
>   * 1: Execute hotplug script
> + *
> + * The last parameter, "num_exec" refeers to the number of times hotplug
> + * scripts have been called for this device. This is currently used for
> + * IOEMU nic interfaces on Linux, since we need to call hotplug scripts twice
> + * for the same device, the first one to add the vif interface, and the second
> + * time to add the tap interface, so:
> + * num_exec == 0: execute hotplug for vif interface.
> + * num_exec == 1: execute hotplug for the associated tap interface.
>   */

I think you should add:

    * The main body of libxl will, for each device, keep calling
    * libxl__get_hotplug_script_info, with incrementing values of
    * num_exec, and executing the resulting script accordingly,
    * until libxl__get_hotplug_script_info returns <=0.

Or

    * The main body of libxl will call libxl__get_hotplug_script_info
    * with exactly the stated values of num_exec, above.  For device
    * types not mentioned the main body calls it once with
    * num_exec==0.

Personally I'm inclined think the knowledge that nics need two
invocations while disks need only one should be confined to the
non-portable Linux code.  Or do you think different platforms will
always do this the same way ?  It seems a bit odd to have the
information about num_exec spread about like this.  So I would prefer
the former comment (and the corresponding change to the code).

That also avoids a nic-specific section in the main body of libxl's
hotplug script machinery.

> +int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
> +{
...
> +    }
> +
> +out:
> +    return rc;
> +}
> +

As a matter of good practice I think you should say
      rc = 0;
just before out, on the success path, and not rely on it having
happened to be set to 0 by the previous successful call.

Thanks,
Ian.

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

* Re: [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy
  2012-05-30 13:07     ` [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
@ 2012-06-07 14:50       ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 14:50 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy"):
> Since the hotplug script that was in charge of cleaning the backend is
> no longer launched, we need to clean the backend by ourselves, so use
> libxl__xs_path_cleanup instead of xs_rm.

Surely this change should be in (or before) one of the earlier
patches ?  Specifically, the one where that hotplug script is
disabled.

Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 14:20       ` Ian Jackson
@ 2012-06-07 16:42         ` Roger Pau Monne
  2012-06-07 16:47           ` Ian Jackson
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-07 16:42 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
>> This patch converts libxl_device_disk_add to an ao operation that
>> waits for device backend to reach state XenbusStateInitWait and then
>> marks the operation as completed. This is not really useful now, but
>> will be used by latter patches that will launch hotplug scripts after
>> we reached the desired xenbus state.
>
> Just spotted:
>
>> +void libxl__initiate_device_add(libxl__egc *egc, libxl__ao_device *aodev)
>> +{
> ...
>> +    libxl__ev_devstate_init(&aodev->ds);
>> +    rc = libxl__ev_devstate_wait(gc,&aodev->ds, device_backend_callback,
>> +                                 state_path, XenbusStateInitWait,
>> +                                 LIBXL_INIT_TIMEOUT * 1000);
>
> Another unneeded _init.

Ok, I thought that you need to call libxl__ev_devstate_init before 
libxl__ev_devstate_wait? I just saw that _wait performs the _init itself 
(but without calling _init).

Can't we remove _init, if it's not needed? Having and _init function 
makes people thing they have to use it, and the comments doesn't say 
anything about _wait calling _init itself.

> I won't comment on any more of these I find.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 16:42         ` Roger Pau Monne
@ 2012-06-07 16:47           ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 16:47 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> Can't we remove _init, if it's not needed? Having and _init function 
> makes people thing they have to use it, and the comments doesn't say 
> anything about _wait calling _init itself.

_init is needed to provide a way to initialise the structure so that
it is safe to pass to _cancel.  This means that caller can use
idempotent initialisation and cleanup, which avoids leaks and logic
errors.

This is the same way it's done for many other of the event functions,
eg:
    libxl__ev_FOO_{init,register,deregister}
    libxl__datacopier_{state,init,start,kill}
    libxl__bootloader_{state,init,run}

Feel free to provide a comment clarifying the API.

Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 14:25       ` Ian Jackson
@ 2012-06-07 16:55         ` Roger Pau Monne
  2012-06-07 17:05           ` Ian Jackson
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-07 16:55 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
>> This patch converts libxl_device_disk_add to an ao operation that
>> waits for device backend to reach state XenbusStateInitWait and then
>> marks the operation as completed. This is not really useful now, but
>> will be used by latter patches that will launch hotplug scripts after
>> we reached the desired xenbus state.
>
> And:
>
>> +/* Internal AO operation to connect a disk device, called by
>> + * libxl_device_disk_add and libxl__add_disks. This function calls
>> + * libxl__initiate_device_add */
>> +_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
>> +                                    libxl_device_disk *disk,
>> +                                    libxl__ao_device *aodev);
>> +
>> +/* Arranges that dev will be added 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.
>> + */
>> +_hidden void libxl__initiate_device_add(libxl__egc*, libxl__ao_device *aodev);
>
> I don't think these comments are coherent.
>
> I think a function which "Arranges that dev will be added to the
> guest" is one which does everything necessary - ie, the outermost
> entrypoint.
>
> And you're using `internal' here to mean `internal to libxl'.  I think
> that's clear from the name (which has `__').  Whereas on first reading
> it sounds like you mean `internal to the device adding machinery' -
> but `libxl__device_disk_add' is the main entrypoint to that
> machinery.

I've used 'internal' here to reflex the difference between 
libxl_device_disk_add and libxl__device_disk_add, but probably leads to 
confusion.

> And `libxl__initiate_device_add' is the internal helper function.
>
> I think these comments need to be clarified and perhaps
> libxl__initiate_device_add needs to be renamed to be clear about what
> exactly it is for.  Eg
>     /* Initiates the device-kind-independent operations blah blah
>     hidden void libxl__initiate_device_add_core(libxl__egc*,
>                                     libxl__ao_device *aodev);
> or something.
>
> Please do reply suggesting alternative wording
>
> Ian.

Well the order is the following:

libxl__device_{disk/nic}_add (device type dependant function) -> 
libxl__initiate_device_add (device type independent).

I'm really bad about this naming thing. But the fact is that 
libxl__initiate_device_add is not a good name, since when we call this 
function the device is already added (to xenstore), this merely waits 
for it to reach the desired state and performs the necessary actions to 
"add" it to the guest (call hotplug scripts). Maybe "connect" is a more 
appropriate name than "add".

I liked the nomenclature because it follows the same style as 
libxl__initiate_device_remove, and I think (and I might be wrong) it 
makes things easier to understand.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 16:55         ` Roger Pau Monne
@ 2012-06-07 17:05           ` Ian Jackson
  2012-06-07 17:07             ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 17:05 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> Ian Jackson wrote:
> > And you're using `internal' here to mean `internal to libxl'.  I think
> > that's clear from the name (which has `__').  Whereas on first reading
> > it sounds like you mean `internal to the device adding machinery' -
> > but `libxl__device_disk_add' is the main entrypoint to that
> > machinery.
> 
> I've used 'internal' here to reflex the difference between 
> libxl_device_disk_add and libxl__device_disk_add, but probably leads to 
> confusion.

Yes.

> Well the order is the following:
> 
> libxl__device_{disk/nic}_add (device type dependant function) -> 
> libxl__initiate_device_add (device type independent).

Yes.

> I'm really bad about this naming thing. But the fact is that 
> libxl__initiate_device_add is not a good name, since when we call this 
> function the device is already added (to xenstore), this merely waits 
> for it to reach the desired state and performs the necessary actions to 
> "add" it to the guest (call hotplug scripts). Maybe "connect" is a more 
> appropriate name than "add".

Perhaps so.

> I liked the nomenclature because it follows the same style as 
> libxl__initiate_device_remove, and I think (and I might be wrong) it 
> makes things easier to understand.

But  libxl__initiate_device_remove  _is_ the function which actually
initiates a device removal.  It isn't an internal helper for a
family of  libxl__device_FOO_remove  functions.

If it were symmetrical,  libxl__initate_device_add  would be the
single entrypoint and it would call something kind-specific as a helper.
That's what the comments and names seem to suggest to me, apart from
the explicit statement that it's the other way around.

Hence my feeling that it needs to be clarified and perhaps this
function renamed.

Ian.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 17:05           ` Ian Jackson
@ 2012-06-07 17:07             ` Roger Pau Monne
  2012-06-07 17:11               ` Ian Jackson
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-07 17:07 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
>> Ian Jackson wrote:
>>> And you're using `internal' here to mean `internal to libxl'.  I think
>>> that's clear from the name (which has `__').  Whereas on first reading
>>> it sounds like you mean `internal to the device adding machinery' -
>>> but `libxl__device_disk_add' is the main entrypoint to that
>>> machinery.
>> I've used 'internal' here to reflex the difference between
>> libxl_device_disk_add and libxl__device_disk_add, but probably leads to
>> confusion.
>
> Yes.
>
>> Well the order is the following:
>>
>> libxl__device_{disk/nic}_add (device type dependant function) ->
>> libxl__initiate_device_add (device type independent).
>
> Yes.
>
>> I'm really bad about this naming thing. But the fact is that
>> libxl__initiate_device_add is not a good name, since when we call this
>> function the device is already added (to xenstore), this merely waits
>> for it to reach the desired state and performs the necessary actions to
>> "add" it to the guest (call hotplug scripts). Maybe "connect" is a more
>> appropriate name than "add".
>
> Perhaps so.
>
>> I liked the nomenclature because it follows the same style as
>> libxl__initiate_device_remove, and I think (and I might be wrong) it
>> makes things easier to understand.
>
> But  libxl__initiate_device_remove  _is_ the function which actually
> initiates a device removal.  It isn't an internal helper for a
> family of  libxl__device_FOO_remove  functions.
>
> If it were symmetrical,  libxl__initate_device_add  would be the
> single entrypoint and it would call something kind-specific as a helper.
> That's what the comments and names seem to suggest to me, apart from
> the explicit statement that it's the other way around.
>
> Hence my feeling that it needs to be clarified and perhaps this
> function renamed.

What about libxl__initiate_device_connection?

and thanks for reviewing the code :).

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 17:07             ` Roger Pau Monne
@ 2012-06-07 17:11               ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-07 17:11 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
> Ian Jackson wrote:
...
> > Hence my feeling that it needs to be clarified and perhaps this
> > function renamed.
> 
> What about libxl__initiate_device_connection?

That would be fine by me.  You'll want to improve the comments too.

> and thanks for reviewing the code :).

You're welcome.  Sorry I found things this time round that I could
have perhaps seen last time...

Ian.

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

* Re: [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device
  2012-06-07 10:53       ` Ian Jackson
@ 2012-06-11 10:09         ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-11 10:09 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:

I've fixed al other comments, so I'm not going to reply to every one of 
them :)

>> +void libxl__initiate_device_remove(libxl__egc *egc,
>> +                                   libxl__ao_device *aodev)
> ...
>> -    libxl__ev_devstate_init(&aorm->ds);
>> +    libxl__ev_devstate_init(&aodev->ds);
>>
>> -    rc = libxl__ev_devstate_wait(gc,&aorm->ds, device_remove_callback,
>> +    rc = libxl__ev_devstate_wait(gc,&aodev->ds, device_backend_callback,
>>                                    state_path, XenbusStateClosed,
>>                                    LIBXL_DESTROY_TIMEOUT * 1000);
>
> libxl__ev_devstate_init is not needed before _wait.  (Admittedly
> that's there in the code before you touched it.)  In general foo_init
> is not needed before foo_do_the_thing_and_call_me_back.
>
> Given the use of `backend' in function names to refer to what is
> manipulated with aodev->ds, perhaps aodev->ds should be called
> aodev->backend_ds ?

Done, I've changed it to backend_ds

> I was briefly confused about whether `device_backend_cleanup' was a
> general cleanup function for a libxl__ao_device (which it isn't).  And
> there is of course a frontend state too, which we don't explicitly
> deal with here.
>
> How do the frontend and backend directories get removed from
> xenstore ?  (I have a feeling I have asked this before but I don't
> remember the answer.  Perhaps it could be a comment in the code in
> some appropriate place?)

We talked about this, and now I've introduced a function that is always 
called before the user callback, that deletes both frontend and backend 
xs entries.

So the flow of execution is a little bit more "linear", and we have 
common entry and exit points, we only call the callback from the exit 
function.

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

* Re: [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op
  2012-06-07 11:38       ` Ian Jackson
@ 2012-06-11 12:33         ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-11 12:33 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op"):
>> This patch converts libxl_device_disk_add to an ao operation that
>
> In the subject line `asyn' should be `async'.
>
>
>> @@ -1859,11 +1883,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
>>       ret = 0;
>>
>>       libxl_device_disk_remove(ctx, domid, disks + i, 0);
>> -    libxl_device_disk_add(ctx, domid, disk);
>> +    /* fixme-ao */
>> +    libxl_device_disk_add(ctx, domid, disk, 0);
>
> Is there going to be a later patch in a future version of the series
> that fixes these ?
>

Not really, but I might add one.

>
>> +/* Macro to define callbacks of libxl__add_*, checks if device is last
>> + * and calls the function passed as a parameter to this macro with the
>> + * following syntax; func(libxl__egc *, parent_type *, int rc) */
>> +#define DEFINE_DEVICES_CALLBACK(callback_name, parent_type, array_name, \
>> +                                array_size_name, func_to_call)          \
>> +    static void callback_name(libxl__egc *egc, libxl__ao_device *aodev) \
>> +    {                                                                   \
>> +        STATE_AO_GC(aodev->ao);                                         \
>> +        parent_type *p = CONTAINER_OF(aodev->base, *p, array_name);     \
>> +        int rc;                                                         \
>> +                                                                        \
>> +        rc = libxl__ao_device_check_last(gc, aodev, p->array_name,      \
>> +                                         p->array_size_name);           \
>> +        if (rc>  0) return;                                             \
>> +        func_to_call(egc, p, rc);                                       \
>> +    }
>
> This is acceptable IMO and better than the repetition.  However the
> use of a macro for this, so far from the invocation sites, is indeed
> less than perfect.
>
> Looking at the content of this macro, the only thing it needs from the
> parent is array_name and array_size_name.  If you invented
>
>      typedef struct libxl__ao_devices libxl__ao_devices;
>      struct libxl__ao_devices {
>          libxl__ao_device *array;
>          int size;
>          void (*callback)(libxl__egc*, libxl__ao_devices*, int rc);
>      };
>
> Then aodev->base could be of type libxl__ao_devices* and the macro
> above could be a function.  And indeed it would have type
> suitable for simply filling into aodev->callback.  Would that work ?

Yes, I've applied this change.

> Doing this would also perhaps mean DEFINE_DEVICES_ADD's generated
> libxl__add_FOOs functions could become one single function.  AFAICT
> the only macroish things it does are: (1) accessing
> d_config->num_FOOs, which could be passed in as a parameter;
> (2) passing d_config->FOOs[i] to libxl__device_FOO_add, which could be
> dealt with by making libxl__device_FOO_add take a void* for the config
> instead, and passing the start of the d_config->FOOs array, plus the
> element size, and the add function, as arguments.

I think this is really too complex for the benefits it introduces, 
libxl__add_{disks/nics} already takes a lot of arguments. Also take into 
account that libxl__device_disk_add is different from the rest now, 
because it takes the extra xs_transaction parameter.

> Sorry to mess you about.
>
>
> Whether you retain this as a macro or make it a function,
>
>> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
>> index 2dc1cee..1dc8247 100644
>> --- a/tools/libxl/libxl_create.c
>> +++ b/tools/libxl/libxl_create.c
>> @@ -585,6 +585,13 @@ DEFINE_DEVICES_CALLBACK(domcreate_disk_connected,
>>                           libxl__domain_create_state,
>>                           devices, num_devices, domcreate_launch_dm)
>>
>> +static void domcreate_attach_pci(libxl__egc *egc,
>> +                                 libxl__domain_create_state *dcs, int rc);
>> +
>> +DEFINE_DEVICES_CALLBACK(domcreate_nic_connected,
>> +                        libxl__domain_create_state,
>> +                        devices, num_devices, domcreate_attach_pci)
>> +
>>   static void domcreate_console_available(libxl__egc *egc,
>>                                           libxl__domain_create_state *dcs);
>>
>
> These seem not to be in linear execution order ?  These kind of
> arrangements with a chain of callbacks should really have both the
> declarations and the definitions in linear order.  Sadly that means
> writing out the declarations of domcreate_nic_connected etc. here in
> the declarations section but I think that's a price worth paying.
> (This is something you'd have to do anyway if you replace the macro
> with a function as I suggest.)

Done.

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

* Re: [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl
  2012-06-07 14:48       ` Ian Jackson
@ 2012-06-11 14:34         ` Roger Pau Monne
  2012-06-22 11:47         ` [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages] Ian Jackson
  1 sibling, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-11 14:34 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl"):
>> Since most of the needed work is already done in previous patches,
>> this patch only contains the necessary code to call hotplug scripts
>> for nic devices, that should be called when the device is added or
>> removed from a guest.
>
>> @@ -1894,10 +1897,19 @@ _hidden void libxl__initiate_device_remove(libxl__egc *egc,
>>    *<  0: Error
>>    * 0: No need to execute hotplug script
>>    * 1: Execute hotplug script
>> + *
>> + * The last parameter, "num_exec" refeers to the number of times hotplug
>> + * scripts have been called for this device. This is currently used for
>> + * IOEMU nic interfaces on Linux, since we need to call hotplug scripts twice
>> + * for the same device, the first one to add the vif interface, and the second
>> + * time to add the tap interface, so:
>> + * num_exec == 0: execute hotplug for vif interface.
>> + * num_exec == 1: execute hotplug for the associated tap interface.
>>    */
>
> I think you should add:
>
>      * The main body of libxl will, for each device, keep calling
>      * libxl__get_hotplug_script_info, with incrementing values of
>      * num_exec, and executing the resulting script accordingly,
>      * until libxl__get_hotplug_script_info returns<=0.
>
> Or
>
>      * The main body of libxl will call libxl__get_hotplug_script_info
>      * with exactly the stated values of num_exec, above.  For device
>      * types not mentioned the main body calls it once with
>      * num_exec==0.
>
> Personally I'm inclined think the knowledge that nics need two
> invocations while disks need only one should be confined to the
> non-portable Linux code.  Or do you think different platforms will
> always do this the same way ?  It seems a bit odd to have the
> information about num_exec spread about like this.  So I would prefer
> the former comment (and the corresponding change to the code).
>
> That also avoids a nic-specific section in the main body of libxl's
> hotplug script machinery.


What do you think about having a function in the non-portable code that 
tells you the number of times you have to call 
libxl__get_hotplug_script_info? So we can do something like:

aodev->total_exec = libxl__get_hotplug_num_exec(...)

It's not pretty, but at least will allow us to abstract this code from 
Linux/NetBSD, since what I basically do now with NetBSD is return 0 on 
the second call, thus avoiding executing anything. But we still have the 
ugly Linux part of the code in libxl_device.

>> +int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
>> +{
> ...
>> +    }
>> +
>> +out:
>> +    return rc;
>> +}
>> +
>
> As a matter of good practice I think you should say
>        rc = 0;
> just before out, on the success path, and not rely on it having
> happened to be set to 0 by the previous successful call.
>
> Thanks,
> Ian.

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

* [PATCH v6 00/13] execute hotplug scripts from libxl
@ 2012-06-14 12:21 Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 01/13] libxl: change ao_device_remove to ao_device Roger Pau Monne
                   ` (14 more replies)
  0 siblings, 15 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel

This series have been splitted in several patches, to make them easier
to review. Also the amount of changes introduced is quite important,
since apart from all the hotplug necessary functions and
modifications, libxl_domain_destroy has been converted to an async op.
This was necessary in order to have async operations during device
removal.

Also, as an important change, disk and nics are added at different
points for HVM and device model based guests, since we need the disk
in order to start Qemu, but the nic hotplug scripts should be called
at a later point, when Qemu has created the corresponding tap device.

This version includes two new relevant changes:

 * Rename IOEMU nic type to VIF_IOEMU (patch 9).

 * Conversion of libxl__device_disk_local_attach to an async 
   operation (patch 5).

Acked:

[PATCH v6 02/13] libxl: move device model creation prototypes
[PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op
[PATCH v6 08/13] libxl: add option to choose who executes hotplug
[PATCH v6 11/13] libxl: use libxl__xs_path_cleanup on device_destroy

Pending:

[PATCH v6 01/13] libxl: change ao_device_remove to ao_device
[PATCH v6 04/13] libxl: move bootloader data strucutres and
[PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to
[PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
[PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async
[PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU
[PATCH v6 10/13] libxl: set nic type to VIF by default
[PATCH v6 12/13] libxl: call hotplug scripts for disk devices from
[PATCH v6 13/13] libxl: call hotplug scripts for nic devices from

Thanks for reviewing, Roger.

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

* [PATCH v6 01/13] libxl: change ao_device_remove to ao_device
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-15 16:45   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 02/13] libxl: move device model creation prototypes Roger Pau Monne
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

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.

Changes since v5:

 * Added a common exit point for device addition/destruction that
   removes backend and frontend entries (on destruction).

 * Posponed the introduction of the base and active fields in the
   ao_device struct.

 * Don't call libxl__ev_devstate_init, since _wait will do it.

 * Removed "action being performed" comment.

Changes sinve v4:

 * Added a more detailed comment in _prepare and _initiate header.

 * Removed an unnecessary state check from
   libxl_initiate_device_remove.

Changes since v2:

 * Remove unnecessary comments in libxl__ao_device.

 * Change libxl__device_cb to device_addrm_aocomplete.

 * Rename aorm parameter in device_addrm_aocomplete to aodev.

 * Use a macro to define {nic,disk,vkb,vfb}_{remove,destroy}
   functions.

 * Rename libxl__init_ao_device to libxl__prepare_ao_device and add a
   comment explaining why we need to set active to 1.

 * Replace al uses of aorm with aodev.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |  214 ++++++++++++++----------------------------
 tools/libxl/libxl.h          |   15 ++-
 tools/libxl/libxl_device.c   |  136 ++++++++++++++++++---------
 tools/libxl/libxl_internal.h |   58 ++++++++++--
 tools/libxl/xl_cmdimpl.c     |    2 +-
 5 files changed, 226 insertions(+), 199 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 6215923..8f5b334 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1432,6 +1432,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 device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    if (aodev->rc) {
+        LOGE(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);
+        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;
@@ -1609,42 +1629,6 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
     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)
@@ -2009,8 +1993,9 @@ int libxl__device_disk_local_detach(libxl__gc *gc, libxl_device_disk *disk)
             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:
@@ -2178,42 +2163,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)
@@ -2540,42 +2489,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)
@@ -2673,41 +2586,56 @@ 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 */
+#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 --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 05f0e01..bb3beaf 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -655,7 +655,8 @@ int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
                              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,
@@ -672,7 +673,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
 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,
@@ -683,14 +686,18 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb);
 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 --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 3da60e1..8ba1915 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -361,11 +361,13 @@ int libxl__device_disk_dev_number(const char *virtpath, int *pdisk,
     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;
+}
 
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
@@ -441,34 +443,29 @@ out:
 
 /* Callbacks for device related operations */
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+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);
+
+static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev);
 
-int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao,
-                                  libxl__device *dev)
+void libxl__initiate_device_remove(libxl__egc *egc,
+                                   libxl__ao_device *aodev)
 {
-    AO_GC;
+    STATE_AO_GC(aodev->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, aodev->dev);
     char *state_path = libxl__sprintf(gc, "%s/state", be_path);
-    char *state = libxl__xs_read(gc, XBT_NULL, state_path);
     int rc = 0;
-    libxl__ao_device_remove *aorm = 0;
-
-    if (!state)
-        goto out_ok;
-    if (atoi(state) != 4) {
-        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);
+    if (aodev->force)
+        libxl__xs_path_cleanup(gc, t,
+                               libxl__device_frontend_path(gc, aodev->dev));
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%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)) {
@@ -479,42 +476,93 @@ 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, &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_fail;
+    }
 
-    return 0;
+    return;
 
  out_fail:
     assert(rc);
-    device_remove_cleanup(gc, aorm);
-    return rc;
-
- out_ok:
-    libxl__ao_complete(egc, ao, 0);
-    return 0;
+    aodev->rc = rc;
+    device_xsentries_remove(egc, aodev);
+    return;
 }
 
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+static void device_backend_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);
+    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;
+    }
+
+    /* Some devices (vkbd) fail to disconnect properly,
+     * but we shouldn't alarm the user if it's during
+     * domain destruction.
+     */
+    if (rc && aodev->action == DEVICE_CONNECT) {
+        LOG(ERROR, "unable to connect device with path %s",
+                   libxl__device_backend_path(gc, aodev->dev));
+        goto out;
+    } else if (rc) {
+        LOG(DEBUG, "unable to disconnect device with path %s",
+                   libxl__device_backend_path(gc, aodev->dev));
+        goto out;
+    }
+
+out:
+    aodev->rc = rc;
+    device_xsentries_remove(egc, aodev);
+    return;
 }
 
-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_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
+{
+    if (!aodev) return;
+    libxl__ev_devstate_cancel(gc, &aodev->backend_ds);
+}
+
+static void device_xsentries_remove(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 ret = 0;
+
+    if (aodev->action == DEVICE_DISCONNECT) {
+        do {
+            t = xs_transaction_start(CTX->xsh);
+            libxl__xs_path_cleanup(gc, t, fe_path);
+            libxl__xs_path_cleanup(gc, t, be_path);
+            ret = !xs_transaction_end(CTX->xsh, t, 0);
+        } while (ret && errno == EAGAIN);
+
+        if (ret) {
+            LOGE(ERROR, "unable to finish transaction");
+            aodev->rc = ERROR_FAIL;
+        }
+    }
+
+    aodev->callback(egc, aodev);
+    return;
 }
 
 int libxl__wait_for_device_model(libxl__gc *gc,
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index fa4c08f..7ed6456 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -853,13 +853,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.
@@ -1864,6 +1857,57 @@ _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 -----*/
+
+/* 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;
+};
+
+/* 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.
+ */
+_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 --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index afa0af6..2ddcdc5 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5357,7 +5357,7 @@ int main_blockdetach(int argc, char **argv)
     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;
 }
 
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 02/13] libxl: move device model creation prototypes
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 01/13] libxl: change ao_device_remove to ao_device Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Move prototypes regarding device model creation, since they will
depend on domain destruction in future patches.

This patch is pure code motion.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl_internal.h |   75 ++++++++++++++++++++---------------------
 1 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 7ed6456..8612fe4 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1095,44 +1095,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
  * gc: allocation pool
@@ -1908,6 +1870,43 @@ struct libxl__ao_device {
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*----- 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*);
+
 /*----- Domain creation -----*/
 
 typedef struct libxl__domain_create_state libxl__domain_create_state;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 01/13] libxl: change ao_device_remove to ao_device Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 02/13] libxl: move device model creation prototypes Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-21 17:34   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes Roger Pau Monne
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

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 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@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c               |  167 +++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl.h               |    3 +-
 tools/libxl/libxl_create.c        |   29 ++++++-
 tools/libxl/libxl_device.c        |  152 +++++++++++++++++++++++++++++----
 tools/libxl/libxl_dm.c            |   83 +++++++++---------
 tools/libxl/libxl_internal.h      |  116 +++++++++++++++++++++++++-
 tools/libxl/xl_cmdimpl.c          |   12 ++--
 tools/python/xen/lowlevel/xl/xl.c |    2 +-
 8 files changed, 483 insertions(+), 81 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 8f5b334..3ad1931 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1146,11 +1146,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;
 
@@ -1161,7 +1283,7 @@ 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)) {
@@ -1194,7 +1316,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);
 
@@ -1217,9 +1369,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 bb3beaf..1967e66 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -526,7 +526,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info,
 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel);
 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 4456ae8..a47bef7 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -590,6 +590,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)
 {
@@ -855,16 +861,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 8ba1915..9243806 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 */
@@ -524,6 +627,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;
     }
 
@@ -565,6 +669,16 @@ static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev)
     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 340fcfa..e5d666a 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -677,6 +677,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);
@@ -897,12 +901,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);
@@ -1095,48 +1118,24 @@ 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)) {
+        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));
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 8612fe4..8478606 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -822,7 +822,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);
 
 /*
@@ -1828,6 +1827,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
@@ -1846,6 +1846,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' filed 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 appropiate 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;
@@ -1854,8 +1868,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
@@ -1870,6 +1901,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. */
@@ -1903,6 +2014,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*);
@@ -1929,6 +2041,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 2ddcdc5..5ba65c2 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1388,7 +1388,7 @@ static int handle_domain_death(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:
@@ -1986,7 +1986,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)
@@ -2549,7 +2549,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); }
 }
 
@@ -2823,7 +2823,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);
 }
@@ -3083,7 +3083,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);
 
@@ -3236,7 +3236,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)

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

* [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (2 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-21 17:35   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op Roger Pau Monne
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Move bootloader and related data after all the device stuff, since
libxl__bootloader_state will depend on libxl__ao_device (to perform
the local attach of a device).

This is pure code motion.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl_internal.h |  166 +++++++++++++++++++++---------------------
 1 files changed, 83 insertions(+), 83 deletions(-)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 8478606..0000d6b 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1692,6 +1692,89 @@ _hidden const char *libxl__xen_script_dir_path(void);
 _hidden const char *libxl__lock_dir_path(void);
 _hidden const char *libxl__run_dir_path(void);
 
+/*----- 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 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
+ * 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);
+
+/* Prepare a bunch of devices for addition/removal. Every ao_device in
+ * ao_devices is set to 'active', and the ao_device 'base' filed 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 appropiate 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;
+    libxl__device_action action;
+    libxl__device *dev;
+    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
+ * 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.
+ */
+_hidden void libxl__initiate_device_remove(libxl__egc *egc,
+                                           libxl__ao_device *aodev);
+
 /*----- datacopier: copies data from one fd to another -----*/
 
 typedef struct libxl__datacopier_state libxl__datacopier_state;
@@ -1818,89 +1901,6 @@ _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 -----*/
-
-/* 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 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
- * 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);
-
-/* Prepare a bunch of devices for addition/removal. Every ao_device in
- * ao_devices is set to 'active', and the ao_device 'base' filed 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 appropiate 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;
-    libxl__device_action action;
-    libxl__device *dev;
-    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
- * 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.
- */
-_hidden void libxl__initiate_device_remove(libxl__egc *egc,
-                                           libxl__ao_device *aodev);
-
 /*----- Domain destruction -----*/
 
 /* Domain destruction has been split into two functions:
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (3 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-21 17:58   ` Ian Jackson
  2012-07-03 15:14   ` Ian Campbell
  2012-06-14 12:21 ` [PATCH v6 06/13] libxl: convert libxl_device_disk_add " Roger Pau Monne
                   ` (9 subsequent siblings)
  14 siblings, 2 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Stefano Stabellini, Ian Jackson, Roger Pau Monne

This will be needed in future patches, when libxl__device_disk_add
becomes async also. Create a new status structure that defines the
local attach of a disk device and use it in
libxl__device_disk_local_attach.

This is done in this patch to split the changes introduced when
libxl__device_disk_add becomes async.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c            |   91 +++++++++++++++++++++++++++----------
 tools/libxl/libxl_bootloader.c |   97 ++++++++++++++++++++++++++++++++++-----
 tools/libxl/libxl_internal.h   |   42 ++++++++++++-----
 3 files changed, 181 insertions(+), 49 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 3ad1931..43affd1 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2027,20 +2027,20 @@ static char * libxl__alloc_vdev(libxl__gc *gc, const char *blkdev_start,
     return NULL;
 }
 
-char * libxl__device_disk_local_attach(libxl__gc *gc,
-        const libxl_device_disk *in_disk,
-        libxl_device_disk *disk,
-        const char *blkdev_start)
+void libxl__device_disk_local_attach(libxl__egc *egc,
+                                     libxl__disk_local_state *dls)
 {
-    libxl_ctx *ctx = gc->owner;
+    STATE_AO_GC(dls->ao);
+    libxl_ctx *ctx = CTX;
     char *dev = NULL, *be_path = NULL;
-    char *ret = NULL;
     int rc, xs_ret;
     libxl__device device;
     xs_transaction_t t = XBT_NULL;
+    const libxl_device_disk *in_disk = dls->in_disk;
+    libxl_device_disk *disk = &dls->disk;
+    const char *blkdev_start = dls->blkdev_start;
 
-    if (in_disk->pdev_path == NULL)
-        return NULL;
+    assert(in_disk->pdev_path);
 
     memcpy(disk, in_disk, sizeof(libxl_device_disk));
     disk->pdev_path = libxl__strdup(gc, in_disk->pdev_path);
@@ -2076,6 +2076,7 @@ char * libxl__device_disk_local_attach(libxl__gc *gc,
             default:
                 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                            "unrecognized disk format: %d", disk->format);
+                rc = ERROR_FAIL;
                 break;
             }
             break;
@@ -2085,15 +2086,18 @@ char * libxl__device_disk_local_attach(libxl__gc *gc,
                     t = xs_transaction_start(ctx->xsh);
                     if (t == XBT_NULL) {
                         LOG(ERROR, "failed to start a xenstore transaction");
+                        rc = ERROR_FAIL;
                         goto out;
                     }
                     disk->vdev = libxl__alloc_vdev(gc, blkdev_start, t);
                     if (disk->vdev == NULL) {
                         LOG(ERROR, "libxl__alloc_vdev failed");
+                        rc = ERROR_FAIL;
                         goto out;
                     }
-                    if (libxl__device_disk_add(gc, LIBXL_TOOLSTACK_DOMID,
-                                t, disk)) {
+                    rc = libxl__device_disk_add(gc, LIBXL_TOOLSTACK_DOMID,
+                                                t, disk);
+                    if (rc) {
                         LOG(ERROR, "libxl_device_disk_add failed");
                         goto out;
                     }
@@ -2102,6 +2106,7 @@ char * libxl__device_disk_local_attach(libxl__gc *gc,
                 t = XBT_NULL;
                 if (xs_ret == 0) {
                     LOGE(ERROR, "xenstore transaction failed");
+                    rc = ERROR_FAIL;
                     goto out;
                 }
                 dev = GCSPRINTF("/dev/%s", disk->vdev);
@@ -2113,6 +2118,7 @@ char * libxl__device_disk_local_attach(libxl__gc *gc,
         default:
             LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk backend "
                 "type: %d", disk->backend);
+            rc = ERROR_FAIL;
             break;
     }
 
@@ -2126,42 +2132,79 @@ char * libxl__device_disk_local_attach(libxl__gc *gc,
             goto out;
     }
     if (dev != NULL)
-        ret = strdup(dev);
-    return ret;
+        dls->diskpath = strdup(dev);
+
+    dls->callback(egc, dls, 0);
+    return;
 
  out:
+    assert(rc);
     if (t != XBT_NULL)
         xs_transaction_end(ctx->xsh, t, 1);
-    else
-        libxl__device_disk_local_detach(gc, disk);
-    return NULL;
+    dls->callback(egc, dls, rc);
 }
 
-int libxl__device_disk_local_detach(libxl__gc *gc, libxl_device_disk *disk)
+/* Callbacks for local detach */
+
+static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev);
+
+void libxl__device_disk_local_detach(libxl__egc *egc,
+                                     libxl__disk_local_state *dls)
 {
+    STATE_AO_GC(dls->ao);
     int rc = 0;
+    libxl_device_disk *disk = &dls->disk;
+    libxl__device *device;
+    libxl__ao_device *aodev = &dls->aodev;
 
     switch (disk->backend) {
         case LIBXL_DISK_BACKEND_QDISK:
             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, 0);
+                GCNEW(device);
+                rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID,
+                                             disk, device);
+                if (rc != 0) goto out;
+
+                libxl__prepare_ao_device(ao, aodev);
+                aodev->action = DEVICE_DISCONNECT;
+                aodev->dev = device;
+                aodev->callback = local_device_detach_cb;
+                aodev->force = 0;
+                libxl__initiate_device_remove(egc, aodev);
             }
-            break;
+            return;
         default:
             /*
              * Nothing to do for PHYSTYPE_PHY.
              * For other device types assume that the blktap2 process is
              * needed by the soon to be started domain and do nothing.
              */
-            break;
+            dls->callback(egc, dls, rc);
+            return;
     }
 
+out:
+    assert(rc);
+    dls->callback(egc, dls, rc);
+    return;
+}
 
-    return rc;
+static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
+
+    if (aodev->rc) {
+        LOGE(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);
+        goto out;
+    }
+
+out:
+    dls->callback(egc, dls, aodev->rc);
+    return;
 }
 
 /******************************************************************************/
diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c
index 7ebc0df..182a975 100644
--- a/tools/libxl/libxl_bootloader.c
+++ b/tools/libxl/libxl_bootloader.c
@@ -224,11 +224,6 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
     if (bl->outputpath) libxl__remove_file(gc, bl->outputpath);
     if (bl->outputdir) libxl__remove_directory(gc, bl->outputdir);
 
-    if (bl->diskpath) {
-        libxl__device_disk_local_detach(gc, &bl->localdisk);
-        free(bl->diskpath);
-        bl->diskpath = 0;
-    }
     libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
     libxl__datacopier_kill(&bl->keystrokes);
     libxl__datacopier_kill(&bl->display);
@@ -249,10 +244,40 @@ static void bootloader_setpaths(libxl__gc *gc, libxl__bootloader_state *bl)
     bl->outputpath = GCSPRINTF(XEN_RUN_DIR "/bootloader.%"PRIu32".out", domid);
 }
 
+/* Callbacks */
+
+static void bootloader_fisnihed_cb(libxl__egc *egc,
+                                   libxl__disk_local_state *dls,
+                                   int rc);
+
 static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
                                 int rc)
 {
     bootloader_cleanup(egc, bl);
+
+    if (bl->diskpath) {
+        bl->dls.callback = bootloader_fisnihed_cb;
+        libxl__device_disk_local_detach(egc, &bl->dls);
+        return;
+    }
+
+    bl->callback(egc, bl, rc);
+}
+
+static void bootloader_fisnihed_cb(libxl__egc *egc,
+                                   libxl__disk_local_state *dls,
+                                   int rc)
+{
+    STATE_AO_GC(dls->ao);
+    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
+
+    free(bl->diskpath);
+    bl->diskpath = 0;
+
+    if (rc) {
+        LOG(ERROR, "unable to detach locally attached disk");
+    }
+
     bl->callback(egc, bl, rc);
 }
 
@@ -275,6 +300,16 @@ static void bootloader_abort(libxl__egc *egc,
 
 /*----- main flow of control -----*/
 
+/* Callbacks */
+
+static void bootloader_disk_attached_cb(libxl__egc *egc,
+                                        libxl__disk_local_state *dls,
+                                        int rc);
+
+static void bootloader_disk_failed_cb(libxl__egc *egc,
+                                      libxl__disk_local_state *dls,
+                                      int rc);
+
 void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
 {
     STATE_AO_GC(bl->ao);
@@ -282,7 +317,6 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
     uint32_t domid = bl->domid;
     char *logfile_tmp = NULL;
     int rc, r;
-    const char *bootloader;
 
     libxl__bootloader_init(bl);
 
@@ -344,13 +378,38 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
         goto out;
     }
 
-    bl->diskpath = libxl__device_disk_local_attach(gc, bl->disk, &bl->localdisk,
-            info->blkdev_start);
-    if (!bl->diskpath) {
-        rc = ERROR_FAIL;
-        goto out;
+    bl->dls.ao = ao;
+    bl->dls.in_disk = bl->disk;
+    bl->dls.blkdev_start = info->blkdev_start;
+    bl->dls.callback = bootloader_disk_attached_cb;
+    libxl__device_disk_local_attach(egc, &bl->dls);
+    return;
+
+ out:
+    assert(rc);
+ out_ok:
+    free(logfile_tmp);
+    bootloader_callback(egc, bl, rc);
+}
+
+static void bootloader_disk_attached_cb(libxl__egc *egc,
+                                        libxl__disk_local_state *dls,
+                                        int rc)
+{
+    STATE_AO_GC(dls->ao);
+    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
+    const libxl_domain_build_info *info = bl->info;
+    const char *bootloader;
+
+    if (rc) {
+        LOG(ERROR, "failed to attach local disk for bootloader execution");
+        dls->callback = bootloader_disk_failed_cb;
+        libxl__device_disk_local_detach(egc, dls);
+        return;
     }
 
+    bl->diskpath = bl->dls.diskpath;
+
     LOG(DEBUG, "Config bootloader value: %s", info->u.pv.bootloader);
 
     if ( !strcmp(info->u.pv.bootloader, "/usr/bin/pygrub") )
@@ -389,11 +448,23 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
 
  out:
     assert(rc);
- out_ok:
-    free(logfile_tmp);
     bootloader_callback(egc, bl, rc);
 }
 
+static void bootloader_disk_failed_cb(libxl__egc *egc,
+                                      libxl__disk_local_state *dls,
+                                      int rc)
+{
+    STATE_AO_GC(dls->ao);
+    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
+
+    if (rc) {
+        LOG(ERROR, "failed to detach locally attached disk");
+    }
+
+    bootloader_callback(egc, bl, ERROR_FAIL);
+}
+
 static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
 {
     libxl__bootloader_state *bl = CONTAINER_OF(op, *bl, openpty);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 0000d6b..85c21b4 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1245,17 +1245,6 @@ _hidden int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
 _hidden int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
         xs_transaction_t t, libxl_device_disk *disk);
 
-/*
- * Make a disk available in this (the control) domain. Returns path to
- * a device.
- */
-_hidden char * libxl__device_disk_local_attach(libxl__gc *gc,
-        const libxl_device_disk *in_disk,
-        libxl_device_disk *new_disk,
-        const char *blkdev_start);
-_hidden int libxl__device_disk_local_detach(libxl__gc *gc,
-        libxl_device_disk *disk);
-
 _hidden char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid);
 
 struct libxl__xen_console_reader {
@@ -1775,6 +1764,35 @@ struct libxl__ao_devices {
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*----- local disk attach: attach a disk locally to run the bootloader -----*/
+
+typedef struct libxl__disk_local_state libxl__disk_local_state;
+typedef void libxl__disk_local_state_callback(libxl__egc*,
+                                              libxl__disk_local_state*,
+                                              int rc);
+
+struct libxl__disk_local_state {
+    /* filled by the user */
+    libxl__ao *ao;
+    const libxl_device_disk *in_disk;
+    libxl_device_disk disk;
+    const char *blkdev_start;
+    libxl__disk_local_state_callback *callback;
+    /* filled by libxl__device_disk_local_attach */
+    char *diskpath;
+    /* private for implementation of local detach */
+    libxl__ao_device aodev;
+};
+
+/*
+ * Make a disk available in this (the control) domain. Calls dls->callback
+ * when finished.
+ */
+_hidden void libxl__device_disk_local_attach(libxl__egc *egc,
+                                             libxl__disk_local_state *dls);
+_hidden void libxl__device_disk_local_detach(libxl__egc *egc,
+                                             libxl__disk_local_state *dls);
+
 /*----- datacopier: copies data from one fd to another -----*/
 
 typedef struct libxl__datacopier_state libxl__datacopier_state;
@@ -1872,7 +1890,7 @@ struct libxl__bootloader_state {
      * the caller using libxl__device_disk_local_detach, but only
      * after the domain's kernel and initramfs have been loaded into
      * memory and the file references disposed of. */
-    libxl_device_disk localdisk;
+    libxl__disk_local_state dls;
     uint32_t domid;
     /* outputs:
      *  - caller must initialise kernel and ramdisk to point to file
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (4 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-22 11:33   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

This patch converts libxl_device_disk_add to an ao operation that
waits for device backend to reach state XenbusStateInitWait and then
marks the operation as completed. This is not really useful now, but
will be used by latter patches that will launch hotplug scripts after
we reached the desired xenbus state.

As usual, libxl_device_disk_add callers have been modified, and the
internal function libxl__device_disk_add has been used if the call was
inside an already running ao.

Changes since v5:

 * Change the disk addition to use the new ao_devices structure.

 * Change name and comment of _initiate_device_add to
   _initiate_device_connect.

Changes since v4:

 * Added more comments about libxl__device_disk_add and
   libxl__add_disks.

 * Removed stray hunk in Makefile.

 * Fixed _prepare call libxl__add_disks (separate into a different
   loop).

 * Moved some code to check if disks have finished to a macro that
   generates a custom function, which will also be used for vif
   interfaces.

Changes since v2:

 * Remove state read from libxl__initiate_device_add

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |  166 ++++++++++++++++++++++++++++--------------
 tools/libxl/libxl.h          |    4 +-
 tools/libxl/libxl_create.c   |   40 ++++++++--
 tools/libxl/libxl_device.c   |   69 +++++++++++++++++
 tools/libxl/libxl_dm.c       |   60 +++++++++++----
 tools/libxl/libxl_internal.h |   43 ++++++++++-
 tools/libxl/xl_cmdimpl.c     |    2 +-
 7 files changed, 301 insertions(+), 83 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 43affd1..5f09740 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1655,13 +1655,16 @@ int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
     return 0;
 }
 
-int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
-        xs_transaction_t t, libxl_device_disk *disk)
+void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
+                            xs_transaction_t t,
+                            libxl_device_disk *disk,
+                            libxl__ao_device *aodev)
 {
+    STATE_AO_GC(aodev->ao);
     flexarray_t *front;
     flexarray_t *back;
     char *dev;
-    libxl__device device;
+    libxl__device *device;
     int major, minor, rc;
     libxl_ctx *ctx = gc->owner;
 
@@ -1686,7 +1689,8 @@ int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
         goto out_free;
     }
 
-    rc = libxl__device_from_disk(gc, domid, disk, &device);
+    GCNEW(device);
+    rc = libxl__device_from_disk(gc, domid, disk, device);
     if (rc != 0) {
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported"
                " virtual disk identifier %s", disk->vdev);
@@ -1704,7 +1708,7 @@ int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
             flexarray_append(back, "params");
             flexarray_append(back, dev);
 
-            assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD);
+            assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
             break;
         case LIBXL_DISK_BACKEND_TAP:
             dev = libxl__blktap_devpath(gc, disk->pdev_path, disk->format);
@@ -1725,7 +1729,7 @@ int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
             flexarray_append(back, "params");
             flexarray_append(back, libxl__sprintf(gc, "%s:%s",
                           libxl__device_disk_string_of_format(disk->format), disk->pdev_path));
-            assert(device.backend_kind == LIBXL__DEVICE_KIND_QDISK);
+            assert(device->backend_kind == LIBXL__DEVICE_KIND_QDISK);
             break;
         default:
             LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk backend type: %d\n", disk->backend);
@@ -1757,29 +1761,42 @@ int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
     flexarray_append(front, "state");
     flexarray_append(front, libxl__sprintf(gc, "%d", 1));
     flexarray_append(front, "virtual-device");
-    flexarray_append(front, libxl__sprintf(gc, "%d", device.devid));
+    flexarray_append(front, libxl__sprintf(gc, "%d", device->devid));
     flexarray_append(front, "device-type");
     flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk");
 
-    libxl__device_generic_add(gc, t, &device,
+    libxl__device_generic_add(gc, t, device,
                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
                              libxl__xs_kvs_of_flexarray(gc, front, front->count));
 
+    aodev->dev = device;
+    aodev->action = DEVICE_CONNECT;
+    libxl__initiate_device_connection(egc, aodev);
+
     rc = 0;
 
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    return rc;
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
 }
 
-int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
+int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid,
+                          libxl_device_disk *disk,
+                          const libxl_asyncop_how *ao_how)
 {
-    GC_INIT(ctx);
-    int rc = libxl__device_disk_add(gc, domid, XBT_NULL, disk);
-    GC_FREE;
-    return rc;
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *aodev;
+
+    GCNEW(aodev);
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->callback = device_addrm_aocomplete;
+    libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev);
+
+    return AO_INPROGRESS;
 }
 
 static void libxl__device_disk_from_xs_be(libxl__gc *gc,
@@ -1982,11 +1999,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
     ret = 0;
 
     libxl_device_disk_remove(ctx, domid, disks + i, 0);
-    libxl_device_disk_add(ctx, domid, disk);
+    /* fixme-ao */
+    libxl_device_disk_add(ctx, domid, disk, 0);
     stubdomid = libxl_get_stubdom_id(ctx, domid);
     if (stubdomid) {
         libxl_device_disk_remove(ctx, stubdomid, disks + i, 0);
-        libxl_device_disk_add(ctx, stubdomid, disk);
+        /* fixme-ao */
+        libxl_device_disk_add(ctx, stubdomid, disk, 0);
     }
 out:
     for (i = 0; i < num; i++)
@@ -2027,15 +2046,17 @@ static char * libxl__alloc_vdev(libxl__gc *gc, const char *blkdev_start,
     return NULL;
 }
 
+/* Callbacks */
+
+static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev);
+
 void libxl__device_disk_local_attach(libxl__egc *egc,
                                      libxl__disk_local_state *dls)
 {
     STATE_AO_GC(dls->ao);
     libxl_ctx *ctx = CTX;
-    char *dev = NULL, *be_path = NULL;
-    int rc, xs_ret;
-    libxl__device device;
-    xs_transaction_t t = XBT_NULL;
+    char *dev = NULL;
+    int rc;
     const libxl_device_disk *in_disk = dls->in_disk;
     libxl_device_disk *disk = &dls->disk;
     const char *blkdev_start = dls->blkdev_start;
@@ -2082,34 +2103,24 @@ void libxl__device_disk_local_attach(libxl__egc *egc,
             break;
         case LIBXL_DISK_BACKEND_QDISK:
             if (disk->format != LIBXL_DISK_FORMAT_RAW) {
-                do {
-                    t = xs_transaction_start(ctx->xsh);
-                    if (t == XBT_NULL) {
-                        LOG(ERROR, "failed to start a xenstore transaction");
-                        rc = ERROR_FAIL;
-                        goto out;
-                    }
-                    disk->vdev = libxl__alloc_vdev(gc, blkdev_start, t);
-                    if (disk->vdev == NULL) {
-                        LOG(ERROR, "libxl__alloc_vdev failed");
-                        rc = ERROR_FAIL;
-                        goto out;
-                    }
-                    rc = libxl__device_disk_add(gc, LIBXL_TOOLSTACK_DOMID,
-                                                t, disk);
-                    if (rc) {
-                        LOG(ERROR, "libxl_device_disk_add failed");
-                        goto out;
-                    }
-                    xs_ret = xs_transaction_end(ctx->xsh, t, 0);
-                } while (xs_ret == 0 && errno == EAGAIN);
-                t = XBT_NULL;
-                if (xs_ret == 0) {
-                    LOGE(ERROR, "xenstore transaction failed");
+                dls->t = xs_transaction_start(ctx->xsh);
+                if (dls->t == XBT_NULL) {
+                    LOG(ERROR, "failed to start a xenstore transaction");
+                    rc = ERROR_FAIL;
+                    goto out;
+                }
+                disk->vdev = libxl__alloc_vdev(gc, blkdev_start, dls->t);
+                if (disk->vdev == NULL) {
+                    LOG(ERROR, "libxl__alloc_vdev failed");
                     rc = ERROR_FAIL;
                     goto out;
                 }
-                dev = GCSPRINTF("/dev/%s", disk->vdev);
+
+                libxl__prepare_ao_device(ao, &dls->aodev);
+                dls->aodev.callback = local_device_attach_cb;
+                libxl__device_disk_add(egc, LIBXL_TOOLSTACK_DOMID,
+                                       dls->t, disk, &dls->aodev);
+                return;
             } else {
                 dev = disk->pdev_path;
             }
@@ -2122,15 +2133,60 @@ void libxl__device_disk_local_attach(libxl__egc *egc,
             break;
     }
 
-    if (disk->vdev != NULL) {
-        rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID, disk, &device);
-        if (rc < 0)
-            goto out;
-        be_path = libxl__device_backend_path(gc, &device);
-        rc = libxl__wait_for_backend(gc, be_path, "4");
-        if (rc < 0)
-            goto out;
+    if (dev != NULL)
+        dls->diskpath = strdup(dev);
+
+    dls->callback(egc, dls, 0);
+    return;
+
+ out:
+    assert(rc);
+    if (dls->t != XBT_NULL)
+        xs_transaction_end(ctx->xsh, dls->t, 1);
+    dls->callback(egc, dls, rc);
+}
+
+static void local_device_attach_cb(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
+    libxl_ctx *ctx = CTX;
+    char *dev = NULL, *be_path = NULL;
+    int rc, xs_ret;
+    libxl__device device;
+    libxl_device_disk *disk = &dls->disk;
+
+    rc = aodev->rc;
+    if (rc) {
+        LOGE(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);
+        goto out;
+    }
+
+    xs_ret = xs_transaction_end(ctx->xsh, dls->t, 0);
+    if (xs_ret == 0 && errno == EAGAIN) {
+        libxl__device_disk_local_attach(egc, dls);
+        return;
+    }
+    dls->t = XBT_NULL;
+    if (xs_ret == 0) {
+        LOGE(ERROR, "xenstore transaction failed");
+        rc = ERROR_FAIL;
+        goto out;
     }
+    dev = GCSPRINTF("/dev/%s", disk->vdev);
+    LOG(DEBUG, "locally attaching qdisk %s", dev);
+
+    rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID, disk, &device);
+    if (rc < 0)
+        goto out;
+    be_path = libxl__device_backend_path(gc, &device);
+    rc = libxl__wait_for_backend(gc, be_path, "4");
+    if (rc < 0)
+        goto out;
+
     if (dev != NULL)
         dls->diskpath = strdup(dev);
 
@@ -2139,8 +2195,8 @@ void libxl__device_disk_local_attach(libxl__egc *egc,
 
  out:
     assert(rc);
-    if (t != XBT_NULL)
-        xs_transaction_end(ctx->xsh, t, 1);
+    if (dls->t != XBT_NULL)
+        xs_transaction_end(ctx->xsh, dls->t, 1);
     dls->callback(egc, dls, rc);
 }
 
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 1967e66..de06f65 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -651,7 +651,9 @@ void libxl_vminfo_list_free(libxl_vminfo *list, int nr);
  */
 
 /* Disks */
-int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
+int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid,
+                          libxl_device_disk *disk,
+                          const libxl_asyncop_how *ao_how);
 int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
                              libxl_device_disk *disk,
                              const libxl_asyncop_how *ao_how);
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index a47bef7..53ecc0d 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -581,6 +581,9 @@ static void domcreate_bootloader_done(libxl__egc *egc,
                                       libxl__bootloader_state *bl,
                                       int rc);
 
+static void domcreate_launch_dm(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                int rc);
+
 static void domcreate_console_available(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);
 
@@ -681,7 +684,6 @@ static void domcreate_bootloader_done(libxl__egc *egc,
 {
     libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
     STATE_AO_GC(bl->ao);
-    int i;
 
     /* convenience aliases */
     const uint32_t domid = dcs->guest_domid;
@@ -720,15 +722,35 @@ static void domcreate_bootloader_done(libxl__egc *egc,
 
     store_libxl_entry(gc, domid, &d_config->b_info);
 
-    for (i = 0; i < d_config->num_disks; i++) {
-        ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]);
-        if (ret) {
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
-                       "cannot add disk %d to domain: %d", i, ret);
-            ret = ERROR_FAIL;
-            goto error_out;
-        }
+    dcs->aodevs.size = d_config->num_disks;
+    libxl__add_disks(egc, ao, domid, d_config, &dcs->aodevs,
+                     domcreate_launch_dm);
+
+    return;
+
+ error_out:
+    assert(ret);
+    domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_launch_dm(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                int rc)
+{
+    libxl__domain_create_state *dcs = CONTAINER_OF(aodevs, *dcs, aodevs);
+    STATE_AO_GC(dcs->ao);
+    int i, ret = 0;
+
+    /* convenience aliases */
+    const uint32_t domid = dcs->guest_domid;
+    libxl_domain_config *const d_config = dcs->guest_config;
+    libxl__domain_build_state *const state = &dcs->build_state;
+    libxl_ctx *const ctx = CTX;
+
+    if (rc) {
+        LOG(ERROR, "unable to add disk devices");
+        goto error_out;
     }
+
     for (i = 0; i < d_config->num_vifs; i++) {
         ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
         if (ret) {
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 9243806..5d34ed5 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -442,6 +442,45 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
     return;
 }
 
+/******************************************************************************/
+
+/* Macro for defining the functions that will add a bunch of disks when
+ * inside an async op.
+ *
+ * This macro is added to prevent repetition of code.
+ */
+
+/* Capatibility macro, since disk_add now takes a xs transaction parameter */
+#define libxl__device_disk_add(egc, domid, disk, aodev)                       \
+        libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)
+
+#define DEFINE_DEVICES_ADD(type)                                              \
+    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
+                              libxl_domain_config *d_config,                  \
+                              libxl__ao_devices *aodevs,                      \
+                              libxl__devices_callback *callback)              \
+    {                                                                         \
+        AO_GC;                                                                \
+        int i;                                                                \
+        aodevs->size = d_config->num_##type##s;                               \
+        aodevs->callback = callback;                                          \
+        libxl__prepare_ao_devices(ao, aodevs);                                \
+        aodevs->callback = callback;                                          \
+                                                                              \
+        for (i = 0; i < aodevs->size; i++) {                                  \
+            aodevs->array[i].callback = libxl__ao_devices_callback;           \
+            libxl__device_##type##_add(egc, domid, &d_config->type##s[i],     \
+                                       &aodevs->array[i]);                    \
+        }                                                                     \
+    }
+
+DEFINE_DEVICES_ADD(disk)
+
+#undef libxl__device_disk_add
+#undef DEFINE_DEVICES_ADD
+
+/******************************************************************************/
+
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
@@ -554,6 +593,36 @@ static void device_backend_cleanup(libxl__gc *gc,
 
 static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev);
 
+void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
+    int rc = 0;
+
+    if (aodev->dev->backend_kind == LIBXL__DEVICE_KIND_QDISK) {
+        aodev->callback(egc, aodev);
+        return;
+    }
+
+    rc = libxl__ev_devstate_wait(gc, &aodev->backend_ds,
+                                 device_backend_callback,
+                                 state_path, XenbusStateInitWait,
+                                 LIBXL_INIT_TIMEOUT * 1000);
+    if (rc) {
+        LOGE(ERROR, "unable to initialize device %s", be_path);
+        goto out_fail;
+    }
+
+    return;
+
+out_fail:
+    assert(rc);
+    aodev->rc = rc;
+    device_xsentries_remove(egc, aodev);
+    return;
+}
+
 void libxl__initiate_device_remove(libxl__egc *egc,
                                    libxl__ao_device *aodev)
 {
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index e5d666a..b7979cb 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -677,6 +677,9 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
                                 libxl__dm_spawn_state *stubdom_dmss,
                                 int rc);
 
+static void spawn_stub_launch_dm(libxl__egc *egc,
+                                 libxl__ao_devices *aodevs, int rc);
+
 static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
                                            libxl__destroy_domid_state *dis,
                                            int rc);
@@ -685,8 +688,7 @@ void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss)
 {
     STATE_AO_GC(sdss->dm.spawn.ao);
     libxl_ctx *ctx = libxl__gc_owner(gc);
-    int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret;
-    libxl__device_console *console;
+    int ret;
     libxl_device_vfb vfb;
     libxl_device_vkb vkb;
     char **args;
@@ -805,22 +807,53 @@ retry_transaction:
         if (errno == EAGAIN)
             goto retry_transaction;
 
-    for (i = 0; i < dm_config->num_disks; i++) {
-        ret = libxl_device_disk_add(ctx, dm_domid, &dm_config->disks[i]);
-        if (ret)
-            goto out_free;
-    }
+    sdss->aodevs.size = dm_config->num_disks;
+    libxl__add_disks(egc, ao, dm_domid, dm_config, &sdss->aodevs,
+                     spawn_stub_launch_dm);
+
+    free(args);
+    return;
+
+out_free:
+    free(args);
+out:
+    assert(ret);
+    spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret);
+}
+
+static void spawn_stub_launch_dm(libxl__egc *egc,
+                                 libxl__ao_devices *aodevs, int rc)
+{
+    libxl__stub_dm_spawn_state *sdss = CONTAINER_OF(aodevs, *sdss, aodevs);
+    STATE_AO_GC(sdss->dm.spawn.ao);
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret = 0;
+    libxl__device_console *console;
+
+    /* convenience aliases */
+    libxl_domain_config *const dm_config = &sdss->dm_config;
+    libxl_domain_config *const guest_config = sdss->dm.guest_config;
+    const int guest_domid = sdss->dm.guest_domid;
+    libxl__domain_build_state *const d_state = sdss->dm.build_state;
+    libxl__domain_build_state *const stubdom_state = &sdss->dm_state;
+    uint32_t dm_domid = sdss->pvqemu.guest_domid;
+
+    if (rc) {
+        LOG(ERROR, "error connecting disk devices");
+        goto out;
+     }
+
     for (i = 0; i < dm_config->num_vifs; i++) {
         ret = libxl_device_nic_add(ctx, dm_domid, &dm_config->vifs[i]);
         if (ret)
-            goto out_free;
+            goto out;
     }
     ret = libxl_device_vfb_add(ctx, dm_domid, &dm_config->vfbs[0]);
     if (ret)
-        goto out_free;
+        goto out;
     ret = libxl_device_vkb_add(ctx, dm_domid, &dm_config->vkbs[0]);
     if (ret)
-        goto out_free;
+        goto out;
 
     if (guest_config->b_info.u.hvm.serial)
         num_console++;
@@ -828,7 +861,7 @@ retry_transaction:
     console = libxl__calloc(gc, num_console, sizeof(libxl__device_console));
     if (!console) {
         ret = ERROR_NOMEM;
-        goto out_free;
+        goto out;
     }
 
     for (i = 0; i < num_console; i++) {
@@ -864,7 +897,7 @@ retry_transaction:
         ret = libxl__device_console_add(gc, dm_domid, &console[i],
                         i == STUBDOM_CONSOLE_LOGGING ? stubdom_state : NULL);
         if (ret)
-            goto out_free;
+            goto out;
     }
 
     sdss->pvqemu.spawn.ao = ao;
@@ -875,11 +908,8 @@ retry_transaction:
 
     libxl__spawn_local_dm(egc, &sdss->pvqemu);
 
-    free(args);
     return;
 
-out_free:
-    free(args);
 out:
     assert(ret);
     spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 85c21b4..937ab08 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -70,6 +70,7 @@
 #include "_libxl_types_internal.h"
 #include "_libxl_types_internal_json.h"
 
+#define LIBXL_INIT_TIMEOUT 10
 #define LIBXL_DESTROY_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
 #define LIBXL_XENCONSOLE_LIMIT 1048576
@@ -1242,8 +1243,6 @@ _hidden void libxl__device_destroy_tapdisk(libxl__gc *gc, char *be_path);
 _hidden int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
                                    libxl_device_disk *disk,
                                    libxl__device *device);
-_hidden int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
-        xs_transaction_t t, libxl_device_disk *disk);
 
 _hidden char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid);
 
@@ -1752,6 +1751,27 @@ struct libxl__ao_devices {
     libxl__devices_callback *callback;
 };
 
+/* AO operation to connect a disk device, called by
+ * libxl_device_disk_add and libxl__add_disks. This function calls
+ * libxl__initiate_device_connection to wait for the device to
+ * finish the connection (might involve executing hotplug scripts).
+ */
+_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
+                                    xs_transaction_t t,
+                                    libxl_device_disk *disk,
+                                    libxl__ao_device *aodev);
+
+/* Waits for the passed device to reach state XenbusStateInitWait.
+ * This is not really useful by itself, but is important when executing
+ * hotplug scripts, since we need to be sure the device is in the correct
+ * state before executing them.
+ *
+ * Once finished, aodev->callback will be executed.
+ */
+_hidden void libxl__initiate_device_connection(libxl__egc*,
+                                               libxl__ao_device *aodev);
+
+
 /* 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
@@ -1782,6 +1802,8 @@ struct libxl__disk_local_state {
     char *diskpath;
     /* private for implementation of local detach */
     libxl__ao_device aodev;
+    /* private for implementation of local attach */
+    xs_transaction_t t;
 };
 
 /*
@@ -1999,6 +2021,19 @@ _hidden void libxl__destroy_domid(libxl__egc *egc,
 _hidden void libxl__devices_destroy(libxl__egc *egc,
                                     libxl__devices_remove_state *drs);
 
+/* Helper function to add a bunch of disks. This should be used when
+ * the caller is inside an async op. "devices" will be prepared by this
+ * function, so there's no need to call _prepare before calling this
+ * function.
+ *
+ * The "callback" will be called for each device, and the user is responsible
+ * for calling libxl__ao_device_check_last on the callback.
+ */
+void libxl__add_disks(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                      libxl_domain_config *d_config,
+                      libxl__ao_devices *aodevs,
+                      libxl__devices_callback *callback);
+
 /*----- device model creation -----*/
 
 /* First layer; wraps libxl__spawn_spawn. */
@@ -2033,6 +2068,8 @@ typedef struct {
     libxl__domain_build_state dm_state;
     libxl__dm_spawn_state pvqemu;
     libxl__destroy_domid_state dis;
+    /* used to store the state of devices being connected */
+    libxl__ao_devices aodevs;
 } libxl__stub_dm_spawn_state;
 
 _hidden void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state*);
@@ -2061,6 +2098,8 @@ struct libxl__domain_create_state {
          * for the non-stubdom device model. */
     /* necessary if the domain creation failed and we have to destroy it */
     libxl__domain_destroy_state dds;
+    /* used to store the state of devices being connected */
+    libxl__ao_devices aodevs;
 };
 
 /*
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 5ba65c2..a40643d 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5296,7 +5296,7 @@ int main_blockattach(int argc, char **argv)
         return 0;
     }
 
-    if (libxl_device_disk_add(ctx, fe_domid, &disk)) {
+    if (libxl_device_disk_add(ctx, fe_domid, &disk, 0)) {
         fprintf(stderr, "libxl_device_disk_add failed.\n");
     }
     return 0;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (5 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 06/13] libxl: convert libxl_device_disk_add " Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-22 11:37   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

This patch converts libxl_device_nic_add to an ao operation that
waits for device backend to reach state XenbusStateInitWait and then
marks the operation as completed. This is not really useful now, but
will be used by latter patches that will launch hotplug scripts after
we reached the desired xenbus state.

Calls to libxl_device_nic_add have also been moved to occur after the
device model has been launched, so when hotplug scripts are called
from this functions the interfaces already exists.

As usual, libxl_device_nic_add callers have been modified, and the
internal function libxl__device_disk_add has been used if the call was
inside an already running ao.

Changes since v5:

 * Updated to use the new ao_devices struct.

 * Renamed ao_device in nic_add to aodev.

Changes since v4:

 * Used the macro defined in previous patch to define the generic
   callback to wait for nics to be connected.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |   39 ++++++++++++++++++++++++++------
 tools/libxl/libxl.h          |    3 +-
 tools/libxl/libxl_create.c   |   50 +++++++++++++++++++++++++++++++++++------
 tools/libxl/libxl_device.c   |    9 ++++---
 tools/libxl/libxl_dm.c       |   37 ++++++++++++++++++++++++++++--
 tools/libxl/libxl_internal.h |   18 +++++++++++++++
 tools/libxl/xl_cmdimpl.c     |    2 +-
 7 files changed, 133 insertions(+), 25 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 5f09740..2d7a7e4 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2314,12 +2314,27 @@ static int libxl__device_from_nic(libxl__gc *gc, uint32_t domid,
     return 0;
 }
 
-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how)
 {
-    GC_INIT(ctx);
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *aodev;
+
+    GCNEW(aodev);
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->callback = device_addrm_aocomplete;
+    libxl__device_nic_add(egc, domid, nic, aodev);
+
+    return AO_INPROGRESS;
+}
+
+void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                           libxl_device_nic *nic, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
     flexarray_t *front;
     flexarray_t *back;
-    libxl__device device;
+    libxl__device *device;
     char *dompath, **l;
     unsigned int nb, rc;
 
@@ -2350,7 +2365,8 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
         }
     }
 
-    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_free;
 
     flexarray_append(back, "frontend-id");
@@ -2391,6 +2407,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
     flexarray_append(back, libxl__strdup(gc, nic->bridge));
     flexarray_append(back, "handle");
     flexarray_append(back, libxl__sprintf(gc, "%d", nic->devid));
+    flexarray_append(back, "type");
+    flexarray_append(back, libxl__strdup(gc,
+                                     libxl_nic_type_to_string(nic->nictype)));
 
     flexarray_append(front, "backend-id");
     flexarray_append(front, libxl__sprintf(gc, "%d", nic->backend_domid));
@@ -2401,18 +2420,22 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
     flexarray_append(front, "mac");
     flexarray_append(front, libxl__sprintf(gc,
                                     LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
-    libxl__device_generic_add(gc, XBT_NULL, &device,
+    libxl__device_generic_add(gc, XBT_NULL, device,
                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
                              libxl__xs_kvs_of_flexarray(gc, front, front->count));
 
-    /* FIXME: wait for plug */
+    aodev->dev = device;
+    aodev->action = DEVICE_CONNECT;
+    libxl__initiate_device_connection(egc, aodev);
+
     rc = 0;
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    GC_FREE;
-    return rc;
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
 }
 
 static void libxl__device_nic_from_xs_be(libxl__gc *gc,
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index de06f65..324f056 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -672,7 +672,8 @@ int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
 int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
 
 /* Network Interfaces */
-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how);
 int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_nic *nic,
                             const libxl_asyncop_how *ao_how);
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 53ecc0d..274f5d4 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -584,6 +584,9 @@ static void domcreate_bootloader_done(libxl__egc *egc,
 static void domcreate_launch_dm(libxl__egc *egc, libxl__ao_devices *aodevs,
                                 int rc);
 
+static void domcreate_attach_pci(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                 int rc);
+
 static void domcreate_console_available(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);
 
@@ -752,13 +755,11 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__ao_devices *aodevs,
     }
 
     for (i = 0; i < d_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
-        if (ret) {
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
-                       "cannot add nic %d to domain: %d", i, ret);
-            ret = ERROR_FAIL;
-            goto error_out;
-        }
+        /* We have to init the nic here, because we still haven't
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &d_config->vifs[i]);
     }
     switch (d_config->c_info.type) {
     case LIBXL_DOMAIN_TYPE_HVM:
@@ -831,7 +832,6 @@ static void domcreate_devmodel_started(libxl__egc *egc,
 {
     libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm);
     STATE_AO_GC(dmss->spawn.ao);
-    int i;
     libxl_ctx *ctx = CTX;
     int domid = dcs->guest_domid;
 
@@ -851,6 +851,40 @@ static void domcreate_devmodel_started(libxl__egc *egc,
         }
     }
 
+    /* Plug nic interfaces */
+    if (d_config->num_vifs > 0) {
+        /* Attach nics */
+        dcs->aodevs.size = d_config->num_vifs;
+        libxl__add_nics(egc, ao, domid, d_config, &dcs->aodevs,
+                        domcreate_attach_pci);
+        return;
+    }
+
+    domcreate_attach_pci(egc, &dcs->aodevs, 0);
+    return;
+
+error_out:
+    assert(ret);
+    domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_attach_pci(libxl__egc *egc, libxl__ao_devices *aodevs,
+                                 int rc)
+{
+    libxl__domain_create_state *dcs = CONTAINER_OF(aodevs, *dcs, aodevs);
+    STATE_AO_GC(dcs->ao);
+    int i, ret = 0;
+    libxl_ctx *ctx = CTX;
+    int domid = dcs->guest_domid;
+
+    /* convenience aliases */
+    libxl_domain_config *const d_config = dcs->guest_config;
+
+    if (rc) {
+        LOG(ERROR, "unable to add nic devices");
+        goto error_out;
+    }
+
     for (i = 0; i < d_config->num_pcidevs; i++)
         libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);
 
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 5d34ed5..f7217aa 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -454,8 +454,8 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
 #define libxl__device_disk_add(egc, domid, disk, aodev)                       \
         libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)
 
-#define DEFINE_DEVICES_ADD(type)                                              \
-    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
+#define DEFINE_DEVICES_ADD(type, name)                                        \
+    void libxl__add_##name##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
                               libxl_domain_config *d_config,                  \
                               libxl__ao_devices *aodevs,                      \
                               libxl__devices_callback *callback)              \
@@ -469,12 +469,13 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
                                                                               \
         for (i = 0; i < aodevs->size; i++) {                                  \
             aodevs->array[i].callback = libxl__ao_devices_callback;           \
-            libxl__device_##type##_add(egc, domid, &d_config->type##s[i],     \
+            libxl__device_##name##_add(egc, domid, &d_config->type##s[i],     \
                                        &aodevs->array[i]);                    \
         }                                                                     \
     }
 
-DEFINE_DEVICES_ADD(disk)
+DEFINE_DEVICES_ADD(disk, disk)
+DEFINE_DEVICES_ADD(vif, nic)
 
 #undef libxl__device_disk_add
 #undef DEFINE_DEVICES_ADD
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index b7979cb..5631f12 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -680,6 +680,10 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
 static void spawn_stub_launch_dm(libxl__egc *egc,
                                  libxl__ao_devices *aodevs, int rc);
 
+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__ao_devices *aodevs,
+                              int rc);
+
 static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
                                            libxl__destroy_domid_state *dis,
                                            int rc);
@@ -844,9 +848,11 @@ static void spawn_stub_launch_dm(libxl__egc *egc,
      }
 
     for (i = 0; i < dm_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, dm_domid, &dm_config->vifs[i]);
-        if (ret)
-            goto out;
+         /* We have to init the nic here, because we still haven't
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &dm_config->vifs[i]);
     }
     ret = libxl_device_vfb_add(ctx, dm_domid, &dm_config->vfbs[0]);
     if (ret)
@@ -923,9 +929,34 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
         CONTAINER_OF(stubdom_dmss, *sdss, pvqemu);
     STATE_AO_GC(sdss->dm.spawn.ao);
     uint32_t dm_domid = sdss->pvqemu.guest_domid;
+    libxl_domain_config *d_config = stubdom_dmss->guest_config;
 
     if (rc) goto out;
 
+    if (d_config->num_vifs > 0) {
+        sdss->aodevs.size = d_config->num_vifs;
+        libxl__add_nics(egc, ao, dm_domid, d_config, &sdss->aodevs,
+                        stubdom_pvqemu_cb);
+        return;
+    }
+
+out:
+    stubdom_pvqemu_cb(egc, &sdss->aodevs, rc);
+}
+
+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__ao_devices *aodevs,
+                              int rc)
+{
+    libxl__stub_dm_spawn_state *sdss = CONTAINER_OF(aodevs, *sdss, aodevs);
+    STATE_AO_GC(sdss->dm.spawn.ao);
+    uint32_t dm_domid = sdss->pvqemu.guest_domid;
+
+    if (rc) {
+        LOGE(ERROR, "error connecting nics devices");
+        goto out;
+    }
+
     rc = libxl_domain_unpause(CTX, dm_domid);
     if (rc) goto out;
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 937ab08..1d4726b 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1761,6 +1761,11 @@ _hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
                                     libxl_device_disk *disk,
                                     libxl__ao_device *aodev);
 
+/* AO operation to connect a nic device */
+_hidden void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                                   libxl_device_nic *nic,
+                                   libxl__ao_device *aodev);
+
 /* Waits for the passed device to reach state XenbusStateInitWait.
  * This is not really useful by itself, but is important when executing
  * hotplug scripts, since we need to be sure the device is in the correct
@@ -2034,6 +2039,19 @@ void libxl__add_disks(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
                       libxl__ao_devices *aodevs,
                       libxl__devices_callback *callback);
 
+/* Helper function to add a bunch of nics. This should be used when
+ * the caller is inside an async op. "devices" will be prepared by this
+ * function, so there's no need to call _prepare before calling this
+ * function.
+ *
+ * The "callback" will be called for each device, and the user is responsible
+ * for calling libxl__ao_device_check_last on the callback.
+ */
+void libxl__add_nics(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                     libxl_domain_config *d_config,
+                     libxl__ao_devices *aodevs,
+                     libxl__devices_callback *callback);
+
 /*----- device model creation -----*/
 
 /* First layer; wraps libxl__spawn_spawn. */
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index a40643d..404c9c2 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5185,7 +5185,7 @@ int main_networkattach(int argc, char **argv)
         return 0;
     }
 
-    if (libxl_device_nic_add(ctx, domid, &nic)) {
+    if (libxl_device_nic_add(ctx, domid, &nic, 0)) {
         fprintf(stderr, "libxl_device_nic_add failed.\n");
         return 1;
     }
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (6 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-07-03  8:33   ` Ian Campbell
  2012-06-14 12:21 ` [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU Roger Pau Monne
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Add and option to xl.conf file to decide if hotplug scripts are
executed from the toolstack (xl) or from udev as it used to be in the
past.

This option is only introduced in this patch, but it has no effect
since the code to call hotplug scripts from libxl is introduced in a
latter patch.

This choice will be saved in "libxl/disable_udev", as specified in the
DISABLE_UDEV_PATH constant.

Changes since v2:

 * Change atoi(...) to !!atoi(...) to prevent returning negative
   values from xenstore (which will be handled as errors).

 * Check for errors on the return value of libxl__hotplug_settings.

Changes since v1:

 * Used an auxiliary function to check for the current setting.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 docs/man/xl.conf.pod.5       |    8 ++++++++
 tools/examples/xl.conf       |    5 +++++
 tools/libxl/libxl_create.c   |   36 +++++++++++++++++++++++++++++++++++-
 tools/libxl/libxl_internal.c |   19 +++++++++++++++++++
 tools/libxl/libxl_internal.h |    3 +++
 tools/libxl/libxl_types.idl  |    1 +
 tools/libxl/xl.c             |    4 ++++
 tools/libxl/xl.h             |    1 +
 tools/libxl/xl_cmdimpl.c     |    1 +
 9 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/docs/man/xl.conf.pod.5 b/docs/man/xl.conf.pod.5
index 149430c..23932be 100644
--- a/docs/man/xl.conf.pod.5
+++ b/docs/man/xl.conf.pod.5
@@ -55,6 +55,14 @@ default.
 
 Default: C<1>
 
+=item B<run_hotplug_scripts=BOOLEAN>
+
+If disabled hotplug scripts will be called from udev, as it used to
+be in the previous releases. With the default option, hotplug scripts
+will be launched by xl directly.
+
+Default: C<1>
+
 =item B<lockfile="PATH">
 
 Sets the path to the lock file used by xl to serialise certain
diff --git a/tools/examples/xl.conf b/tools/examples/xl.conf
index ebf057c..28ab796 100644
--- a/tools/examples/xl.conf
+++ b/tools/examples/xl.conf
@@ -15,3 +15,8 @@
 
 # first block device to be used for temporary VM disk mounts
 #blkdev_start="xvda"
+
+# default option to run hotplug scripts from xl
+# if disabled the old behaviour will be used, and hotplug scripts will be
+# launched by udev.
+#run_hotplug_scripts=1
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 274f5d4..d47d1ea 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -404,7 +404,7 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info,
                        uint32_t *domid)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
-    int flags, ret, rc;
+    int flags, ret, rc, nb_vm;
     char *uuid_string;
     char *dom_path, *vm_path, *libxl_path;
     struct xs_permissions roperm[2];
@@ -525,6 +525,40 @@ retry_transaction:
             libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path),
                         rwperm, ARRAY_SIZE(rwperm));
 
+    if (libxl_list_vm(ctx, &nb_vm) < 0) {
+        LOG(ERROR, "cannot get number of running guests");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    int hotplug_setting = libxl__hotplug_settings(gc, t);
+    if (hotplug_setting < 0) {
+        LOG(ERROR, "unable to get current hotplug scripts execution setting");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (libxl_defbool_val(info->run_hotplug_scripts) != hotplug_setting &&
+        (nb_vm - 1)) {
+        LOG(ERROR, "cannot change hotplug execution option once set, "
+                    "please shutdown all guests before changing it");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl_defbool_val(info->run_hotplug_scripts)) {
+        rc = libxl__xs_write(gc, t, DISABLE_UDEV_PATH, "1");
+        if (rc) {
+            LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH);
+            goto out;
+        }
+    } else {
+        rc = xs_rm(ctx->xsh, t, DISABLE_UDEV_PATH);
+        if (rc) {
+            LOGE(ERROR, "unable to delete %s", DISABLE_UDEV_PATH);
+            goto out;
+        }
+    }
+
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
     xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name));
 
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index 8139520..bc56f21 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -346,6 +346,25 @@ libxl_device_model_version libxl__device_model_version_running(libxl__gc *gc,
     return value;
 }
 
+int libxl__hotplug_settings(libxl__gc *gc, xs_transaction_t t)
+{
+    int rc = 0;
+    char *val;
+
+    val = libxl__xs_read(gc, t, DISABLE_UDEV_PATH);
+    if (!val && errno != ENOENT) {
+        LOGE(ERROR, "cannot read %s from xenstore", DISABLE_UDEV_PATH);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (!val) val = "0";
+
+    rc = !!atoi(val);
+
+out:
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 1d4726b..1350ba9 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -88,6 +88,7 @@
 #define STUBDOM_CONSOLE_SERIAL 3
 #define STUBDOM_SPECIAL_CONSOLES 3
 #define TAP_DEVICE_SUFFIX "-emu"
+#define DISABLE_UDEV_PATH "libxl/disable_udev"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
@@ -1415,6 +1416,8 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s);
 _hidden libxl_device_model_version
 libxl__device_model_version_running(libxl__gc *gc, uint32_t domid);
 
+/* Check how executes hotplug script currently */
+int libxl__hotplug_settings(libxl__gc *gc, xs_transaction_t t);
 
 /*
  * Calling context and GC for event-generating functions:
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index b727abb..1ede19e 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -221,6 +221,7 @@ libxl_domain_create_info = Struct("domain_create_info",[
     ("xsdata",       libxl_key_value_list),
     ("platformdata", libxl_key_value_list),
     ("poolid",       uint32),
+    ("run_hotplug_scripts",libxl_defbool),
     ], dir=DIR_IN)
 
 MemKB = UInt(64, init_val = "LIBXL_MEMKB_DEFAULT")
diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c
index a5ada03..460a6df 100644
--- a/tools/libxl/xl.c
+++ b/tools/libxl/xl.c
@@ -39,6 +39,7 @@ int dryrun_only;
 int force_execution;
 int autoballoon = 1;
 char *blkdev_start;
+libxl_defbool run_hotplug_scripts;
 char *lockfile;
 char *default_vifscript = NULL;
 char *default_bridge = NULL;
@@ -70,6 +71,9 @@ static void parse_global_config(const char *configfile,
     if (!xlu_cfg_get_long (config, "autoballoon", &l, 0))
         autoballoon = l;
 
+    libxl_defbool_setdefault(&run_hotplug_scripts, true);
+    xlu_cfg_get_defbool(config, "run_hotplug_scripts", &run_hotplug_scripts, 0);
+
     if (!xlu_cfg_get_string (config, "lockfile", &buf, 0))
         lockfile = strdup(buf);
     else {
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 59556b5..fddaecb 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -140,6 +140,7 @@ int xl_child_pid(xlchildnum); /* returns 0 if child struct is not in use */
 
 /* global options */
 extern int autoballoon;
+extern libxl_defbool run_hotplug_scripts;
 extern int dryrun_only;
 extern char *lockfile;
 extern char *default_vifscript;
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 404c9c2..fd980b1 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -594,6 +594,7 @@ static void parse_config_data(const char *config_source,
         }
     }
 
+    c_info->run_hotplug_scripts = run_hotplug_scripts;
     c_info->type = LIBXL_DOMAIN_TYPE_PV;
     if (!xlu_cfg_get_string (config, "builder", &buf, 0) &&
         !strncmp(buf, "hvm", strlen(buf)))
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (7 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-22 11:39   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 10/13] libxl: set nic type to VIF by default Roger Pau Monne
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

This change will avoid the confusion caused by the fact that IOEMU
means both PV and TAP network interfaces.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c         |    4 ++--
 tools/libxl/libxl_dm.c      |    8 ++++----
 tools/libxl/libxl_types.idl |    2 +-
 tools/libxl/xl_cmdimpl.c    |    4 ++--
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 2d7a7e4..20c1340 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2296,7 +2296,7 @@ int libxl__device_nic_setdefault(libxl__gc *gc, libxl_device_nic *nic)
                                   libxl__xen_script_dir_path()) < 0 )
         return ERROR_FAIL;
     if (!nic->nictype)
-        nic->nictype = LIBXL_NIC_TYPE_IOEMU;
+        nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
     return 0;
 }
 
@@ -2606,7 +2606,7 @@ const char *libxl__device_nic_devname(libxl__gc *gc,
     switch (type) {
     case LIBXL_NIC_TYPE_VIF:
         return GCSPRINTF("vif%u.%d", domid, devid);
-    case LIBXL_NIC_TYPE_IOEMU:
+    case LIBXL_NIC_TYPE_VIF_IOEMU:
         return GCSPRINTF("vif%u.%d" TAP_DEVICE_SUFFIX, domid, devid);
     default:
         abort();
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 5631f12..45a1a7f 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -206,12 +206,12 @@ static char ** libxl__build_device_model_args_old(libxl__gc *gc,
                               NULL);
         }
         for (i = 0; i < num_vifs; i++) {
-            if (vifs[i].nictype == LIBXL_NIC_TYPE_IOEMU) {
+            if (vifs[i].nictype == LIBXL_NIC_TYPE_VIF_IOEMU) {
                 char *smac = libxl__sprintf(gc,
                                    LIBXL_MAC_FMT, LIBXL_MAC_BYTES(vifs[i].mac));
                 const char *ifname = libxl__device_nic_devname(gc,
                                                 domid, vifs[i].devid,
-                                                LIBXL_NIC_TYPE_IOEMU);
+                                                LIBXL_NIC_TYPE_VIF_IOEMU);
                 flexarray_vappend(dm_args,
                                   "-net",
                                   GCSPRINTF(
@@ -452,12 +452,12 @@ static char ** libxl__build_device_model_args_new(libxl__gc *gc,
                                                          b_info->max_vcpus));
         }
         for (i = 0; i < num_vifs; i++) {
-            if (vifs[i].nictype == LIBXL_NIC_TYPE_IOEMU) {
+            if (vifs[i].nictype == LIBXL_NIC_TYPE_VIF_IOEMU) {
                 char *smac = libxl__sprintf(gc,
                                 LIBXL_MAC_FMT, LIBXL_MAC_BYTES(vifs[i].mac));
                 const char *ifname = libxl__device_nic_devname(gc,
                                                 guest_domid, vifs[i].devid,
-                                                LIBXL_NIC_TYPE_IOEMU);
+                                                LIBXL_NIC_TYPE_VIF_IOEMU);
                 flexarray_append(dm_args, "-device");
                 flexarray_append(dm_args,
                    libxl__sprintf(gc, "%s,id=nic%d,netdev=net%d,mac=%s",
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 1ede19e..80394e1 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -60,7 +60,7 @@ libxl_disk_backend = Enumeration("disk_backend", [
     ])
 
 libxl_nic_type = Enumeration("nic_type", [
-    (1, "IOEMU"),
+    (1, "VIF_IOEMU"),
     (2, "VIF"),
     ])
 
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index fd980b1..66b9d38 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -971,7 +971,7 @@ static void parse_config_data(const char *config_source,
                     nic->bridge = strdup(p2 + 1);
                 } else if (!strcmp(p, "type")) {
                     if (!strcmp(p2 + 1, "ioemu"))
-                        nic->nictype = LIBXL_NIC_TYPE_IOEMU;
+                        nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
                     else
                         nic->nictype = LIBXL_NIC_TYPE_VIF;
                 } else if (!strcmp(p, "ip")) {
@@ -5137,7 +5137,7 @@ int main_networkattach(int argc, char **argv)
             if (!strcmp("vif", oparg)) {
                 nic.nictype = LIBXL_NIC_TYPE_VIF;
             } else if (!strcmp("ioemu", oparg)) {
-                nic.nictype = LIBXL_NIC_TYPE_IOEMU;
+                nic.nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
             } else {
                 fprintf(stderr, "Invalid parameter `type'.\n");
                 return 1;
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (8 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-22 11:40   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 11/13] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Set the default value for nic interfaces to VIF, since it used to be
IOEMU, even for PV guests.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 20c1340..44c8442 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2296,7 +2296,7 @@ int libxl__device_nic_setdefault(libxl__gc *gc, libxl_device_nic *nic)
                                   libxl__xen_script_dir_path()) < 0 )
         return ERROR_FAIL;
     if (!nic->nictype)
-        nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
+        nic->nictype = LIBXL_NIC_TYPE_VIF;
     return 0;
 }
 
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 11/13] libxl: use libxl__xs_path_cleanup on device_destroy
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (9 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 10/13] libxl: set nic type to VIF by default Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-14 12:21 ` [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since the hotplug script that was in charge of cleaning the backend is
no longer launched, we need to clean the backend by ourselves, so use
libxl__xs_path_cleanup instead of xs_rm.

Changes sinve v2:

 * Changed the goto construction to a do-while loop.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl_device.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index f7217aa..ca51577 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -484,16 +484,26 @@ DEFINE_DEVICES_ADD(vif, nic)
 
 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_transaction_t t = 0;
+    int rc = 0;
 
-    xs_rm(ctx->xsh, XBT_NULL, be_path);
-    xs_rm(ctx->xsh, XBT_NULL, fe_path);
+    do {
+        t = xs_transaction_start(CTX->xsh);
+        libxl__xs_path_cleanup(gc, t, fe_path);
+        libxl__xs_path_cleanup(gc, t, be_path);
+        rc = !xs_transaction_end(CTX->xsh, t, 0);
+    } while (rc && errno == EAGAIN);
+    if (rc) {
+        LOGE(ERROR, "unable to finish transaction");
+        goto out;
+    }
 
     libxl__device_destroy_tapdisk(gc, be_path);
 
-    return 0;
+out:
+    return rc;
 }
 
 /* Callback for device destruction */
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (10 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 11/13] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-06-22 11:43   ` Ian Jackson
  2012-06-14 12:21 ` [PATCH v6 13/13] libxl: call hotplug scripts for nic " Roger Pau Monne
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since most of the needed work is already done in previous patches,
this patch only contains the necessary code to call hotplug scripts
for disk devices, that should be called when the device is added or
removed from a guest.

We will chain the launch of the disk hotplug scripts after the
device_backend_callback callback, or directly from
libxl__initiate_device_{add,remove} if the device is already in the
desired state.

Changes since v5:

 * Added common exit point using the device_hotplug_done function.

 * Changed the "what" field in ao_device to "const char *".

Changes since v4:

 * Init args and env to NULL.

 * Correctly propagate errors from libxl__get_hotplug_script_info.

 * Replaced if in libxl__ev_child_inuse with asserts.

 * Renamed fork_cb to child_death_cb.

 * Move deregistration of device_hotplug_timeout_cb to the top of the
   function.

 * Removed "pid" field from libxl__ao_device struct.

 * Moved arraysize declaration.

 * Fixed diff complain about no newline at the end of libxl_netbsd.c.

Changes since v2:

 * Added array size check with assert.

 * Added NetBSD code (so compilation is not broken).

 * Removed a check for null in device_hotplug_timeout_cb.

Changes since v1:

 * Moved all the event related code that was inside libxl_linux.c into
   libxl_device.c, so the flow of the device addition/removal event is
   all in the same file.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/hotplug/Linux/xen-backend.rules     |    6 +-
 tools/hotplug/Linux/xen-hotplug-common.sh |    6 ++
 tools/libxl/libxl.c                       |   10 ++
 tools/libxl/libxl_device.c                |  129 +++++++++++++++++++++++++++-
 tools/libxl/libxl_internal.h              |   19 ++++
 tools/libxl/libxl_linux.c                 |  100 ++++++++++++++++++++++
 tools/libxl/libxl_netbsd.c                |    8 ++
 7 files changed, 270 insertions(+), 8 deletions(-)

diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules
index 405387f..d55ff11 100644
--- a/tools/hotplug/Linux/xen-backend.rules
+++ b/tools/hotplug/Linux/xen-backend.rules
@@ -1,11 +1,11 @@
-SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="tap*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="vbd*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
-SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
+SUBSYSTEM=="xen-backend", ACTION=="remove", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
 SUBSYSTEM=="xen", KERNEL=="blktap[0-9]*", NAME="xen/%k", MODE="0600"
 SUBSYSTEM=="blktap2", KERNEL=="blktap[0-9]*", NAME="xen/blktap-2/%k", MODE="0600"
diff --git a/tools/hotplug/Linux/xen-hotplug-common.sh b/tools/hotplug/Linux/xen-hotplug-common.sh
index 8f6557d..4a7bc73 100644
--- a/tools/hotplug/Linux/xen-hotplug-common.sh
+++ b/tools/hotplug/Linux/xen-hotplug-common.sh
@@ -15,6 +15,12 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
+# Hack to prevent the execution of hotplug scripts from udev if the domain
+# has been launched from libxl
+if [ -n "${UDEV_CALL}" ] && \
+   xenstore-read "libxl/disable_udev" >/dev/null 2>&1; then
+    exit 0
+fi
 
 dir=$(dirname "$0")
 . "$dir/hotplugpath.sh"
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 44c8442..0205b11 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1708,6 +1708,11 @@ void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
             flexarray_append(back, "params");
             flexarray_append(back, dev);
 
+            flexarray_append(back, "script");
+            flexarray_append(back, GCSPRINTF("%s/%s",
+                                             libxl__xen_script_dir_path(),
+                                             "block"));
+
             assert(device->backend_kind == LIBXL__DEVICE_KIND_VBD);
             break;
         case LIBXL_DISK_BACKEND_TAP:
@@ -1723,6 +1728,11 @@ void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
                 libxl__device_disk_string_of_format(disk->format),
                 disk->pdev_path));
 
+            flexarray_append(back, "script");
+            flexarray_append(back, GCSPRINTF("%s/%s",
+                                             libxl__xen_script_dir_path(),
+                                             "blktap"));
+
             /* now create a phy device to export the device to the guest */
             goto do_backend_phy;
         case LIBXL_DISK_BACKEND_QDISK:
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index ca51577..fcbead6 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -602,7 +602,16 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
 static void device_backend_cleanup(libxl__gc *gc,
                                    libxl__ao_device *aodev);
 
-static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev);
+static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev);
+
+static void device_hotplug_timeout_cb(libxl__egc *egc, libxl__ev_time *ev,
+                                      const struct timeval *requested_abs);
+
+static void device_hotplug_child_death_cb(libxl__egc *egc,
+                                          libxl__ev_child *child,
+                                          pid_t pid, int status);
+
+static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
 
 void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
 {
@@ -630,7 +639,7 @@ void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
 out_fail:
     assert(rc);
     aodev->rc = rc;
-    device_xsentries_remove(egc, aodev);
+    device_hotplug_child_death_cb(egc, &aodev->child, 0, 0);
     return;
 }
 
@@ -678,7 +687,7 @@ retry_transaction:
  out_fail:
     assert(rc);
     aodev->rc = rc;
-    device_xsentries_remove(egc, aodev);
+    device_hotplug_child_death_cb(egc, &aodev->child, 0, 0);
     return;
 }
 
@@ -696,6 +705,11 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
         return;
     }
 
+    /* We init this here because we might call device_hotplug_done
+     * without actually calling any hotplug script */
+    libxl__ev_child_init(&aodev->child);
+    libxl__ev_time_init(&aodev->ev);
+
     /* Some devices (vkbd) fail to disconnect properly,
      * but we shouldn't alarm the user if it's during
      * domain destruction.
@@ -711,9 +725,12 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds,
         goto out;
     }
 
+    device_hotplug(egc, aodev);
+    return;
+
 out:
     aodev->rc = rc;
-    device_xsentries_remove(egc, aodev);
+    device_hotplug_done(egc, aodev);
     return;
 }
 
@@ -723,7 +740,104 @@ static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev)
     libxl__ev_devstate_cancel(gc, &aodev->backend_ds);
 }
 
-static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev)
+static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    char *be_path = libxl__device_backend_path(gc, aodev->dev);
+    char **args = NULL, **env = NULL;
+    int rc = 0;
+    int hotplug;
+    pid_t pid;
+
+    /* Check if we have to execute hotplug scripts for this device
+     * and return the necessary args/env vars for execution */
+    hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args, &env,
+                                             aodev->action);
+    switch (hotplug) {
+    case 0:
+        /* no hotplug script to execute */
+        goto out;
+    case 1:
+        /* execute hotplug script */
+        break;
+    default:
+        /* everything else is an error */
+        LOG(ERROR, "unable to get args/env to execute hotplug script for "
+                   "device %s", libxl__device_backend_path(gc, aodev->dev));
+        rc = hotplug;
+        goto out;
+    }
+
+    /* Set hotplug timeout */
+    rc = libxl__ev_time_register_rel(gc, &aodev->ev, device_hotplug_timeout_cb,
+                                     LIBXL_HOTPLUG_TIMEOUT * 1000);
+    if (rc) {
+        LOG(ERROR, "unable to register timeout for hotplug device %s", be_path);
+        goto out;
+    }
+
+    aodev->what = GCSPRINTF("%s %s", args[0], args[1]);
+    LOG(DEBUG, "calling hotplug script: %s %s", args[0], args[1]);
+
+    /* fork and execute hotplug script */
+    pid = libxl__ev_child_fork(gc, &aodev->child, device_hotplug_child_death_cb);
+    if (pid == -1) {
+        LOG(ERROR, "unable to fork");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (!pid) {
+        /* child */
+        libxl__exec(gc, -1, -1, -1, args[0], args, env);
+        /* notreached */
+        abort();
+    }
+
+    assert(libxl__ev_child_inuse(&aodev->child));
+
+    return;
+
+out:
+    aodev->rc = rc;
+    device_hotplug_done(egc, aodev);
+    return;
+}
+
+static void device_hotplug_timeout_cb(libxl__egc *egc, libxl__ev_time *ev,
+                                      const struct timeval *requested_abs)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(ev, *aodev, ev);
+    STATE_AO_GC(aodev->ao);
+
+    assert(libxl__ev_child_inuse(&aodev->child));
+    LOG(DEBUG, "killing hotplug script %s because of timeout", aodev->what);
+    if (kill(aodev->child.pid, SIGKILL)) {
+        LOGEV(ERROR, errno, "unable to kill hotplug script %s [%ld]",
+                            aodev->what, (unsigned long)aodev->child.pid);
+    }
+
+    return;
+}
+
+static void device_hotplug_child_death_cb(libxl__egc *egc,
+                                          libxl__ev_child *child,
+                                          pid_t pid, int status)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(child, *aodev, child);
+    STATE_AO_GC(aodev->ao);
+
+    if (status) {
+        libxl_report_child_exitstatus(CTX, aodev->rc ? LIBXL__LOG_ERROR
+                                                     : LIBXL__LOG_WARNING,
+                                      aodev->what, pid, status);
+        aodev->rc = ERROR_FAIL;
+    }
+
+    device_hotplug_done(egc, aodev);
+}
+
+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);
@@ -731,6 +845,11 @@ static void device_xsentries_remove(libxl__egc *egc, libxl__ao_device *aodev)
     xs_transaction_t t = 0;
     int ret = 0;
 
+    /* Clean events and check reentrancy */
+    libxl__ev_time_deregister(gc, &aodev->ev);
+    assert(!libxl__ev_child_inuse(&aodev->child));
+
+    /* Clean xenstore if it's a disconnection */
     if (aodev->action == DEVICE_DISCONNECT) {
         do {
             t = xs_transaction_start(CTX->xsh);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 1350ba9..a2e375a 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -72,6 +72,7 @@
 
 #define LIBXL_INIT_TIMEOUT 10
 #define LIBXL_DESTROY_TIMEOUT 10
+#define LIBXL_HOTPLUG_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
 #define LIBXL_XENCONSOLE_LIMIT 1048576
 #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
@@ -1739,6 +1740,10 @@ struct libxl__ao_device {
     /* Used internally to have a reference to the upper libxl__ao_devices
      * struct when present */
     libxl__ao_devices *aodevs;
+    /* device hotplug execution */
+    const char *what;
+    libxl__ev_time ev;
+    libxl__ev_child child;
 };
 
 /* Helper struct to simply the plug/unplug of multiple devices at the same
@@ -1792,6 +1797,20 @@ _hidden void libxl__initiate_device_connection(libxl__egc*,
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aodev);
 
+/*
+ * libxl__get_hotplug_script_info returns the args and env that should
+ * be passed to the hotplug script for the requested device.
+ *
+ * Since a device might not need to execute any hotplug script, this function
+ * can return the following values:
+ * < 0: Error
+ * 0: No need to execute hotplug script
+ * 1: Execute hotplug script
+ */
+_hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                           char ***args, char ***env,
+                                           libxl__device_action action);
+
 /*----- local disk attach: attach a disk locally to run the bootloader -----*/
 
 typedef struct libxl__disk_local_state libxl__disk_local_state;
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 0169b2f..8883e45 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -77,3 +77,103 @@ char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
                 "%d", minor & (nr_parts - 1));
     return ret;
 }
+
+/* Hotplug scripts helpers */
+
+static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    const char *type = libxl__device_kind_to_string(dev->backend_kind);
+    char **env;
+    int nr = 0;
+
+    script = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF("%s/%s", be_path, "script"));
+    if (!script) {
+        LOGEV(ERROR, errno, "unable to read script from %s", be_path);
+        return NULL;
+    }
+
+    const int arraysize = 9;
+    GCNEW_ARRAY(env, arraysize);
+    env[nr++] = "script";
+    env[nr++] = script;
+    env[nr++] = "XENBUS_TYPE";
+    env[nr++] = libxl__strdup(gc, type);
+    env[nr++] = "XENBUS_PATH";
+    env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
+    env[nr++] = "XENBUS_BASE_PATH";
+    env[nr++] = "backend";
+    env[nr++] = NULL;
+    assert(nr == arraysize);
+
+    return env;
+}
+
+/* Hotplug scripts caller functions */
+
+static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
+                               char ***args, char ***env,
+                               libxl__device_action action)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    int nr = 0, rc = 0;
+
+    script = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF("%s/%s", be_path, "script"));
+    if (!script) {
+        LOGEV(ERROR, errno, "unable to read script from %s", be_path);
+        rc = ERROR_FAIL;
+        goto error;
+    }
+
+    *env = get_hotplug_env(gc, dev);
+    if (!*env) {
+        rc = ERROR_FAIL;
+        goto error;
+    }
+
+    const int arraysize = 3;
+    GCNEW_ARRAY(*args, arraysize);
+    (*args)[nr++] = script;
+    (*args)[nr++] = action == DEVICE_CONNECT ? "add" : "remove";
+    (*args)[nr++] = NULL;
+    assert(nr == arraysize);
+
+    rc = 0;
+
+error:
+    return rc;
+}
+
+int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                   char ***args, char ***env,
+                                   libxl__device_action action)
+{
+    char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
+    int rc;
+
+    /* Check if we have to run hotplug scripts */
+    if (!disable_udev) {
+        rc = 0;
+        goto out;
+    }
+
+    switch (dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+        rc = libxl__hotplug_disk(gc, dev, args, env, action);
+        if (!rc) rc = 1;
+        break;
+    default:
+        /* If no need to execute any hotplug scripts,
+         * call the callback manually
+         */
+        rc = 0;
+        break;
+    }
+
+out:
+    return rc;
+}
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index dbf5f71..a2f8d3f 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -30,3 +30,11 @@ char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
     /* TODO */
     return NULL;
 }
+
+/* Hotplug scripts caller functions */
+int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
+                                   char ***args, char ***env,
+                                   libxl__device_action action)
+{
+    return 0;
+}
-- 
1.7.7.5 (Apple Git-26)

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

* [PATCH v6 13/13] libxl: call hotplug scripts for nic devices from libxl
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (11 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
@ 2012-06-14 12:21 ` Roger Pau Monne
  2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
  2012-07-03  8:27 ` [PATCH v6 00/13] execute hotplug scripts from libxl Ian Campbell
  2012-07-03  9:19 ` Ian Campbell
  14 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-14 12:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Ian Jackson, Roger Pau Monne

Since most of the needed work is already done in previous patches,
this patch only contains the necessary code to call hotplug scripts
for nic devices, that should be called when the device is added or
removed from a guest.

Added another parameter to libxl__get_hotplug_script_info, that is
used to know the number of times hotplug scripts have been called for
that device. This is currently used by IOEMU nics on Linux.

Changes since v4:

 * Add num_exec to NetBSD dummy function.

 * Better comment in the prototype of libxl__get_hotplug_script_info.

 * Remove nasty use of goto.

 * Keep calling device_hotplug until libxl__get_hotplug_script_info
   returns <= 0. This is used by TAP nics which also have a VIF
   interface (PV_IOEMU).

Changes since v2:

 * Change libxl__nic_type to return the value in a parameter passed by
   the caller.

 * Rename vif_execute to num_exec, to represent the number of times
   hotplug scripts have been called for that device.

Changes since v1:

 * Move event code to libxl_device.c (as in previous patch).

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/hotplug/Linux/xen-backend.rules |    6 +-
 tools/libxl/libxl_device.c            |   50 ++++++++++++++++--
 tools/libxl/libxl_internal.h          |   14 +++++-
 tools/libxl/libxl_linux.c             |   92 +++++++++++++++++++++++++++++++-
 tools/libxl/libxl_netbsd.c            |    3 +-
 5 files changed, 152 insertions(+), 13 deletions(-)

diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules
index d55ff11..c591a3f 100644
--- a/tools/hotplug/Linux/xen-backend.rules
+++ b/tools/hotplug/Linux/xen-backend.rules
@@ -2,8 +2,8 @@ SUBSYSTEM=="xen-backend", KERNEL=="tap*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scr
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
-SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ENV{UDEV_CALL}="1", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ENV{UDEV_CALL}="1", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
 SUBSYSTEM=="xen-backend", ACTION=="remove", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
@@ -13,4 +13,4 @@ KERNEL=="blktap-control", NAME="xen/blktap-2/control", MODE="0600"
 KERNEL=="gntdev", NAME="xen/%k", MODE="0600"
 KERNEL=="pci_iomul", NAME="xen/%k", MODE="0600"
 KERNEL=="tapdev[a-z]*", NAME="xen/blktap-2/tapdev%m", MODE="0600"
-SUBSYSTEM=="net", KERNEL=="vif*-emu", ACTION=="add", RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap"
+SUBSYSTEM=="net", KERNEL=="vif*-emu", ACTION=="add", ENV{UDEV_CALL}="1", RUN+="/etc/xen/scripts/vif-setup $env{ACTION} type_if=tap"
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index fcbead6..7988090 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -100,6 +100,29 @@ out:
     return numdevs;
 }
 
+int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
+{
+    char *snictype, *be_path;
+    int rc = 0;
+
+    be_path = libxl__device_backend_path(gc, dev);
+    snictype = libxl__xs_read(gc, XBT_NULL,
+                              GCSPRINTF("%s/%s", be_path, "type"));
+    if (!snictype) {
+        LOGE(ERROR, "unable to read nictype from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    rc = libxl_nic_type_from_string(snictype, nictype);
+    if (rc) {
+        LOGE(ERROR, "unable to parse nictype from %s", be_path);
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
 int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t,
         libxl__device *device, char **bents, char **fents)
 {
@@ -613,6 +636,8 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
 
 static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
 
+static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev);
+
 void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
@@ -752,7 +777,8 @@ static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev)
     /* Check if we have to execute hotplug scripts for this device
      * and return the necessary args/env vars for execution */
     hotplug = libxl__get_hotplug_script_info(gc, aodev->dev, &args, &env,
-                                             aodev->action);
+                                             aodev->action,
+                                             aodev->num_exec);
     switch (hotplug) {
     case 0:
         /* no hotplug script to execute */
@@ -834,7 +860,16 @@ static void device_hotplug_child_death_cb(libxl__egc *egc,
         aodev->rc = ERROR_FAIL;
     }
 
-    device_hotplug_done(egc, aodev);
+    device_hotplug_clean(gc, aodev);
+
+    /* Increase num_exec and call hotplug scripts again if necessary
+     * If no more executions are needed, device_hotplug will call
+     * device_hotplug_done breaking the loop.
+     */
+    aodev->num_exec++;
+    device_hotplug(egc, aodev);
+
+    return;
 }
 
 static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
@@ -845,9 +880,7 @@ static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
     xs_transaction_t t = 0;
     int ret = 0;
 
-    /* Clean events and check reentrancy */
-    libxl__ev_time_deregister(gc, &aodev->ev);
-    assert(!libxl__ev_child_inuse(&aodev->child));
+    device_hotplug_clean(gc, aodev);
 
     /* Clean xenstore if it's a disconnection */
     if (aodev->action == DEVICE_DISCONNECT) {
@@ -868,6 +901,13 @@ static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev)
     return;
 }
 
+static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev)
+{
+    /* Clean events and check reentrancy */
+    libxl__ev_time_deregister(gc, &aodev->ev);
+    assert(!libxl__ev_child_inuse(&aodev->child));
+}
+
 static void devices_remove_callback(libxl__egc *egc, libxl__ao_devices *aodevs,
                                     int rc)
 {
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index a2e375a..a353291 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -826,6 +826,8 @@ _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__wait_for_backend(libxl__gc *gc, char *be_path, char *state);
+_hidden int libxl__nic_type(libxl__gc *gc, libxl__device *dev,
+                            libxl_nic_type *nictype);
 
 /*
  * For each aggregate type which can be used as an input we provide:
@@ -1742,6 +1744,7 @@ struct libxl__ao_device {
     libxl__ao_devices *aodevs;
     /* device hotplug execution */
     const char *what;
+    int num_exec;
     libxl__ev_time ev;
     libxl__ev_child child;
 };
@@ -1806,10 +1809,19 @@ _hidden void libxl__initiate_device_remove(libxl__egc *egc,
  * < 0: Error
  * 0: No need to execute hotplug script
  * 1: Execute hotplug script
+ *
+ * The last parameter, "num_exec" refeers to the number of times hotplug
+ * scripts have been called for this device.
+ *
+ * The main body of libxl will, for each device, keep calling
+ * libxl__get_hotplug_script_info, with incrementing values of
+ * num_exec, and executing the resulting script accordingly,
+ * until libxl__get_hotplug_script_info returns<=0.
  */
 _hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                            char ***args, char ***env,
-                                           libxl__device_action action);
+                                           libxl__device_action action,
+                                           int num_exec);
 
 /*----- local disk attach: attach a disk locally to run the bootloader -----*/
 
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 8883e45..4877eb5 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -87,6 +87,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
     const char *type = libxl__device_kind_to_string(dev->backend_kind);
     char **env;
     int nr = 0;
+    libxl_nic_type nictype;
 
     script = libxl__xs_read(gc, XBT_NULL,
                             GCSPRINTF("%s/%s", be_path, "script"));
@@ -95,7 +96,7 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
         return NULL;
     }
 
-    const int arraysize = 9;
+    const int arraysize = 13;
     GCNEW_ARRAY(env, arraysize);
     env[nr++] = "script";
     env[nr++] = script;
@@ -105,14 +106,86 @@ static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev)
     env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
     env[nr++] = "XENBUS_BASE_PATH";
     env[nr++] = "backend";
+    if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
+        if (libxl__nic_type(gc, dev, &nictype)) {
+            LOG(ERROR, "unable to get nictype");
+            return NULL;
+        }
+        switch (nictype) {
+        case LIBXL_NIC_TYPE_VIF_IOEMU:
+            env[nr++] = "INTERFACE";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid, dev->devid,
+                                                      LIBXL_NIC_TYPE_VIF_IOEMU));
+        case LIBXL_NIC_TYPE_VIF:
+            env[nr++] = "vif";
+            env[nr++] = libxl__strdup(gc, libxl__device_nic_devname(gc,
+                                                      dev->domid, dev->devid,
+                                                      LIBXL_NIC_TYPE_VIF));
+            break;
+        default:
+            return NULL;
+        }
+    }
+
     env[nr++] = NULL;
-    assert(nr == arraysize);
+    assert(nr <= arraysize);
 
     return env;
 }
 
 /* Hotplug scripts caller functions */
 
+static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
+                               char ***args, char ***env,
+                               libxl__device_action action, int num_exec)
+{
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script;
+    int nr = 0, rc = 0;
+    libxl_nic_type nictype;
+
+    script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
+                                                             "script"));
+    if (!script) {
+        LOGE(ERROR, "unable to read script from %s", be_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__nic_type(gc, dev, &nictype);
+    if (rc) {
+        LOG(ERROR, "error when fetching nic type");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    *env = get_hotplug_env(gc, dev);
+    if (!env) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    const int arraysize = 4;
+    GCNEW_ARRAY(*args, arraysize);
+    (*args)[nr++] = script;
+
+    if (nictype == LIBXL_NIC_TYPE_VIF_IOEMU && num_exec) {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "add" : "remove";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=tap");
+        (*args)[nr++] = NULL;
+    } else {
+        (*args)[nr++] = action == DEVICE_CONNECT ? "online" : "offline";
+        (*args)[nr++] = libxl__strdup(gc, "type_if=vif");
+        (*args)[nr++] = NULL;
+    }
+    assert(nr == arraysize);
+    rc = 0;
+
+out:
+    return rc;
+}
+
 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
                                char ***args, char ***env,
                                libxl__device_action action)
@@ -150,7 +223,8 @@ error:
 
 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
     int rc;
@@ -163,9 +237,21 @@ int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
 
     switch (dev->backend_kind) {
     case LIBXL__DEVICE_KIND_VBD:
+        if (num_exec != 0) {
+            rc = 0;
+            goto out;
+        }
         rc = libxl__hotplug_disk(gc, dev, args, env, action);
         if (!rc) rc = 1;
         break;
+    case LIBXL__DEVICE_KIND_VIF:
+        if (num_exec > 1) {
+            rc = 0;
+            goto out;
+        }
+        rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
+        if (!rc) rc = 1;
+        break;
     default:
         /* If no need to execute any hotplug scripts,
          * call the callback manually
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index a2f8d3f..28cdf21 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -34,7 +34,8 @@ char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
 /* Hotplug scripts caller functions */
 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
                                    char ***args, char ***env,
-                                   libxl__device_action action)
+                                   libxl__device_action action,
+                                   int num_exec)
 {
     return 0;
 }
-- 
1.7.7.5 (Apple Git-26)

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

* Re: [PATCH v6 01/13] libxl: change ao_device_remove to ao_device
  2012-06-14 12:21 ` [PATCH v6 01/13] libxl: change ao_device_remove to ao_device Roger Pau Monne
@ 2012-06-15 16:45   ` Ian Jackson
  2012-06-18  8:58     ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-15 16:45 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 01/13] 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.
...

Looks good.  I have only one comment:

> +static void device_xsentries_remove(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 ret = 0;
> +
> +    if (aodev->action == DEVICE_DISCONNECT) {
> +        do {
> +            t = xs_transaction_start(CTX->xsh);
> +            libxl__xs_path_cleanup(gc, t, fe_path);
> +            libxl__xs_path_cleanup(gc, t, be_path);
> +            ret = !xs_transaction_end(CTX->xsh, t, 0);
> +        } while (ret && errno == EAGAIN);

The error handling here seems a bit lacking.  Perhaps you should
import my "[PATCH 08/21] libxl: provide libxl__xs_*_checked ..." into
your series and use those ?  You can see an example of how they're
used in "[PATCH 09/21] libxl: wait for qemu to acknowledge logdirty
command".

And you need to check the return values from libxl__xs_path_cleanup.

Thanks,
Ian.

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

* Re: [PATCH v6 01/13] libxl: change ao_device_remove to ao_device
  2012-06-15 16:45   ` Ian Jackson
@ 2012-06-18  8:58     ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-18  8:58 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 01/13] 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.
> ...
>
> Looks good.  I have only one comment:
>
>> +static void device_xsentries_remove(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 ret = 0;
>> +
>> +    if (aodev->action == DEVICE_DISCONNECT) {
>> +        do {
>> +            t = xs_transaction_start(CTX->xsh);
>> +            libxl__xs_path_cleanup(gc, t, fe_path);
>> +            libxl__xs_path_cleanup(gc, t, be_path);
>> +            ret = !xs_transaction_end(CTX->xsh, t, 0);
>> +        } while (ret&&  errno == EAGAIN);
>
> The error handling here seems a bit lacking.  Perhaps you should
> import my "[PATCH 08/21] libxl: provide libxl__xs_*_checked ..." into
> your series and use those ?  You can see an example of how they're
> used in "[PATCH 09/21] libxl: wait for qemu to acknowledge logdirty
> command".

Is it possible to change this part of the code after you have committed 
your series? If you want I can send a patch to fix this so you can add 
it at the end of your series.

> And you need to check the return values from libxl__xs_path_cleanup.

Even if I check the return value from libxl__xs_path_cleanup I will only 
print an error message, but the logic of the function will not change, 
and the error message it's already printed by libxl__xs_path_cleanup. If 
front or back xenstore entries remove failed, I will still try to remove 
the other entries and commit the transaction.

Thanks for the review.

Roger.

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

* Re: [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op
  2012-06-14 12:21 ` [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
@ 2012-06-21 17:34   ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-21 17:34 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 03/13] 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.

See below for a couple of typos, but:

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

> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 8612fe4..8478606 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
...
> +/* Prepare a bunch of devices for addition/removal. Every ao_device in
> + * ao_devices is set to 'active', and the ao_device 'base' filed is set to
                                                              ^^^^^
> + * the one pointed by aodevs.

field

> + */
> +_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 appropiate error if found.
                                                   ^^^^^^^^^^
appropriate

Ian.

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

* Re: [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes
  2012-06-14 12:21 ` [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes Roger Pau Monne
@ 2012-06-21 17:35   ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-21 17:35 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes"):
> Move bootloader and related data after all the device stuff, since
> libxl__bootloader_state will depend on libxl__ao_device (to perform
> the local attach of a device).
> 
> This is pure code motion.

On that basis (without having checked it myself):

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

Thanks,
Ian.

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

* Re: [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op
  2012-06-14 12:21 ` [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op Roger Pau Monne
@ 2012-06-21 17:58   ` Ian Jackson
  2012-06-26 10:27     ` Roger Pau Monne
  2012-07-03 15:14   ` Ian Campbell
  1 sibling, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-21 17:58 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Stefano Stabellini, xen-devel

Roger Pau Monne writes ("[PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op"):
> This will be needed in future patches, when libxl__device_disk_add
> becomes async also. Create a new status structure that defines the
> local attach of a disk device and use it in
> libxl__device_disk_local_attach.

This is looking good.  I have a couple of comments:

> diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c
> index 7ebc0df..182a975 100644
> --- a/tools/libxl/libxl_bootloader.c
> +++ b/tools/libxl/libxl_bootloader.c
...
> +static void bootloader_fisnihed_cb(libxl__egc *egc,
                          ^^^^^^^^
`finished'.  You have apparently managed to misspell this everywhere
you mention it!

> +                                   libxl__disk_local_state *dls,
> +                                   int rc);
> +
>  static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
>                                  int rc)
>  {
>      bootloader_cleanup(egc, bl);
> +
> +    if (bl->diskpath) {
> +        bl->dls.callback = bootloader_fisnihed_cb;
> +        libxl__device_disk_local_detach(egc, &bl->dls);
> +        return;
> +    }

Can we make libxl__device_disk_local_detach idempotent (and perhaps
call it `libxl__device_disk_local_attached_initiate_cleanup' or
something, if you can think of a name that's less than a paragraph) ?

If so then this would be simpler and wouldn't need to test
bl->diskpath.

> +static void bootloader_disk_attached_cb(libxl__egc *egc,
> +                                        libxl__disk_local_state *dls,
> +                                        int rc)
...
> +    bl->diskpath = bl->dls.diskpath;

Now that we have a bl->dls.diskpath, surely we can do away with
bl->diskpath ?  I'm not a fan of having multiple variables with the
same information in them, unless it's essential.  It just leads to
confusion and error.

> +/*
> + * Make a disk available in this (the control) domain. Calls dls->callback
> + * when finished.
> + */
> +_hidden void libxl__device_disk_local_attach(libxl__egc *egc,
> +                                             libxl__disk_local_state *dls);
> +_hidden void libxl__device_disk_local_detach(libxl__egc *egc,
> +                                             libxl__disk_local_state *dls);

You really need to explain the rules for one of these dls's.

Is it something like this:

     * A libxl__disk_local_state may be in the following states:
     *    Undefined, Idle, Attaching, Attached, Detaching

    typedef void libxl__disk_local_state_callback(libxl__egc*,
                                                  libxl__disk_local_state*,
                                                  int rc);

   _hidden void libxl__device_disk_local_attach(libxl__egc *egc,
                                                libxl__disk_local_state *dls);
       /* Undefined/Idle -> Attaching.  Will call callback.
        * On entry to callback, if rc!=0 dls is Idle;
        * if rc==0 it is Attached and dls->diskpath is usable. */

   _hidden void libxl__device_disk_local_detach(libxl__egc *egc,
                                                libxl__disk_local_state *dls);
       /* Attached -> Detaching.  Will call callback.
        * On entry to callback, dls is Idle, regardless of
        * success or failure. */

And my suggestion about idempotency would change this latter comment
to:
       /* Idle/Attached -> Detaching.  Will call callback.
        * On entry to callback, dls is Idle, regardless of
        * success or failure. */

And the bootloader code might want this:

   _hidden void libxl__device_disk_local_init(libxl__disk_local_state *dls);
       /* Undefined/Idle -> Idle */

Or you can explain it in prose if you like.

Ian.

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

* Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-14 12:21 ` [PATCH v6 06/13] libxl: convert libxl_device_disk_add " Roger Pau Monne
@ 2012-06-22 11:33   ` Ian Jackson
  2012-06-26 15:04     ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:33 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op"):
> This patch converts libxl_device_disk_add to an ao operation that
> waits for device backend to reach state XenbusStateInitWait and then
> marks the operation as completed. This is not really useful now, but
> will be used by latter patches that will launch hotplug scripts after
                  ^^^^^^
later

> we reached the desired xenbus state.

Thanks, here are my review comments:


> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 85c21b4..937ab08 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
...
> +/* AO operation to connect a disk device, called by
> + * libxl_device_disk_add and libxl__add_disks. This function calls
> + * libxl__initiate_device_connection to wait for the device to
> + * finish the connection (might involve executing hotplug scripts).
> + */
> +_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
> +                                    xs_transaction_t t,
> +                                    libxl_device_disk *disk,
> +                                    libxl__ao_device *aodev);
> +

This is a confusing doc comment.  The reader doesn't want to know how
the function is implemented; we need to know what it does.
Particularly, we need to know what happens when it completes.  I infer
that it calls aodev->callback but this should be stated.

> +/* Waits for the passed device to reach state XenbusStateInitWait.
> + * This is not really useful by itself, but is important when executing
> + * hotplug scripts, since we need to be sure the device is in the correct
> + * state before executing them.
> + *
> + * Once finished, aodev->callback will be executed.
> + */
> +_hidden void libxl__initiate_device_connection(libxl__egc*,
> +                                               libxl__ao_device *aodev);

This function's name and its functionality seem not to correspond.  It
doesn't actually initiate anything, as far as I can tell.

>  /* First layer; wraps libxl__spawn_spawn. */
> @@ -2033,6 +2068,8 @@ typedef struct {
>      libxl__domain_build_state dm_state;
>      libxl__dm_spawn_state pvqemu;
>      libxl__destroy_domid_state dis;
> +    /* used to store the state of devices being connected */
> +    libxl__ao_devices aodevs;
>  } libxl__stub_dm_spawn_state;

I'm not sure how valuable these comments are.  libxl__ao_devices are
always used to store the state of devices being "<something>'d".
That's what a libxl__ao_devices is for.  And in the context of a spawn
or create that would obviously be "connected".

In general I'm a fan of comments which say things which aren't clear
from the code, but I'm not keen on ones which restate what the code
says.


> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
> index 9243806..5d34ed5 100644
> --- a/tools/libxl/libxl_device.c
> +++ b/tools/libxl/libxl_device.c
> @@ -442,6 +442,45 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>      return;
>  }
> 
> +/******************************************************************************/
> +
> +/* Macro for defining the functions that will add a bunch of disks when
> + * inside an async op.
> + *
> + * This macro is added to prevent repetition of code.
> + */
> +
> +/* Capatibility macro, since disk_add now takes a xs transaction parameter */
> +#define libxl__device_disk_add(egc, domid, disk, aodev)                       \
> +        libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)

Is it really safe to call libxl__device_disk_add without a real
transaction ?  I see that the current code does it but it seems wrong
to me.  We end up writing all of the individual settings in the
backend one at a time.

I think this applies to all the other device types too.  So I think
the right answer would be to make them take a transaction parameter
too.  Ie, insert a patch before this one which adds a transaction
parameter (ignored for now and always passed 0 if you don't want to
actually make it work properly) to libxl__add_nic etc.  Then you don't
need this unpleasant macro.

> +void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
> +{
> +    STATE_AO_GC(aodev->ao);
> +    char *be_path = libxl__device_backend_path(gc, aodev->dev);
> +    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
> +    int rc = 0;
...
> +out_fail:
> +    assert(rc);
> +    aodev->rc = rc;
> +    device_xsentries_remove(egc, aodev);
> +    return;
> +}

Firstly, I'm not convinced it's really proper for
libxl__initiate_device_connection to call device_xsentries_remove.
After all device_xsentries_remove is part of the implementation of
libxl__initiate_device_remove.

And, secondly, does device_xsentries_remove really do what you want ?
It has a test in it which makes it only do its work if action is
DISCONNECT.


> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 43affd1..5f09740 100644
> --- a/tools/libxl/libxl.c
> +++ b/tools/libxl/libxl.c


> @@ -2027,15 +2046,17 @@ static char * libxl__alloc_vdev(libxl__gc *gc, const char *blkdev_start,

> +                dls->t = xs_transaction_start(ctx->xsh);
> +                if (dls->t == XBT_NULL) {
> +                    LOG(ERROR, "failed to start a xenstore transaction");
> +                    rc = ERROR_FAIL;
> +                    goto out;
> +                }
> +                disk->vdev = libxl__alloc_vdev(gc, blkdev_start, dls->t);
...
> +                libxl__device_disk_add(egc, LIBXL_TOOLSTACK_DOMID,
> +                                       dls->t, disk, &dls->aodev);
...
> +    xs_ret = xs_transaction_end(ctx->xsh, dls->t, 0);
> +    if (xs_ret == 0 && errno == EAGAIN) {
> +        libxl__device_disk_local_attach(egc, dls);
> +        return;

Isn't the effect of this that if the xs transaction gets a conflict,
we'll rerun the hotplug scripts, etc. ?  I think I may be confused
here, but I don't understand how this transaction loop is supposed to
work and how it is supposed to relate to the interaction with other
domains, scripts, etc.

Indeed it seems to me like your arrangements in libxl__device_disk_add
couldn't work if a non-null t was supplied.  libxl__device_disk_add
would do all the writes in the transaction, but not commit it, so that
none of them are visible to anyone, and then wait for the deivde state
to change, which will never happen.


>  static void libxl__device_disk_from_xs_be(libxl__gc *gc,
> @@ -1982,11 +1999,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
>      ret = 0;
> 
>      libxl_device_disk_remove(ctx, domid, disks + i, 0);
> -    libxl_device_disk_add(ctx, domid, disk);
> +    /* fixme-ao */
> +    libxl_device_disk_add(ctx, domid, disk, 0);
>      stubdomid = libxl_get_stubdom_id(ctx, domid);
>      if (stubdomid) {
>          libxl_device_disk_remove(ctx, stubdomid, disks + i, 0);
> -        libxl_device_disk_add(ctx, stubdomid, disk);
> +        /* fixme-ao */
> +        libxl_device_disk_add(ctx, stubdomid, disk, 0);

I think this code is a symptom of a problem elsewhere.  When adding a
disk to a domain, it should not be necessary to explicitly ask to add
it to the stubdom too.  But this is not your fault, or your problem
right now.


Thanks,
Ian.

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-14 12:21 ` [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
@ 2012-06-22 11:37   ` Ian Jackson
  2012-06-22 12:01     ` Ian Campbell
  2012-06-26 16:17     ` Roger Pau Monne
  0 siblings, 2 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:37 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Campbell, xen-devel

Roger Pau Monne writes ("[PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
> This patch converts libxl_device_nic_add to an ao operation that
> waits for device backend to reach state XenbusStateInitWait and then
> marks the operation as completed. This is not really useful now, but
> will be used by latter patches that will launch hotplug scripts after
> we reached the desired xenbus state.
> 
> Calls to libxl_device_nic_add have also been moved to occur after the
> device model has been launched, so when hotplug scripts are called
> from this functions the interfaces already exists.
> 
> As usual, libxl_device_nic_add callers have been modified, and the
> internal function libxl__device_disk_add has been used if the call was
> inside an already running ao.

This all looks reasonable to me.  But seeing this:

> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
> index 5d34ed5..f7217aa 100644
> --- a/tools/libxl/libxl_device.c
> +++ b/tools/libxl/libxl_device.c
> @@ -454,8 +454,8 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>  #define libxl__device_disk_add(egc, domid, disk, aodev)                       \
>          libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)
> 
> -#define DEFINE_DEVICES_ADD(type)                                              \
> -    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
> +#define DEFINE_DEVICES_ADD(type, name)                                        \
> +    void libxl__add_##name##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
>                                libxl_domain_config *d_config,                  \
>                                libxl__ao_devices *aodevs,                      \
>                                libxl__devices_callback *callback)              \
> @@ -469,12 +469,13 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>                                                                                \
>          for (i = 0; i < aodevs->size; i++) {                                  \
>              aodevs->array[i].callback = libxl__ao_devices_callback;           \
> -            libxl__device_##type##_add(egc, domid, &d_config->type##s[i],     \
> +            libxl__device_##name##_add(egc, domid, &d_config->type##s[i],     \
>                                         &aodevs->array[i]);                    \
>          }                                                                     \
>      }
> 
> -DEFINE_DEVICES_ADD(disk)
> +DEFINE_DEVICES_ADD(disk, disk)
> +DEFINE_DEVICES_ADD(vif, nic)

it seems to me that this is an anomaly which might be better fixed
than worked around.

Should we rename the functions libxl_*nic* or the structures *vif* ?
Or should we rename both, to "net" perhaps ?


In any case,

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

Ian.

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

* Re: [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU
  2012-06-14 12:21 ` [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU Roger Pau Monne
@ 2012-06-22 11:39   ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:39 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU"):
> This change will avoid the confusion caused by the fact that IOEMU
> means both PV and TAP network interfaces.

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

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-14 12:21 ` [PATCH v6 10/13] libxl: set nic type to VIF by default Roger Pau Monne
@ 2012-06-22 11:40   ` Ian Jackson
  2012-06-26 16:20     ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:40 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> Set the default value for nic interfaces to VIF, since it used to be
> IOEMU, even for PV guests.

If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
HVM guests getting emulated network interfaces by default ?

Ian.

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

* Re: [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl
  2012-06-14 12:21 ` [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
@ 2012-06-22 11:43   ` Ian Jackson
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:43 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl"):
> Since most of the needed work is already done in previous patches,
> this patch only contains the necessary code to call hotplug scripts
> for disk devices, that should be called when the device is added or
> removed from a guest.

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

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

* Re: [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages]
  2012-06-07 14:48       ` Ian Jackson
  2012-06-11 14:34         ` Roger Pau Monne
@ 2012-06-22 11:47         ` Ian Jackson
  2012-06-26  8:57           ` Roger Pau Monne
  1 sibling, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-22 11:47 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("[PATCH v6 13/13] libxl: call hotplug scripts for nic devices from libxl"):
> Since most of the needed work is already done in previous patches,
> this patch only contains the necessary code to call hotplug scripts
> for nic devices, that should be called when the device is added or
> removed from a guest.

Thanks.

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

However, AFAICT you missed this comment of mine:
> Roger Pau Monne writes ("[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl"):
> > +int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
> > +{
> ...
> > +    }
> > +
> > +out:
> > +    return rc;
> > +}
> > +
> 
> As a matter of good practice I think you should say
>       rc = 0;
> just before out, on the success path, and not rely on it having
> happened to be set to 0 by the previous successful call.

So IWBNI in the next version you did that too.

Thanks,
Ian.

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-22 11:37   ` Ian Jackson
@ 2012-06-22 12:01     ` Ian Campbell
  2012-06-26 16:17     ` Roger Pau Monne
  1 sibling, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-06-22 12:01 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Roger Pau Monne

On Fri, 2012-06-22 at 12:37 +0100, Ian Jackson wrote:
> 
> > -DEFINE_DEVICES_ADD(disk)
> > +DEFINE_DEVICES_ADD(disk, disk)
> > +DEFINE_DEVICES_ADD(vif, nic)
> 
> it seems to me that this is an anomaly which might be better fixed
> than worked around.
> 
> Should we rename the functions libxl_*nic* or the structures *vif* ?
> Or should we rename both, to "net" perhaps ?

If its a simple sed then I guess libxl_device_nic* is the answer -- but
if it turns into another yakk shaving exercise then perhaps we can just
live with it how it is.

libxl_device_net would also have been acceptable but doesn't seem as
analogous to libxl_device_disk to me and would have involved changing
both halves.

I don't like libxl_device_vif -- that's more an implementation thing --
cf. the TYOE_IOEMU vs TYPE_VIF conversation...

Ian.

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

* Re: [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages]
  2012-06-22 11:47         ` [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages] Ian Jackson
@ 2012-06-26  8:57           ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26  8:57 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 13/13] libxl: call hotplug scripts for nic devices from libxl"):
>> Since most of the needed work is already done in previous patches,
>> this patch only contains the necessary code to call hotplug scripts
>> for nic devices, that should be called when the device is added or
>> removed from a guest.
>
> Thanks.
>
> Acked-by: Ian Jackson<ian.jackson@eu.citrix.com>
>
> However, AFAICT you missed this comment of mine:
>> Roger Pau Monne writes ("[PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl"):
>>> +int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
>>> +{
>> ...
>>> +    }
>>> +
>>> +out:
>>> +    return rc;
>>> +}
>>> +
>> As a matter of good practice I think you should say
>>        rc = 0;
>> just before out, on the success path, and not rely on it having
>> happened to be set to 0 by the previous successful call.
>
> So IWBNI in the next version you did that too.

Sorry, I will add that and the acked-by on the next repost.

> Thanks,
> Ian.

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

* Re: [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op
  2012-06-21 17:58   ` Ian Jackson
@ 2012-06-26 10:27     ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26 10:27 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op"):
>> This will be needed in future patches, when libxl__device_disk_add
>> becomes async also. Create a new status structure that defines the
>> local attach of a disk device and use it in
>> libxl__device_disk_local_attach.
>
> This is looking good.  I have a couple of comments:

Thanks for the review!

>
>> diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c
>> index 7ebc0df..182a975 100644
>> --- a/tools/libxl/libxl_bootloader.c
>> +++ b/tools/libxl/libxl_bootloader.c
> ...
>> +static void bootloader_fisnihed_cb(libxl__egc *egc,
>                            ^^^^^^^^
> `finished'.  You have apparently managed to misspell this everywhere
> you mention it!

Probably copy-pasted it wrong everywhere, fixed.

>> +                                   libxl__disk_local_state *dls,
>> +                                   int rc);
>> +
>>   static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
>>                                   int rc)
>>   {
>>       bootloader_cleanup(egc, bl);
>> +
>> +    if (bl->diskpath) {
>> +        bl->dls.callback = bootloader_fisnihed_cb;
>> +        libxl__device_disk_local_detach(egc,&bl->dls);
>> +        return;
>> +    }
>
> Can we make libxl__device_disk_local_detach idempotent (and perhaps
> call it `libxl__device_disk_local_attached_initiate_cleanup' or
> something, if you can think of a name that's less than a paragraph) ?

I'm not sure the "attached" in the name is correct, because the device 
might have failed to attach, and still we are going to call this 
function. How about "libxl__device_disk_local_initiate_detach"? (still 
quite long). Then the attach function should be renamed to 
libxl__device_disk_local_initiate_attach.

> If so then this would be simpler and wouldn't need to test
> bl->diskpath.

Ok, I've moved the test for bl->dls.diskpath to 
libxl__device_disk_local_detach, so we have a more linear flow of callbacks.

>
>> +static void bootloader_disk_attached_cb(libxl__egc *egc,
>> +                                        libxl__disk_local_state *dls,
>> +                                        int rc)
> ...
>> +    bl->diskpath = bl->dls.diskpath;
>
> Now that we have a bl->dls.diskpath, surely we can do away with
> bl->diskpath ?  I'm not a fan of having multiple variables with the
> same information in them, unless it's essential.  It just leads to
> confusion and error.

Done.

>> +/*
>> + * Make a disk available in this (the control) domain. Calls dls->callback
>> + * when finished.
>> + */
>> +_hidden void libxl__device_disk_local_attach(libxl__egc *egc,
>> +                                             libxl__disk_local_state *dls);
>> +_hidden void libxl__device_disk_local_detach(libxl__egc *egc,
>> +                                             libxl__disk_local_state *dls);
>
> You really need to explain the rules for one of these dls's.
>
> Is it something like this:
>
>       * A libxl__disk_local_state may be in the following states:
>       *    Undefined, Idle, Attaching, Attached, Detaching

Ok, I've added the init function and the description of what this 
functions do, together with the rename it should be a little bit more clear.

>      typedef void libxl__disk_local_state_callback(libxl__egc*,
>                                                    libxl__disk_local_state*,
>                                                    int rc);
>
>     _hidden void libxl__device_disk_local_attach(libxl__egc *egc,
>                                                  libxl__disk_local_state *dls);
>         /* Undefined/Idle ->  Attaching.  Will call callback.
>          * On entry to callback, if rc!=0 dls is Idle;
>          * if rc==0 it is Attached and dls->diskpath is usable. */
>
>     _hidden void libxl__device_disk_local_detach(libxl__egc *egc,
>                                                  libxl__disk_local_state *dls);
>         /* Attached ->  Detaching.  Will call callback.
>          * On entry to callback, dls is Idle, regardless of
>          * success or failure. */
>
> And my suggestion about idempotency would change this latter comment
> to:
>         /* Idle/Attached ->  Detaching.  Will call callback.
>          * On entry to callback, dls is Idle, regardless of
>          * success or failure. */
>
> And the bootloader code might want this:
>
>     _hidden void libxl__device_disk_local_init(libxl__disk_local_state *dls);
>         /* Undefined/Idle ->  Idle */
>
> Or you can explain it in prose if you like.
>
> Ian.

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

* Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-22 11:33   ` Ian Jackson
@ 2012-06-26 15:04     ` Roger Pau Monne
  2012-06-26 15:14       ` Roger Pau Monne
  2012-06-26 17:19       ` Ian Jackson
  0 siblings, 2 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26 15:04 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op"):
>> This patch converts libxl_device_disk_add to an ao operation that
>> waits for device backend to reach state XenbusStateInitWait and then
>> marks the operation as completed. This is not really useful now, but
>> will be used by latter patches that will launch hotplug scripts after
>                    ^^^^^^
> later

Thanks

>> we reached the desired xenbus state.
>
> Thanks, here are my review comments:
>
>
>> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
>> index 85c21b4..937ab08 100644
>> --- a/tools/libxl/libxl_internal.h
>> +++ b/tools/libxl/libxl_internal.h
> ...
>> +/* AO operation to connect a disk device, called by
>> + * libxl_device_disk_add and libxl__add_disks. This function calls
>> + * libxl__initiate_device_connection to wait for the device to
>> + * finish the connection (might involve executing hotplug scripts).
>> + */
>> +_hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid,
>> +                                    xs_transaction_t t,
>> +                                    libxl_device_disk *disk,
>> +                                    libxl__ao_device *aodev);
>> +
>
> This is a confusing doc comment.  The reader doesn't want to know how
> the function is implemented; we need to know what it does.
> Particularly, we need to know what happens when it completes.  I infer
> that it calls aodev->callback but this should be stated.

Yes, fixed comment.

>> +/* Waits for the passed device to reach state XenbusStateInitWait.
>> + * This is not really useful by itself, but is important when executing
>> + * hotplug scripts, since we need to be sure the device is in the correct
>> + * state before executing them.
>> + *
>> + * Once finished, aodev->callback will be executed.
>> + */
>> +_hidden void libxl__initiate_device_connection(libxl__egc*,
>> +                                               libxl__ao_device *aodev);
>
> This function's name and its functionality seem not to correspond.  It
> doesn't actually initiate anything, as far as I can tell.

I've renamed it to libxl__wait_device_connection

>>   /* First layer; wraps libxl__spawn_spawn. */
>> @@ -2033,6 +2068,8 @@ typedef struct {
>>       libxl__domain_build_state dm_state;
>>       libxl__dm_spawn_state pvqemu;
>>       libxl__destroy_domid_state dis;
>> +    /* used to store the state of devices being connected */
>> +    libxl__ao_devices aodevs;
>>   } libxl__stub_dm_spawn_state;
>
> I'm not sure how valuable these comments are.  libxl__ao_devices are
> always used to store the state of devices being "<something>'d".
> That's what a libxl__ao_devices is for.  And in the context of a spawn
> or create that would obviously be "connected".
>
> In general I'm a fan of comments which say things which aren't clear
> from the code, but I'm not keen on ones which restate what the code
> says.

I've removed both occurrences of this comment.

>
>> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
>> index 9243806..5d34ed5 100644
>> --- a/tools/libxl/libxl_device.c
>> +++ b/tools/libxl/libxl_device.c
>> @@ -442,6 +442,45 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>>       return;
>>   }
>>
>> +/******************************************************************************/
>> +
>> +/* Macro for defining the functions that will add a bunch of disks when
>> + * inside an async op.
>> + *
>> + * This macro is added to prevent repetition of code.
>> + */
>> +
>> +/* Capatibility macro, since disk_add now takes a xs transaction parameter */
>> +#define libxl__device_disk_add(egc, domid, disk, aodev)                       \
>> +        libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)
>
> Is it really safe to call libxl__device_disk_add without a real
> transaction ?  I see that the current code does it but it seems wrong
> to me.  We end up writing all of the individual settings in the
> backend one at a time.

Well, this is not really my code, this was part of Stefanos series about 
local disk attach. However, I don't see how we end up writing them one 
at a time, libxl__device_generic_add creates a transaction if none is 
given, so all backend and frontend entries are added at the same 
transaction. Calling libxl__device_disk_add without a transaction 
behaves just like it did previously.

> I think this applies to all the other device types too.  So I think
> the right answer would be to make them take a transaction parameter
> too.  Ie, insert a patch before this one which adds a transaction
> parameter (ignored for now and always passed 0 if you don't want to
> actually make it work properly) to libxl__add_nic etc.  Then you don't
> need this unpleasant macro.

Ok, I will add this patch that makes all device_*_add take a transaction 
parameter, although it will be ignored right now.

>> +void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
>> +{
>> +    STATE_AO_GC(aodev->ao);
>> +    char *be_path = libxl__device_backend_path(gc, aodev->dev);
>> +    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
>> +    int rc = 0;
> ...
>> +out_fail:
>> +    assert(rc);
>> +    aodev->rc = rc;
>> +    device_xsentries_remove(egc, aodev);
>> +    return;
>> +}
>
> Firstly, I'm not convinced it's really proper for
> libxl__initiate_device_connection to call device_xsentries_remove.
> After all device_xsentries_remove is part of the implementation of
> libxl__initiate_device_remove.

This is part of both flows, both device connection and disconnection.

> And, secondly, does device_xsentries_remove really do what you want ?
> It has a test in it which makes it only do its work if action is
> DISCONNECT.

Yes, that's because it's called by both flows.

>
>> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
>> index 43affd1..5f09740 100644
>> --- a/tools/libxl/libxl.c
>> +++ b/tools/libxl/libxl.c
>
>
>> @@ -2027,15 +2046,17 @@ static char * libxl__alloc_vdev(libxl__gc *gc, const char *blkdev_start,
>
>> +                dls->t = xs_transaction_start(ctx->xsh);
>> +                if (dls->t == XBT_NULL) {
>> +                    LOG(ERROR, "failed to start a xenstore transaction");
>> +                    rc = ERROR_FAIL;
>> +                    goto out;
>> +                }
>> +                disk->vdev = libxl__alloc_vdev(gc, blkdev_start, dls->t);
> ...
>> +                libxl__device_disk_add(egc, LIBXL_TOOLSTACK_DOMID,
>> +                                       dls->t, disk,&dls->aodev);
> ...
>> +    xs_ret = xs_transaction_end(ctx->xsh, dls->t, 0);
>> +    if (xs_ret == 0&&  errno == EAGAIN) {
>> +        libxl__device_disk_local_attach(egc, dls);
>> +        return;
>
> Isn't the effect of this that if the xs transaction gets a conflict,
> we'll rerun the hotplug scripts, etc. ?  I think I may be confused
> here, but I don't understand how this transaction loop is supposed to
> work and how it is supposed to relate to the interaction with other
> domains, scripts, etc.

Yes I see your point. We should disconnect the device (execute hotplug 
scripts) but since the xenstore entries are already gone (because the 
transaction is not committed successfully) I don't see anyway to do it, 
we cannot execute those scripts if the backend entries have been lost.

> Indeed it seems to me like your arrangements in libxl__device_disk_add
> couldn't work if a non-null t was supplied.  libxl__device_disk_add
> would do all the writes in the transaction, but not commit it, so that
> none of them are visible to anyone, and then wait for the deivde state
> to change, which will never happen.

I'm not so sure, is it possible to add a watch to a xenstore path that 
is inside of a not yet committed transaction? If so this will work fine, 
the transaction will be finished correctly, and the path will be updated 
to the correct state (2).

If the transaction is not committed successfully, we will get a timeout 
from the devstate event and exit.

>
>>   static void libxl__device_disk_from_xs_be(libxl__gc *gc,
>> @@ -1982,11 +1999,13 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
>>       ret = 0;
>>
>>       libxl_device_disk_remove(ctx, domid, disks + i, 0);
>> -    libxl_device_disk_add(ctx, domid, disk);
>> +    /* fixme-ao */
>> +    libxl_device_disk_add(ctx, domid, disk, 0);
>>       stubdomid = libxl_get_stubdom_id(ctx, domid);
>>       if (stubdomid) {
>>           libxl_device_disk_remove(ctx, stubdomid, disks + i, 0);
>> -        libxl_device_disk_add(ctx, stubdomid, disk);
>> +        /* fixme-ao */
>> +        libxl_device_disk_add(ctx, stubdomid, disk, 0);
>
> I think this code is a symptom of a problem elsewhere.  When adding a
> disk to a domain, it should not be necessary to explicitly ask to add
> it to the stubdom too.  But this is not your fault, or your problem
> right now.

So I assume we can leave this for later.

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

* Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-26 15:04     ` Roger Pau Monne
@ 2012-06-26 15:14       ` Roger Pau Monne
  2012-06-26 17:19       ` Ian Jackson
  1 sibling, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26 15:14 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Roger Pau Monne wrote:
>> Isn't the effect of this that if the xs transaction gets a conflict,
>> we'll rerun the hotplug scripts, etc. ?  I think I may be confused
>> here, but I don't understand how this transaction loop is supposed to
>> work and how it is supposed to relate to the interaction with other
>> domains, scripts, etc.
>
> Yes I see your point. We should disconnect the device (execute hotplug
> scripts) but since the xenstore entries are already gone (because the
> transaction is not committed successfully) I don't see anyway to do it,
> we cannot execute those scripts if the backend entries have been lost.

Sorry, I've made a mistake here, since the transaction is not committed, 
we never reach the desired state (2), so if the transaction fails no 
scripts are executed, and we can carry on trying to add the device again.

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-22 11:37   ` Ian Jackson
  2012-06-22 12:01     ` Ian Campbell
@ 2012-06-26 16:17     ` Roger Pau Monne
  2012-06-26 17:22       ` Ian Jackson
  1 sibling, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26 16:17 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Ian Campbell, xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
>> This patch converts libxl_device_nic_add to an ao operation that
>> waits for device backend to reach state XenbusStateInitWait and then
>> marks the operation as completed. This is not really useful now, but
>> will be used by latter patches that will launch hotplug scripts after
>> we reached the desired xenbus state.
>>
>> Calls to libxl_device_nic_add have also been moved to occur after the
>> device model has been launched, so when hotplug scripts are called
>> from this functions the interfaces already exists.
>>
>> As usual, libxl_device_nic_add callers have been modified, and the
>> internal function libxl__device_disk_add has been used if the call was
>> inside an already running ao.
>
> This all looks reasonable to me.  But seeing this:
>
>> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
>> index 5d34ed5..f7217aa 100644
>> --- a/tools/libxl/libxl_device.c
>> +++ b/tools/libxl/libxl_device.c
>> @@ -454,8 +454,8 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>>   #define libxl__device_disk_add(egc, domid, disk, aodev)                       \
>>           libxl__device_disk_add(egc, domid, XBT_NULL, disk, aodev)
>>
>> -#define DEFINE_DEVICES_ADD(type)                                              \
>> -    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
>> +#define DEFINE_DEVICES_ADD(type, name)                                        \
>> +    void libxl__add_##name##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
>>                                 libxl_domain_config *d_config,                  \
>>                                 libxl__ao_devices *aodevs,                      \
>>                                 libxl__devices_callback *callback)              \
>> @@ -469,12 +469,13 @@ void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
>>                                                                                 \
>>           for (i = 0; i<  aodevs->size; i++) {                                  \
>>               aodevs->array[i].callback = libxl__ao_devices_callback;           \
>> -            libxl__device_##type##_add(egc, domid,&d_config->type##s[i],     \
>> +            libxl__device_##name##_add(egc, domid,&d_config->type##s[i],     \
>>                                          &aodevs->array[i]);                    \
>>           }                                                                     \
>>       }
>>
>> -DEFINE_DEVICES_ADD(disk)
>> +DEFINE_DEVICES_ADD(disk, disk)
>> +DEFINE_DEVICES_ADD(vif, nic)
>
> it seems to me that this is an anomaly which might be better fixed
> than worked around.
>
> Should we rename the functions libxl_*nic* or the structures *vif* ?
> Or should we rename both, to "net" perhaps ?

I think we should either rename the strucutres to nic also (because the 
also hold ioemu cards), or get rid of nic/vif an name everything net.

>
> In any case,
>
> Acked-by: Ian Jackson<ian.jackson@eu.citrix.com>
>
> Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-22 11:40   ` Ian Jackson
@ 2012-06-26 16:20     ` Roger Pau Monne
  2012-06-26 16:58       ` Pasi Kärkkäinen
  2012-06-26 17:22       ` Ian Jackson
  0 siblings, 2 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-26 16:20 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
>> Set the default value for nic interfaces to VIF, since it used to be
>> IOEMU, even for PV guests.
>
> If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> HVM guests getting emulated network interfaces by default ?

Yes, if you want emulated interfaces with HVM guests you should use 
'type=ioemu', that's how it has always been right?

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-26 16:20     ` Roger Pau Monne
@ 2012-06-26 16:58       ` Pasi Kärkkäinen
  2012-06-27  8:50         ` Ian Campbell
  2012-06-26 17:22       ` Ian Jackson
  1 sibling, 1 reply; 84+ messages in thread
From: Pasi Kärkkäinen @ 2012-06-26 16:58 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
> Ian Jackson wrote:
> >Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> >>Set the default value for nic interfaces to VIF, since it used to be
> >>IOEMU, even for PV guests.
> >
> >If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> >HVM guests getting emulated network interfaces by default ?
> 
> Yes, if you want emulated interfaces with HVM guests you should use
> 'type=ioemu', that's how it has always been right?
> 

With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
(at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..

Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers

"NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM drivers WILL NOT work! Don't specify "type" parameter for the vif. (with type=ioemu the pvhvm nic in the VM will have mac address full of zeroes - and thus won't work!). "


-- Pasi

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

* Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-26 15:04     ` Roger Pau Monne
  2012-06-26 15:14       ` Roger Pau Monne
@ 2012-06-26 17:19       ` Ian Jackson
  2012-06-27 17:35         ` Roger Pau Monne
  1 sibling, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-26 17:19 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op"):
> Ian Jackson wrote:
> > Roger Pau Monne writes ("[PATCH v6 06/13] libxl: convert libxl_device_disk_a
> > Is it really safe to call libxl__device_disk_add without a real
> > transaction ?  I see that the current code does it but it seems wrong
> > to me.  We end up writing all of the individual settings in the
> > backend one at a time.
> 
> Well, this is not really my code, this was part of Stefanos series about 
> local disk attach. However, I don't see how we end up writing them one 
> at a time, libxl__device_generic_add creates a transaction if none is 
> given, so all backend and frontend entries are added at the same 
> transaction. Calling libxl__device_disk_add without a transaction 
> behaves just like it did previously.

Oh, right, that's OK then.  Sorry for missing that.

> > I think this applies to all the other device types too.  So I think
> > the right answer would be to make them take a transaction parameter
> > too.  Ie, insert a patch before this one which adds a transaction
> > parameter (ignored for now and always passed 0 if you don't want to
> > actually make it work properly) to libxl__add_nic etc.  Then you don't
> > need this unpleasant macro.
> 
> Ok, I will add this patch that makes all device_*_add take a transaction 
> parameter, although it will be ignored right now.

Right.  (You could pass it through to device_generic_add if that was
easy.)

> >> +void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
> >> +{
> >> +    STATE_AO_GC(aodev->ao);
> >> +    char *be_path = libxl__device_backend_path(gc, aodev->dev);
> >> +    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
> >> +    int rc = 0;
> > ...
> >> +out_fail:
> >> +    assert(rc);
> >> +    aodev->rc = rc;
> >> +    device_xsentries_remove(egc, aodev);
> >> +    return;
> >> +}
> >
> > Firstly, I'm not convinced it's really proper for
> > libxl__initiate_device_connection to call device_xsentries_remove.
> > After all device_xsentries_remove is part of the implementation of
> > libxl__initiate_device_remove.
> 
> This is part of both flows, both device connection and disconnection.

Well then it should have a proper description and a better name,
perhaps ?  As it is it looks like you're doing what amounts to "goto"
from one "function" to another - only we don't notice it like that
because it's split into multiple ao callbacks.

> > And, secondly, does device_xsentries_remove really do what you want ?
> > It has a test in it which makes it only do its work if action is
> > DISCONNECT.
> 
> Yes, that's because it's called by both flows.

If it is called in the connect flow, won't it be a no-op then ?
Perhaps I'm being excessively dense here.


> > Isn't the effect of this that if the xs transaction gets a conflict,
> > we'll rerun the hotplug scripts, etc. ?  I think I may be confused
> > here, but I don't understand how this transaction loop is supposed to
> > work and how it is supposed to relate to the interaction with other
> > domains, scripts, etc.
> 
> Yes I see your point. We should disconnect the device (execute hotplug 
> scripts) but since the xenstore entries are already gone (because the 
> transaction is not committed successfully) I don't see anyway to do it, 
> we cannot execute those scripts if the backend entries have been lost.
> 
> > Indeed it seems to me like your arrangements in libxl__device_disk_add
> > couldn't work if a non-null t was supplied.  libxl__device_disk_add
> > would do all the writes in the transaction, but not commit it, so that
> > none of them are visible to anyone, and then wait for the deivde state
> > to change, which will never happen.
> 
> I'm not so sure, is it possible to add a watch to a xenstore path that 
> is inside of a not yet committed transaction? If so this will work fine, 
> the transaction will be finished correctly, and the path will be updated 
> to the correct state (2).

AIUI you can add a watch for any path that you like - the path you ask
to watch doesn't have to exist.  But you won't (necessarily) see
events for uncommitted transactions.

> If the transaction is not committed successfully, we will get a timeout 
> from the devstate event and exit.

I think that the only way all this could work is if you firstly, in
one transaction, create enough of the backend for the hotplug scripts
to run, and then in a second transaction create the rest of the
backend plus the frontend.

> > I think this code is a symptom of a problem elsewhere.  When adding a
> > disk to a domain, it should not be necessary to explicitly ask to add
> > it to the stubdom too.  But this is not your fault, or your problem
> > right now.
> 
> So I assume we can leave this for later.

Yes.

Thanks,
Ian.

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-26 16:17     ` Roger Pau Monne
@ 2012-06-26 17:22       ` Ian Jackson
  2012-06-28  9:53         ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-06-26 17:22 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Campbell, xen-devel

Roger Pau Monne writes ("Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
> Ian Jackson wrote:
> > Should we rename the functions libxl_*nic* or the structures *vif* ?
> > Or should we rename both, to "net" perhaps ?
> 
> I think we should either rename the strucutres to nic also (because the 
> also hold ioemu cards), or get rid of nic/vif an name everything net.

Can you try to rename everything to `net' and see if that turns out to
be an impenetrable yak ?

Thanks,
Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-26 16:20     ` Roger Pau Monne
  2012-06-26 16:58       ` Pasi Kärkkäinen
@ 2012-06-26 17:22       ` Ian Jackson
  1 sibling, 0 replies; 84+ messages in thread
From: Ian Jackson @ 2012-06-26 17:22 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

Roger Pau Monne writes ("Re: [PATCH v6 10/13] libxl: set nic type to VIF by default"):
> Ian Jackson wrote:
> > Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> >> Set the default value for nic interfaces to VIF, since it used to be
> >> IOEMU, even for PV guests.
> >
> > If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> > HVM guests getting emulated network interfaces by default ?
> 
> Yes, if you want emulated interfaces with HVM guests you should use 
> 'type=ioemu', that's how it has always been right?

AIUI the current code doesn't require that.  Certainly looking at your
patch it appears that the existing default is VIF_IOEMU.

Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-26 16:58       ` Pasi Kärkkäinen
@ 2012-06-27  8:50         ` Ian Campbell
  2012-06-28  9:22           ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Campbell @ 2012-06-27  8:50 UTC (permalink / raw)
  To: Pasi Kärkkäinen; +Cc: xen-devel, Ian Jackson, Roger Pau Monne

On Tue, 2012-06-26 at 17:58 +0100, Pasi Kärkkäinen wrote:
> On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
> > Ian Jackson wrote:
> > >Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> > >>Set the default value for nic interfaces to VIF, since it used to be
> > >>IOEMU, even for PV guests.
> > >
> > >If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> > >HVM guests getting emulated network interfaces by default ?
> > 
> > Yes, if you want emulated interfaces with HVM guests you should use
> > 'type=ioemu', that's how it has always been right?
> > 
> 
> With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
> (at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..
> 
> Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers
> 
> "NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM
> drivers WILL NOT work! Don't specify "type" parameter for the vif.
> (with type=ioemu the pvhvm nic in the VM will have mac address full of
> zeroes - and thus won't work!). "

mac=00:00:00:00:00 is certainly a bug, if (lib)xl behaves this way too
then we should fix it.

But surely type=ioemu is supposed to mean "only emulated"? In which case
the actual xend bug is that it created a PV VIF at all.

What are the options here? I think they are, with their (lib)xl
behaviour:

		PV				HVM
type=ioemu	meaningless / an error		emulated device + paravirt VIF*
type=vif	paravirt VIF device*&		paravirt VIF device only&

Where * == current lib(xl) default and & == proposed default after this change.
and:
        type=ioemu =>	LIBXL_NIC_TYPE_IOEMU to be renamed LIBXL_NIC_TYPE_VIF_IOEMU.
        type=vif =>	LIBXL_NIV_TYPE_VIF, no renaming proposed.
        
But if my table is correct then LIBXL_NIC_TYPE_VIF_IOEMU is the right
default and shouldn't be changed. Roger can you either confirm or
correct my table.

Ian.


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

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

* Re: [PATCH v6 06/13] libxl: convert libxl_device_disk_add to an async op
  2012-06-26 17:19       ` Ian Jackson
@ 2012-06-27 17:35         ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-27 17:35 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel

Ian Jackson wrote:
>>>> +void libxl__initiate_device_connection(libxl__egc *egc, libxl__ao_device *aodev)
>>>> +{
>>>> +    STATE_AO_GC(aodev->ao);
>>>> +    char *be_path = libxl__device_backend_path(gc, aodev->dev);
>>>> +    char *state_path = libxl__sprintf(gc, "%s/state", be_path);
>>>> +    int rc = 0;
>>> ...
>>>> +out_fail:
>>>> +    assert(rc);
>>>> +    aodev->rc = rc;
>>>> +    device_xsentries_remove(egc, aodev);
>>>> +    return;
>>>> +}
>>> Firstly, I'm not convinced it's really proper for
>>> libxl__initiate_device_connection to call device_xsentries_remove.
>>> After all device_xsentries_remove is part of the implementation of
>>> libxl__initiate_device_remove.
>> This is part of both flows, both device connection and disconnection.
>
> Well then it should have a proper description and a better name,
> perhaps ?

This functions is latter renamed to "device_hotplug_done", which is the 
point where the callback is done. Since this name is only going to be 
there for like two commits, can we leave it like that?

> As it is it looks like you're doing what amounts to "goto"
> from one "function" to another - only we don't notice it like that
> because it's split into multiple ao callbacks.

Yes, that's mainly one of the consequences of having the same exit point 
for all the possible scenarios. Almost every iteration of this series 
has been adding more of this stuff.

>>> And, secondly, does device_xsentries_remove really do what you want ?
>>> It has a test in it which makes it only do its work if action is
>>> DISCONNECT.
>> Yes, that's because it's called by both flows.
>
> If it is called in the connect flow, won't it be a no-op then ?
> Perhaps I'm being excessively dense here.

It is a no-op here, but in latter patches it becomes the exit point for 
the device addition/removal flow, once it is renamed to device_hotplug_done.

>
>>> Isn't the effect of this that if the xs transaction gets a conflict,
>>> we'll rerun the hotplug scripts, etc. ?  I think I may be confused
>>> here, but I don't understand how this transaction loop is supposed to
>>> work and how it is supposed to relate to the interaction with other
>>> domains, scripts, etc.
>> Yes I see your point. We should disconnect the device (execute hotplug
>> scripts) but since the xenstore entries are already gone (because the
>> transaction is not committed successfully) I don't see anyway to do it,
>> we cannot execute those scripts if the backend entries have been lost.
>>
>>> Indeed it seems to me like your arrangements in libxl__device_disk_add
>>> couldn't work if a non-null t was supplied.  libxl__device_disk_add
>>> would do all the writes in the transaction, but not commit it, so that
>>> none of them are visible to anyone, and then wait for the deivde state
>>> to change, which will never happen.
>> I'm not so sure, is it possible to add a watch to a xenstore path that
>> is inside of a not yet committed transaction? If so this will work fine,
>> the transaction will be finished correctly, and the path will be updated
>> to the correct state (2).
>
> AIUI you can add a watch for any path that you like - the path you ask
> to watch doesn't have to exist.  But you won't (necessarily) see
> events for uncommitted transactions.

Yes, but then we will hit a timeout if the transaction is not actually 
committed.

>> If the transaction is not committed successfully, we will get a timeout
>> from the devstate event and exit.
>
> I think that the only way all this could work is if you firstly, in
> one transaction, create enough of the backend for the hotplug scripts
> to run, and then in a second transaction create the rest of the
> backend plus the frontend.

The hotplug scripts require the backend to be in state 2 (it requires 
that the kernel has initialized the device) so it needs to have a full 
backend set up.

>>> I think this code is a symptom of a problem elsewhere.  When adding a
>>> disk to a domain, it should not be necessary to explicitly ask to add
>>> it to the stubdom too.  But this is not your fault, or your problem
>>> right now.
>> So I assume we can leave this for later.
>
> Yes.
>
> Thanks,
> Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-27  8:50         ` Ian Campbell
@ 2012-06-28  9:22           ` Roger Pau Monne
  2012-06-28  9:26             ` Ian Campbell
  2012-06-28  9:28             ` Roger Pau Monne
  0 siblings, 2 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28  9:22 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Ian Campbell wrote:
> On Tue, 2012-06-26 at 17:58 +0100, Pasi Kärkkäinen wrote:
>> On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
>>> Ian Jackson wrote:
>>>> Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
>>>>> Set the default value for nic interfaces to VIF, since it used to be
>>>>> IOEMU, even for PV guests.
>>>> If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
>>>> HVM guests getting emulated network interfaces by default ?
>>> Yes, if you want emulated interfaces with HVM guests you should use
>>> 'type=ioemu', that's how it has always been right?
>>>
>> With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
>> (at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..
>>
>> Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers
>>
>> "NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM
>> drivers WILL NOT work! Don't specify "type" parameter for the vif.
>> (with type=ioemu the pvhvm nic in the VM will have mac address full of
>> zeroes - and thus won't work!). "
>
> mac=00:00:00:00:00 is certainly a bug, if (lib)xl behaves this way too
> then we should fix it.
>
> But surely type=ioemu is supposed to mean "only emulated"? In which case
> the actual xend bug is that it created a PV VIF at all.

Currently there's no network type that means "emulated only", we have 
VIF and VIF_IOEMU.

> What are the options here? I think they are, with their (lib)xl
> behaviour:
>
> 		PV				HVM
> type=ioemu	meaningless / an error		emulated device + paravirt VIF*
> type=vif	paravirt VIF device*&		paravirt VIF device only&

You are missing a row, the default one when user doesn't specify 
anything, this currently is:

	PV				HVM
default	nic type is set to IEOMU	nic type is set to IOEMU

In the past this was not a problem, since when the guest is PV, we 
didn't launch Qemu, and thus the tap device was never created and the 
hotplug scripts were not launched. Now that we launch hotplug scripts 
from libxl this is a problem, because when we call libxl_device_nic_add, 
libxl has no idea if the domain is a PV or HVM guest, and only sees the 
network type, which is set to IOEMU by default.

This is the main problem, I think it should be ok to leave the default 
type as IOEMU in libxl__device_nic_setdefault and set the type manually 
to VIF for PV guests in 
libxl_create.c:libxl__domain_build_info_setdefault, does this sound ok?

> Where * == current lib(xl) default and&  == proposed default after this change.
> and:
>          type=ioemu =>	LIBXL_NIC_TYPE_IOEMU to be renamed LIBXL_NIC_TYPE_VIF_IOEMU.
>          type=vif =>	LIBXL_NIV_TYPE_VIF, no renaming proposed.
>
> But if my table is correct then LIBXL_NIC_TYPE_VIF_IOEMU is the right
> default and shouldn't be changed. Roger can you either confirm or
> correct my table.
>
> Ian.
>


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

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28  9:22           ` Roger Pau Monne
@ 2012-06-28  9:26             ` Ian Campbell
  2012-06-28  9:41               ` Roger Pau Monne
  2012-06-28  9:28             ` Roger Pau Monne
  1 sibling, 1 reply; 84+ messages in thread
From: Ian Campbell @ 2012-06-28  9:26 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Thu, 2012-06-28 at 10:22 +0100, Roger Pau Monne wrote:
> Ian Campbell wrote:
> > On Tue, 2012-06-26 at 17:58 +0100, Pasi Kärkkäinen wrote:
> >> On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
> >>> Ian Jackson wrote:
> >>>> Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> >>>>> Set the default value for nic interfaces to VIF, since it used to be
> >>>>> IOEMU, even for PV guests.
> >>>> If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> >>>> HVM guests getting emulated network interfaces by default ?
> >>> Yes, if you want emulated interfaces with HVM guests you should use
> >>> 'type=ioemu', that's how it has always been right?
> >>>
> >> With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
> >> (at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..
> >>
> >> Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers
> >>
> >> "NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM
> >> drivers WILL NOT work! Don't specify "type" parameter for the vif.
> >> (with type=ioemu the pvhvm nic in the VM will have mac address full of
> >> zeroes - and thus won't work!). "
> >
> > mac=00:00:00:00:00 is certainly a bug, if (lib)xl behaves this way too
> > then we should fix it.
> >
> > But surely type=ioemu is supposed to mean "only emulated"? In which case
> > the actual xend bug is that it created a PV VIF at all.
> 
> Currently there's no network type that means "emulated only", we have 
> VIF and VIF_IOEMU.

Ah, ok, yes I'm confused.

> > What are the options here? I think they are, with their (lib)xl
> > behaviour:
> >
> > 		PV				HVM
> > type=ioemu	meaningless / an error		emulated device + paravirt VIF*
> > type=vif	paravirt VIF device*&		paravirt VIF device only&
> 
> You are missing a row, the default one when user doesn't specify 
> anything,

That was supposed to be indicated by the * (now) and & (after your
patch) symbols above.

>  this currently is:
> 
> 	PV				HVM
> default	nic type is set to IEOMU	nic type is set to IOEMU
> 
> In the past this was not a problem, since when the guest is PV, we 
> didn't launch Qemu, and thus the tap device was never created and the 
> hotplug scripts were not launched. Now that we launch hotplug scripts 
> from libxl this is a problem, because when we call libxl_device_nic_add, 
> libxl has no idea if the domain is a PV or HVM guest, and only sees the 
> network type, which is set to IOEMU by default.

It has a domid so it can ask and/or propagate it down to setdefaults.

> This is the main problem, I think it should be ok to leave the default 
> type as IOEMU in libxl__device_nic_setdefault and set the type manually 
> to VIF for PV guests in 
> libxl_create.c:libxl__domain_build_info_setdefault, does this sound ok?

Does buildinfo setdefault have the necessary pointer to get at the vifs?
I don't think it does.

> 
> > Where * == current lib(xl) default and&  == proposed default after this change.
> > and:
> >          type=ioemu =>	LIBXL_NIC_TYPE_IOEMU to be renamed LIBXL_NIC_TYPE_VIF_IOEMU.
> >          type=vif =>	LIBXL_NIV_TYPE_VIF, no renaming proposed.
> >
> > But if my table is correct then LIBXL_NIC_TYPE_VIF_IOEMU is the right
> > default and shouldn't be changed. Roger can you either confirm or
> > correct my table.
> >
> > Ian.
> >
> 



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

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28  9:22           ` Roger Pau Monne
  2012-06-28  9:26             ` Ian Campbell
@ 2012-06-28  9:28             ` Roger Pau Monne
  1 sibling, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28  9:28 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Roger Pau Monne wrote:
> In the past this was not a problem, since when the guest is PV, we
> didn't launch Qemu, and thus the tap device was never created and the
> hotplug scripts were not launched. Now that we launch hotplug scripts
> from libxl this is a problem, because when we call libxl_device_nic_add,
> libxl has no idea if the domain is a PV or HVM guest, and only sees the
> network type, which is set to IOEMU by default.
>
> This is the main problem, I think it should be ok to leave the default
> type as IOEMU in libxl__device_nic_setdefault and set the type manually
> to VIF for PV guests in
> libxl_create.c:libxl__domain_build_info_setdefault, does this sound ok?

My bad, libxl__domain_build_info_setdefault doesn't have access to
libxl_domain_config, I will search for another place...

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28  9:26             ` Ian Campbell
@ 2012-06-28  9:41               ` Roger Pau Monne
  2012-06-28  9:54                 ` Ian Campbell
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28  9:41 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Ian Campbell wrote:
> On Thu, 2012-06-28 at 10:22 +0100, Roger Pau Monne wrote:
>> Ian Campbell wrote:
>>> On Tue, 2012-06-26 at 17:58 +0100, Pasi Kärkkäinen wrote:
>>>> On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
>>>>> Ian Jackson wrote:
>>>>>> Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
>>>>>>> Set the default value for nic interfaces to VIF, since it used to be
>>>>>>> IOEMU, even for PV guests.
>>>>>> If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
>>>>>> HVM guests getting emulated network interfaces by default ?
>>>>> Yes, if you want emulated interfaces with HVM guests you should use
>>>>> 'type=ioemu', that's how it has always been right?
>>>>>
>>>> With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
>>>> (at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..
>>>>
>>>> Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers
>>>>
>>>> "NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM
>>>> drivers WILL NOT work! Don't specify "type" parameter for the vif.
>>>> (with type=ioemu the pvhvm nic in the VM will have mac address full of
>>>> zeroes - and thus won't work!). "
>>> mac=00:00:00:00:00 is certainly a bug, if (lib)xl behaves this way too
>>> then we should fix it.
>>>
>>> But surely type=ioemu is supposed to mean "only emulated"? In which case
>>> the actual xend bug is that it created a PV VIF at all.
>> Currently there's no network type that means "emulated only", we have
>> VIF and VIF_IOEMU.
>
> Ah, ok, yes I'm confused.
>
>>> What are the options here? I think they are, with their (lib)xl
>>> behaviour:
>>>
>>> 		PV				HVM
>>> type=ioemu	meaningless / an error		emulated device + paravirt VIF*
>>> type=vif	paravirt VIF device*&		paravirt VIF device only&
>> You are missing a row, the default one when user doesn't specify
>> anything,
>
> That was supposed to be indicated by the * (now) and&  (after your
> patch) symbols above.
>
>>   this currently is:
>>
>> 	PV				HVM
>> default	nic type is set to IEOMU	nic type is set to IOEMU
>>
>> In the past this was not a problem, since when the guest is PV, we
>> didn't launch Qemu, and thus the tap device was never created and the
>> hotplug scripts were not launched. Now that we launch hotplug scripts
>> from libxl this is a problem, because when we call libxl_device_nic_add,
>> libxl has no idea if the domain is a PV or HVM guest, and only sees the
>> network type, which is set to IOEMU by default.
>
> It has a domid so it can ask and/or propagate it down to setdefaults.

I think the most suitable place is 
libxl_create.c:initiate_domain_create, which also sets the defaults for 
disk devices, so I think it's adequate to place something like:

if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV) {
     for (i = 0; i < d_config->num_vifs; i++) {
         d_config->vifs[i].nictype = LIBXL_NIC_TYPE_VIF;
     }
}


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

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-26 17:22       ` Ian Jackson
@ 2012-06-28  9:53         ` Roger Pau Monne
  2012-06-28  9:56           ` Ian Campbell
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28  9:53 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Ian Campbell, xen-devel

Ian Jackson wrote:
> Roger Pau Monne writes ("Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
>> Ian Jackson wrote:
>>> Should we rename the functions libxl_*nic* or the structures *vif* ?
>>> Or should we rename both, to "net" perhaps ?
>> I think we should either rename the strucutres to nic also (because the
>> also hold ioemu cards), or get rid of nic/vif an name everything net.
>
> Can you try to rename everything to `net' and see if that turns out to
> be an impenetrable yak ?

I think it is much more easy to rename everything to nic, which provides 
the same level of abstraction from my PoV. Renaming everything to net 
it's a rather very big change. Would you be ok with that change?

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28  9:41               ` Roger Pau Monne
@ 2012-06-28  9:54                 ` Ian Campbell
  2012-06-28 10:07                   ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Campbell @ 2012-06-28  9:54 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Thu, 2012-06-28 at 10:41 +0100, Roger Pau Monne wrote:
> Ian Campbell wrote:
> > On Thu, 2012-06-28 at 10:22 +0100, Roger Pau Monne wrote:
> >> Ian Campbell wrote:
> >>> On Tue, 2012-06-26 at 17:58 +0100, Pasi Kärkkäinen wrote:
> >>>> On Tue, Jun 26, 2012 at 05:20:35PM +0100, Roger Pau Monne wrote:
> >>>>> Ian Jackson wrote:
> >>>>>> Roger Pau Monne writes ("[PATCH v6 10/13] libxl: set nic type to VIF by default"):
> >>>>>>> Set the default value for nic interfaces to VIF, since it used to be
> >>>>>>> IOEMU, even for PV guests.
> >>>>>> If your renaming of IOEMU to VIF_IOEMU is correct, does this not stop
> >>>>>> HVM guests getting emulated network interfaces by default ?
> >>>>> Yes, if you want emulated interfaces with HVM guests you should use
> >>>>> 'type=ioemu', that's how it has always been right?
> >>>>>
> >>>> With Xen 4.1 you don't have to use "type=ioemu". Emulated interfaces seem to work OK without "type=ioemu".
> >>>> (at least with xm/xend). And if you actually do add "type=ioemu" it will break PVHVM for Linux guests..
> >>>>
> >>>> Quote from: http://wiki.xen.org/wiki/XenLinuxPVonHVMdrivers
> >>>>
> >>>> "NOTE! If you have "type=ioemu" specified for the "vif"-line, PVHVM
> >>>> drivers WILL NOT work! Don't specify "type" parameter for the vif.
> >>>> (with type=ioemu the pvhvm nic in the VM will have mac address full of
> >>>> zeroes - and thus won't work!). "
> >>> mac=00:00:00:00:00 is certainly a bug, if (lib)xl behaves this way too
> >>> then we should fix it.
> >>>
> >>> But surely type=ioemu is supposed to mean "only emulated"? In which case
> >>> the actual xend bug is that it created a PV VIF at all.
> >> Currently there's no network type that means "emulated only", we have
> >> VIF and VIF_IOEMU.
> >
> > Ah, ok, yes I'm confused.
> >
> >>> What are the options here? I think they are, with their (lib)xl
> >>> behaviour:
> >>>
> >>> 		PV				HVM
> >>> type=ioemu	meaningless / an error		emulated device + paravirt VIF*
> >>> type=vif	paravirt VIF device*&		paravirt VIF device only&
> >> You are missing a row, the default one when user doesn't specify
> >> anything,
> >
> > That was supposed to be indicated by the * (now) and&  (after your
> > patch) symbols above.
> >
> >>   this currently is:
> >>
> >> 	PV				HVM
> >> default	nic type is set to IEOMU	nic type is set to IOEMU
> >>
> >> In the past this was not a problem, since when the guest is PV, we
> >> didn't launch Qemu, and thus the tap device was never created and the
> >> hotplug scripts were not launched. Now that we launch hotplug scripts
> >> from libxl this is a problem, because when we call libxl_device_nic_add,
> >> libxl has no idea if the domain is a PV or HVM guest, and only sees the
> >> network type, which is set to IOEMU by default.
> >
> > It has a domid so it can ask and/or propagate it down to setdefaults.
> 
> I think the most suitable place is 
> libxl_create.c:initiate_domain_create, which also sets the defaults for 
> disk devices, 

.. by calling setdefaults though.

I'd like to keep all such logic in setdefaults as far as possible.

libxl__devic_nic_setdefautls is an internal function so we can add
either a domid or type parameter quite easily. Are there any callsites
which would be unable to provide one or the other of those?

Probably domid is best, with setdefaults calling libxl__domain_type as
necessary.

> so I think it's adequate to place something like:
> 
> if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV) {
>      for (i = 0; i < d_config->num_vifs; i++) {
>          d_config->vifs[i].nictype = LIBXL_NIC_TYPE_VIF;
>      }
> }
> 



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

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-28  9:53         ` Roger Pau Monne
@ 2012-06-28  9:56           ` Ian Campbell
  2012-06-28 13:30             ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Campbell @ 2012-06-28  9:56 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Thu, 2012-06-28 at 10:53 +0100, Roger Pau Monne wrote:
> Ian Jackson wrote:
> > Roger Pau Monne writes ("Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
> >> Ian Jackson wrote:
> >>> Should we rename the functions libxl_*nic* or the structures *vif* ?
> >>> Or should we rename both, to "net" perhaps ?
> >> I think we should either rename the strucutres to nic also (because the
> >> also hold ioemu cards), or get rid of nic/vif an name everything net.
> >
> > Can you try to rename everything to `net' and see if that turns out to
> > be an impenetrable yak ?
> 
> I think it is much more easy to rename everything to nic, which provides 
> the same level of abstraction from my PoV. Renaming everything to net 
> it's a rather very big change. Would you be ok with that change?

I'd be happy with nic, I think it fits better with libxl_device_disk
anyway. (if it were libxl_device_net would be more analogous to
libxl_device_storage or something)

Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28  9:54                 ` Ian Campbell
@ 2012-06-28 10:07                   ` Roger Pau Monne
  2012-06-28 10:10                     ` Ian Campbell
  0 siblings, 1 reply; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28 10:07 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Ian Campbell wrote:
> On Thu, 2012-06-28 at 10:41 +0100, Roger Pau Monne wrote:
>> I think the most suitable place is
>> libxl_create.c:initiate_domain_create, which also sets the defaults for
>> disk devices,
>
> .. by calling setdefaults though.

Yes, sorry.

>
> I'd like to keep all such logic in setdefaults as far as possible.
>
> libxl__devic_nic_setdefautls is an internal function so we can add
> either a domid or type parameter quite easily. Are there any callsites
> which would be unable to provide one or the other of those?
>
> Probably domid is best, with setdefaults calling libxl__domain_type as
> necessary.

I think it would be appropriate to pass domid to every setdefault 
function, even if it's only used by nic now:

libxl__device_disk_setdefault
libxl__device_nic_setdefault
libxl__device_vfb_setdefault
libxl__device_vkb_setdefault
libxl__device_pci_setdefault

To keep the symmetry, are you ok with that?

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28 10:07                   ` Roger Pau Monne
@ 2012-06-28 10:10                     ` Ian Campbell
  2012-06-28 13:29                       ` Roger Pau Monne
  0 siblings, 1 reply; 84+ messages in thread
From: Ian Campbell @ 2012-06-28 10:10 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Thu, 2012-06-28 at 11:07 +0100, Roger Pau Monne wrote:
> Ian Campbell wrote:
> > On Thu, 2012-06-28 at 10:41 +0100, Roger Pau Monne wrote:
> >> I think the most suitable place is
> >> libxl_create.c:initiate_domain_create, which also sets the defaults for
> >> disk devices,
> >
> > .. by calling setdefaults though.
> 
> Yes, sorry.
> 
> >
> > I'd like to keep all such logic in setdefaults as far as possible.
> >
> > libxl__devic_nic_setdefautls is an internal function so we can add
> > either a domid or type parameter quite easily. Are there any callsites
> > which would be unable to provide one or the other of those?
> >
> > Probably domid is best, with setdefaults calling libxl__domain_type as
> > necessary.
> 
> I think it would be appropriate to pass domid to every setdefault 
> function, even if it's only used by nic now:
> 
> libxl__device_disk_setdefault
> libxl__device_nic_setdefault
> libxl__device_vfb_setdefault
> libxl__device_vkb_setdefault
> libxl__device_pci_setdefault
> 
> To keep the symmetry, are you ok with that?

Lets make that cleanup in 4.3 and just do the necessary for 4.2.

Ian.

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

* Re: [PATCH v6 10/13] libxl: set nic type to VIF by default
  2012-06-28 10:10                     ` Ian Campbell
@ 2012-06-28 13:29                       ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28 13:29 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Ian Campbell wrote:
> On Thu, 2012-06-28 at 11:07 +0100, Roger Pau Monne wrote:
>> Ian Campbell wrote:
>>> On Thu, 2012-06-28 at 10:41 +0100, Roger Pau Monne wrote:
>>>> I think the most suitable place is
>>>> libxl_create.c:initiate_domain_create, which also sets the defaults for
>>>> disk devices,
>>> .. by calling setdefaults though.
>> Yes, sorry.
>>
>>> I'd like to keep all such logic in setdefaults as far as possible.
>>>
>>> libxl__devic_nic_setdefautls is an internal function so we can add
>>> either a domid or type parameter quite easily. Are there any callsites
>>> which would be unable to provide one or the other of those?
>>>
>>> Probably domid is best, with setdefaults calling libxl__domain_type as
>>> necessary.
>> I think it would be appropriate to pass domid to every setdefault
>> function, even if it's only used by nic now:
>>
>> libxl__device_disk_setdefault
>> libxl__device_nic_setdefault
>> libxl__device_vfb_setdefault
>> libxl__device_vkb_setdefault
>> libxl__device_pci_setdefault
>>
>> To keep the symmetry, are you ok with that?
>
> Lets make that cleanup in 4.3 and just do the necessary for 4.2.

Ok, I've just changed libxl__device_nic_setdefault to take a domid 
parameter.

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

* Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation
  2012-06-28  9:56           ` Ian Campbell
@ 2012-06-28 13:30             ` Roger Pau Monne
  0 siblings, 0 replies; 84+ messages in thread
From: Roger Pau Monne @ 2012-06-28 13:30 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Ian Jackson, xen-devel

Ian Campbell wrote:
> On Thu, 2012-06-28 at 10:53 +0100, Roger Pau Monne wrote:
>> Ian Jackson wrote:
>>> Roger Pau Monne writes ("Re: [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation"):
>>>> Ian Jackson wrote:
>>>>> Should we rename the functions libxl_*nic* or the structures *vif* ?
>>>>> Or should we rename both, to "net" perhaps ?
>>>> I think we should either rename the strucutres to nic also (because the
>>>> also hold ioemu cards), or get rid of nic/vif an name everything net.
>>> Can you try to rename everything to `net' and see if that turns out to
>>> be an impenetrable yak ?
>> I think it is much more easy to rename everything to nic, which provides
>> the same level of abstraction from my PoV. Renaming everything to net
>> it's a rather very big change. Would you be ok with that change?
>
> I'd be happy with nic, I think it fits better with libxl_device_disk
> anyway. (if it were libxl_device_net would be more analogous to
> libxl_device_storage or something)

Done, I've added a pre-patch to rename every *vif* to nic.

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

* Re: [PATCH v6 00/13] execute hotplug scripts from libxl
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (12 preceding siblings ...)
  2012-06-14 12:21 ` [PATCH v6 13/13] libxl: call hotplug scripts for nic " Roger Pau Monne
@ 2012-07-03  8:27 ` Ian Campbell
  2012-07-03  9:19 ` Ian Campbell
  14 siblings, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03  8:27 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: xen-devel

On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
...

I'm afraid that something in this series appears to break stub-dm
support.

It looks like you need to add code to
libxl__domain_create_info_setdefault to set cinfo->run_hotplug_scripts
to a specific default.

        quartz:~# gdb --args xl -vvv cr -F /etc/xen/debian-HVM-1 
        [...]
        Reading symbols from /usr/sbin/xl...done.
        (gdb) r
        Starting program: /usr/sbin/xl -vvv cr -F /etc/xen/debian-HVM-1
        [Thread debugging using libthread_db enabled]
        Parsing config from /etc/xen/debian-HVM-1
        libxl: debug: libxl_create.c:1135:do_domain_create: ao 0x806a088: create: how=(nil) callback=(nil) poller=0x8069728
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=hda spec.backend=unknown
        libxl: debug: libxl_device.c:289:libxl__device_disk_set_backend: Disk vdev=hda, using backend phy
        libxl: debug: libxl_create.c:665:initiate_domain_create: running bootloader
        libxl: debug: libxl_bootloader.c:324:libxl__bootloader_run: not a PV domain, skipping bootloader
        libxl: debug: libxl_event.c:561:libxl__ev_xswatch_deregister: watch w=0x806a278: deregister unregistered
        xc: detail: elf_parse_binary: phdr: paddr=0x100000 memsz=0x9bca4
        xc: detail: elf_parse_binary: memory: 0x100000 -> 0x19bca4
        xc: info: VIRTUAL MEMORY ARRANGEMENT:
          Loader:        0000000000100000->000000000019bca4
          TOTAL:         0000000000000000->0000000007800000
          ENTRY ADDRESS: 0000000000100000
        xc: info: PHYSICAL MEMORY ALLOCATION:
          4KB PAGES: 0x0000000000000200
          2MB PAGES: 0x000000000000003b
          1GB PAGES: 0x0000000000000000
        xc: detail: elf_load_binary: phdr 0 at 0x0xb7cc7000 -> 0x0xb7d59b14
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=hda spec.backend=phy
        libxl: debug: libxl_event.c:512:libxl__ev_xswatch_register: watch w=0x806af2c wpath=/local/domain/0/backend/vbd/10/768/state token=3/0: register slotnum=3
        [New Thread 0xb7fddb70 (LWP 5177)]
        libxl: debug: libxl_create.c:1148:do_domain_create: ao 0x806a088: inprogress: poller=0x8069728, flags=i
        libxl: debug: libxl_event.c:457:watchfd_callback: watch w=0x806af2c wpath=/local/domain/0/backend/vbd/10/768/state token=3/0: event epath=/local/domain/0/backend/vbd/10/768/state
        libxl: debug: libxl_event.c:596:devstate_watch_callback: backend /local/domain/0/backend/vbd/10/768/state wanted state 2 ok
        libxl: debug: libxl_event.c:549:libxl__ev_xswatch_deregister: watch w=0x806af2c wpath=/local/domain/0/backend/vbd/10/768/state token=3/0: deregister slotnum=3
        libxl: debug: libxl_event.c:561:libxl__ev_xswatch_deregister: watch w=0x806af2c: deregister unregistered
        libxl: debug: libxl_device.c:806:device_hotplug: calling hotplug script: /etc/xen/scripts/block add
        libxl: debug: libxl_event.c:426:watchfd_callback: watch epath=/local/domain/0/backend/vbd/10/768/state token=3/0: empty slot
        xl: libxl.c:252: libxl_defbool_val: Assertion `!libxl_defbool_is_default(db)' failed.
        
        Program received signal SIGABRT, Aborted.
        0xff7fe424 in __kernel_vsyscall ()
        (gdb) bt
        #0  0xff7fe424 in __kernel_vsyscall ()
        #1  0xb7e1d781 in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
        #2  0xb7e20bb2 in *__GI_abort () at abort.c:92
        #3  0xb7e168e8 in *__GI___assert_fail (
            assertion=0xb7fbe96c "!libxl_defbool_is_default(db)", file=0xb7fbe54c "libxl.c", 
            line=252, function=0xb7fc06a3 "libxl_defbool_val") at assert.c:81
        #4  0xb7f8d121 in libxl_defbool_val (db=...) at libxl.c:252
        #5  0xb7f9709e in libxl__domain_make (gc=0x806a098, info=0x806a3d4, domid=0x806a618)
            at libxl_create.c:518
        #6  0xb7f9aa85 in libxl__spawn_stub_dm (egc=0xbffff39c, sdss=0x806a358) at libxl_dm.c:782
        #7  0xb7f96493 in domcreate_launch_dm (egc=0xbffff39c, aodevs=0x806a750, rc=0)
            at libxl_create.c:956
        #8  0xb7fa5a27 in libxl__ao_devices_callback (egc=0xbffff39c, aodev=0x806af08)
            at libxl_device.c:464
        #9  0xb7fa69c7 in device_hotplug_done (egc=<value optimized out>, aodev=0x806af08)
            at libxl_device.c:900
        #10 0xb7fa6c85 in device_hotplug (egc=<value optimized out>, aodev=0x806af08)
            at libxl_device.c:829
        #11 0xb7fa6d0a in device_hotplug_child_death_cb (egc=0xbffff39c, child=0x806af80, 
            pid=5180, status=0) at libxl_device.c:870
        #12 0xb7fb45db in childproc_reaped (egc=0xbffff39c, pid=6, status=0) at libxl_fork.c:264
        #13 0xb7fb4c57 in libxl__fork_selfpipe_woken (egc=0xbffff39c) at libxl_fork.c:300
        #14 0xb7fb122c in afterpoll_internal (egc=0xbffff39c, poller=<value optimized out>, 
            nfds=3, fds=0x8071198, now=...) at libxl_event.c:901
        #15 0xb7fb1edb in eventloop_iteration (egc=<value optimized out>, poller=0x8069728)
            at libxl_event.c:1305
        #16 0xb7fb254f in libxl__ao_inprogress (ao=0x806a088, file=0xb7fc0a27 "libxl_create.c", 
            line=1148, func=0xb7fc0c80 "do_domain_create") at libxl_event.c:1551
        #17 0xb7f9877b in do_domain_create (ctx=<value optimized out>, 
            d_config=<value optimized out>, domid=0x8067f34, restore_fd=-1, ao_how=0x0, 
            aop_console_how=0x0) at libxl_create.c:1148
        #18 0xb7f98877 in libxl_domain_create_new (ctx=0x8069030, d_config=0xbffff5a8, 
            domid=0x8067f34, ao_how=0x0, aop_console_how=0x0) at libxl_create.c:1169
        #19 0x080538d2 in create_domain (dom_info=<value optimized out>) at xl_cmdimpl.c:1796
        #20 0x0805ce8f in main_create (argc=3, argv=0xbffffd2c) at xl_cmdimpl.c:3761
        #21 0x0804d1be in main (argc=5, argv=0xbffffd24) at xl.c:267

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

* Re: [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts
  2012-06-14 12:21 ` [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
@ 2012-07-03  8:33   ` Ian Campbell
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03  8:33 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
> @@ -70,6 +71,9 @@ static void parse_global_config(const char *configfile,
>      if (!xlu_cfg_get_long (config, "autoballoon", &l, 0))
>          autoballoon = l;
>  
> +    libxl_defbool_setdefault(&run_hotplug_scripts, true);
> +    xlu_cfg_get_defbool(config, "run_hotplug_scripts", &run_hotplug_scripts, 0);


>      if (!xlu_cfg_get_string (config, "lockfile", &buf, 0))
>          lockfile = strdup(buf);
>      else {
> diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
> index 59556b5..fddaecb 100644
> --- a/tools/libxl/xl.h
> +++ b/tools/libxl/xl.h
> @@ -140,6 +140,7 @@ int xl_child_pid(xlchildnum); /* returns 0 if child struct is not in use */
>  
>  /* global options */
>  extern int autoballoon;
> +extern libxl_defbool run_hotplug_scripts;
>  extern int dryrun_only;
>  extern char *lockfile;
>  extern char *default_vifscript;
> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
> index 404c9c2..fd980b1 100644
> --- a/tools/libxl/xl_cmdimpl.c
> +++ b/tools/libxl/xl_cmdimpl.c
> @@ -594,6 +594,7 @@ static void parse_config_data(const char *config_source,
>          }
>      }
>  
> +    c_info->run_hotplug_scripts = run_hotplug_scripts;

This should be libxl_defbool_set(&c_info->...., run_hotplug_scripts)
where the run_hotplug_script can be a plain boolean and doesn't need to
be a defbool. Since the variable is contained within xl we don't need a
separate specific "default" value.

You also need a call to libxl_defbool_setdefault in
libxl__domain_create_info_setdefault to handle toolstacks which do not
have an opinion. This is the cause of the stubdom failure I reported
before.

You might also want to propagate the value from the main domain to the
stubdom PV domain, Actually I assume you'll need this because the user
needs to be able to configure both with the same key.

>      c_info->type = LIBXL_DOMAIN_TYPE_PV;
>      if (!xlu_cfg_get_string (config, "builder", &buf, 0) &&
>          !strncmp(buf, "hvm", strlen(buf)))

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

* Re: [PATCH v6 00/13] execute hotplug scripts from libxl
  2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
                   ` (13 preceding siblings ...)
  2012-07-03  8:27 ` [PATCH v6 00/13] execute hotplug scripts from libxl Ian Campbell
@ 2012-07-03  9:19 ` Ian Campbell
  2012-07-03  9:26   ` Ian Campbell
  2012-07-03 12:54   ` Ian Jackson
  14 siblings, 2 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03  9:19 UTC (permalink / raw)
  To: Roger Pau Monne, Ian Jackson; +Cc: xen-devel

On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
...

It seems that the error handling when the bootloader fails is broken by
this change. Actually I think it was broken before (seemed to blindly
plunge on, Ian J CCd) but now it just hangs.

Before this series a failed bootloader invocation would be:
        # xl -vvv cr /tmp/di-test.cfg 
        Parsing config from /tmp/di-test.cfg
        xl: acquire lock
        xl: acquire lock rc=0
        libxl: debug: libxl_create.c:1025:do_domain_create: ao 0x8069d80: create: how=(nil) callback=(nil) poller=0x8069dc0
        libxl: debug: libxl_device.c:188:libxl__device_disk_set_backend: Disk vdev=xvdd spec.backend=unknown
        libxl: debug: libxl_device.c:142:disk_try_backend: Disk vdev=xvdd, backend phy unsuitable as phys path not a block device
        libxl: debug: libxl_device.c:149:disk_try_backend: Disk vdev=xvdd, backend tap unsuitable because blktap not available
        libxl: debug: libxl_device.c:224:libxl__device_disk_set_backend: Disk vdev=xvdd, using backend qdisk
        libxl: debug: libxl_device.c:188:libxl__device_disk_set_backend: Disk vdev=xvda spec.backend=unknown
        libxl: debug: libxl_device.c:224:libxl__device_disk_set_backend: Disk vdev=xvda, using backend phy
        libxl: debug: libxl_create.c:625:initiate_domain_create: running bootloader
        libxl: debug: libxl_device.c:188:libxl__device_disk_set_backend: Disk vdev=(null) spec.backend=qdisk
        libxl: debug: libxl.c:2061:libxl__device_disk_local_attach: locally attaching qdisk /scratch/di-test.iso
        libxl: debug: libxl_bootloader.c:354:libxl__bootloader_run: Config bootloader value: pygrub
        libxl: debug: libxl_bootloader.c:370:libxl__bootloader_run: Checking for bootloader in libexec path: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_create.c:1038:do_domain_create: ao 0x8069d80: inprogress: poller=0x8069dc0, flags=i
        libxl: debug: libxl_event.c:512:libxl__ev_xswatch_register: watch w=0x8069ef8 wpath=/local/domain/27 token=3/0: register slotnum=3
        libxl: debug: libxl_event.c:1604:libxl__ao_progress_report: ao 0x8069d80: progress report: ignored
        libxl: debug: libxl_bootloader.c:478:bootloader_gotptys: executing bootloader: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: --args=debian-installer/exit/always_halt=true -- console=hvc0 hostname=di-test domain=uk.xensource.com auto-install/enable=true url=http://cosworth.uk.xensource.com/users/ianc/ks/wheezy.cfg base-installer/kernel/image=linux-image-686-pae
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: --output=/var/run/xen/bootloader.27.out
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: --output-format=simple0
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: --output-directory=/var/run/xen/bootloader.27.d
        libxl: debug: libxl_bootloader.c:482:bootloader_gotptys:   bootloader arg: /scratch/di-test.iso
        libxl: debug: libxl_event.c:457:watchfd_callback: watch w=0x8069ef8 wpath=/local/domain/27 token=3/0: event epath=/local/domain/27
        libxl: error: libxl_bootloader.c:557:bootloader_finished: bootloader failed - consult logfile /var/log/xen/bootloader.27.log
        libxl: error: libxl_exec.c:118:libxl_report_child_exitstatus: bootloader [7754] exited with error status 1
        libxl: debug: libxl_event.c:549:libxl__ev_xswatch_deregister: watch w=0x8069ef8 wpath=/local/domain/27 token=3/0: deregister slotnum=3
        libxl: error: libxl_create.c:851:domcreate_rebuild_done: cannot (re-)build domain: -3
        libxl: debug: libxl_event.c:1434:libxl__ao_complete: ao 0x8069d80: complete, rc=-3
        libxl: error: libxl.c:3407:libxl_set_vcpuaffinity: setting vcpu affinity: No such process
        libxl: warning: libxl.c:3421:libxl_set_vcpuaffinity_all: failed to set affinity for 0
        xc: error: do_evtchn_op: HYPERVISOR_event_channel_op failed: -1: Internal error
        xc: error: do_evtchn_op: HYPERVISOR_event_channel_op failed: -1: Internal error
        domainbuilder: detail: xc_dom_allocate: cmdline="(null)", features="(null)"
        libxl: debug: libxl_dom.c:256:libxl__build_pv: pv kernel mapped 0 path (null)
        
        domainbuilder: detail: xc_dom_kernel_file: filename="(null)"
        libxl: error: libxl_dom.c:268:libxl__build_pv: xc_dom_kernel_file failed: Bad address
        domainbuilder: detail: xc_dom_release: called
        xl: libxl_event.c:1427: libxl__ao_inprogress_gc: Assertion `!ao->complete' failed.
        Aborted

So it appears to blunder on and then fail for some other reason.

With this series applied instead I see:
        # xl -vvv cr /tmp/di-test.cfg 
        Parsing config from /tmp/di-test.cfg
        xl: acquire lock
        xl: acquire lock rc=0
        libxl: debug: libxl_create.c:1135:do_domain_create: ao 0x8069d80: create: how=(nil) callback=(nil) poller=0x8069dc0
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=xvdd spec.backend=unknown
        libxl: debug: libxl_device.c:207:disk_try_backend: Disk vdev=xvdd, backend phy unsuitable as phys path not a block device
        libxl: debug: libxl_device.c:214:disk_try_backend: Disk vdev=xvdd, backend tap unsuitable because blktap not available
        libxl: debug: libxl_device.c:289:libxl__device_disk_set_backend: Disk vdev=xvdd, using backend qdisk
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=xvda spec.backend=unknown
        libxl: debug: libxl_device.c:289:libxl__device_disk_set_backend: Disk vdev=xvda, using backend phy
        libxl: debug: libxl_create.c:665:initiate_domain_create: running bootloader
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=(null) spec.backend=qdisk
        libxl: debug: libxl.c:2224:libxl__device_disk_local_attach: locally attaching qdisk /scratch/di-test.iso
        libxl: debug: libxl_bootloader.c:413:bootloader_disk_attached_cb: Config bootloader value: pygrub
        libxl: debug: libxl_bootloader.c:429:bootloader_disk_attached_cb: Checking for bootloader in libexec path: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_create.c:1148:do_domain_create: ao 0x8069d80: inprogress: poller=0x8069dc0, flags=i
        libxl: debug: libxl_event.c:512:libxl__ev_xswatch_register: watch w=0x8069f98 wpath=/local/domain/30 token=3/0: register slotnum=3
        libxl: debug: libxl_event.c:1604:libxl__ao_progress_report: ao 0x8069d80: progress report: ignored
        libxl: debug: libxl_bootloader.c:549:bootloader_gotptys: executing bootloader: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --args=debian-installer/exit/always_halt=true -- console=hvc0 hostname=di-test domain=uk.xensource.com auto-install/enable=true url=http://cosworth.uk.xensource.com/users/ianc/ks/wheezy.cfg base-installer/kernel/image=linux-image-686-pae
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output=/var/run/xen/bootloader.30.out
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output-format=simple0
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output-directory=/var/run/xen/bootloader.30.d
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: /scratch/di-test.iso
        libxl: debug: libxl_event.c:457:watchfd_callback: watch w=0x8069f98 wpath=/local/domain/30 token=3/0: event epath=/local/domain/30
        libxl: error: libxl_bootloader.c:628:bootloader_finished: bootloader failed - consult logfile /var/log/xen/bootloader.30.log
        libxl: error: libxl_exec.c:118:libxl_report_child_exitstatus: bootloader [7783] exited with error status 1
        libxl: debug: libxl_event.c:549:libxl__ev_xswatch_deregister: watch w=0x8069f98 wpath=/local/domain/30 token=3/0: deregister slotnum=3
        <hang>

I suspect that if it didn't hang it would continue with the dodgy
behaviour above so I think both behaviours warrant investigation.

Ian.

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

* Re: [PATCH v6 00/13] execute hotplug scripts from libxl
  2012-07-03  9:19 ` Ian Campbell
@ 2012-07-03  9:26   ` Ian Campbell
  2012-07-03 12:54   ` Ian Jackson
  1 sibling, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03  9:26 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Ian Jackson, xen-devel

On Tue, 2012-07-03 at 10:19 +0100, Ian Campbell wrote:
> On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
> ...
> 
> It seems that the error handling when the bootloader fails is broken by
> this change. Actually I think it was broken before (seemed to blindly
> plunge on, Ian J CCd) but now it just hangs.

Actually it seems that with this series it hangs in much the same place
even on successful pygrub invocation:
        # xl -vvv cr /tmp/di-test.cfg 
        Parsing config from /tmp/di-test.cfg
        xl: acquire lock
        xl: acquire lock rc=0
        libxl: debug: libxl_create.c:1135:do_domain_create: ao 0x8069ee8: create: how=(nil) callback=(nil) poller=0x8069e50
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=xvdd spec.backend=unknown
        libxl: debug: libxl_device.c:207:disk_try_backend: Disk vdev=xvdd, backend phy unsuitable as phys path not a block device
        libxl: debug: libxl_device.c:214:disk_try_backend: Disk vdev=xvdd, backend tap unsuitable because blktap not available
        libxl: debug: libxl_device.c:289:libxl__device_disk_set_backend: Disk vdev=xvdd, using backend qdisk
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=xvda spec.backend=unknown
        libxl: debug: libxl_device.c:289:libxl__device_disk_set_backend: Disk vdev=xvda, using backend phy
        libxl: debug: libxl_create.c:665:initiate_domain_create: running bootloader
        libxl: debug: libxl_device.c:253:libxl__device_disk_set_backend: Disk vdev=(null) spec.backend=qdisk
        libxl: debug: libxl.c:2224:libxl__device_disk_local_attach: locally attaching qdisk /scratch/di-test.iso
        libxl: debug: libxl_bootloader.c:413:bootloader_disk_attached_cb: Config bootloader value: pygrub
        libxl: debug: libxl_bootloader.c:429:bootloader_disk_attached_cb: Checking for bootloader in libexec path: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_create.c:1148:do_domain_create: ao 0x8069ee8: inprogress: poller=0x8069e50, flags=i
        libxl: debug: libxl_event.c:512:libxl__ev_xswatch_register: watch w=0x806a0d8 wpath=/local/domain/33 token=3/0: register slotnum=3
        libxl: debug: libxl_event.c:1604:libxl__ao_progress_report: ao 0x8069ee8: progress report: ignored
        libxl: debug: libxl_bootloader.c:549:bootloader_gotptys: executing bootloader: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: /usr/lib/xen/bin/pygrub
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --args=debian-installer/exit/always_halt=true -- console=hvc0 hostname=di-test domain=uk.xensource.com auto-install/enable=true url=http://cosworth.uk.xensource.com/users/ianc/ks/wheezy.cfg base-installer/kernel/image=linux-image-686-pae
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output=/var/run/xen/bootloader.33.out
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output-format=simple0
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --output-directory=/var/run/xen/bootloader.33.d
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --kernel=/install.386/xen/vmlinuz
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: --ramdisk=/install.386/xen/initrd.gz
        libxl: debug: libxl_bootloader.c:553:bootloader_gotptys:   bootloader arg: /scratch/di-test.iso
        libxl: debug: libxl_event.c:457:watchfd_callback: watch w=0x806a0d8 wpath=/local/domain/33 token=3/0: event epath=/local/domain/33
        libxl: debug: libxl_bootloader.c:634:bootloader_finished: bootloader completed
        libxl: debug: libxl_bootloader.c:136:bootloader_result_command: bootloader output contained kernel /var/run/xen/bootloader.33.d/boot_kernel.IZtG8X
        libxl: debug: libxl_bootloader.c:136:bootloader_result_command: bootloader output contained ramdisk /var/run/xen/bootloader.33.d/boot_ramdisk.qb1WlL
        libxl: debug: libxl_bootloader.c:136:bootloader_result_command: bootloader output contained args debian-installer/exit/always_halt=true -- console=hvc0 hostname=di-test domain=uk.xensource.com auto-install/enable=true url=http://cosworth.uk.xensource.com/users/ianc/ks/wheezy.cfg base-installer/kernel/image=linux-image-686-pae
        libxl: debug: libxl_bootloader.c:647:bootloader_finished: bootloader execution successful
        libxl: debug: libxl_event.c:549:libxl__ev_xswatch_deregister: watch w=0x806a0d8 wpath=/local/domain/33 token=3/0: deregister slotnum=3
        <hang>

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

* Re: [PATCH v6 00/13] execute hotplug scripts from libxl
  2012-07-03  9:19 ` Ian Campbell
  2012-07-03  9:26   ` Ian Campbell
@ 2012-07-03 12:54   ` Ian Jackson
  2012-07-03 13:04     ` Ian Campbell
  1 sibling, 1 reply; 84+ messages in thread
From: Ian Jackson @ 2012-07-03 12:54 UTC (permalink / raw)
  To: Ian Campbell; +Cc: xen-devel, Roger Pau Monne

Ian Campbell writes ("Re: [Xen-devel] [PATCH v6 00/13] execute hotplug scripts from libxl"):
> On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
> ...
> 
> It seems that the error handling when the bootloader fails is broken by
> this change. Actually I think it was broken before (seemed to blindly
> plunge on, Ian J CCd) but now it just hangs.

The blindly plunging on seems to be my fault.  The patch below should
fix it I think.

Ian.

diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index a633227..6599335 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -671,7 +671,10 @@ static void domcreate_bootloader_done(libxl__egc *egc,
     libxl__srm_restore_autogen_callbacks *const callbacks =
         &dcs->shs.callbacks.restore.a;
 
-    if (rc) domcreate_rebuild_done(egc, dcs, rc);
+    if (rc) {
+        domcreate_rebuild_done(egc, dcs, rc);
+        return;
+    }
 
     /* consume bootloader outputs. state->pv_{kernel,ramdisk} have
      * been initialised by the bootloader already.

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

* Re: [PATCH v6 00/13] execute hotplug scripts from libxl
  2012-07-03 12:54   ` Ian Jackson
@ 2012-07-03 13:04     ` Ian Campbell
  0 siblings, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03 13:04 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Roger Pau Monne

On Tue, 2012-07-03 at 13:54 +0100, Ian Jackson wrote:
> Ian Campbell writes ("Re: [Xen-devel] [PATCH v6 00/13] execute hotplug scripts from libxl"):
> > On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
> > ...
> > 
> > It seems that the error handling when the bootloader fails is broken by
> > this change. Actually I think it was broken before (seemed to blindly
> > plunge on, Ian J CCd) but now it just hangs.
> 
> The blindly plunging on seems to be my fault.  The patch below should
> fix it I think.

Seems to do the trick for me:
Acked/Tested-by: Ian Campbell <ian.campbell@citrix.com>

> 
> Ian.
> 
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index a633227..6599335 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -671,7 +671,10 @@ static void domcreate_bootloader_done(libxl__egc *egc,
>      libxl__srm_restore_autogen_callbacks *const callbacks =
>          &dcs->shs.callbacks.restore.a;
>  
> -    if (rc) domcreate_rebuild_done(egc, dcs, rc);
> +    if (rc) {
> +        domcreate_rebuild_done(egc, dcs, rc);
> +        return;
> +    }
>  
>      /* consume bootloader outputs. state->pv_{kernel,ramdisk} have
>       * been initialised by the bootloader already.

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

* Re: [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op
  2012-06-14 12:21 ` [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op Roger Pau Monne
  2012-06-21 17:58   ` Ian Jackson
@ 2012-07-03 15:14   ` Ian Campbell
  1 sibling, 0 replies; 84+ messages in thread
From: Ian Campbell @ 2012-07-03 15:14 UTC (permalink / raw)
  To: Roger Pau Monne; +Cc: Stefano Stabellini, Ian Jackson, xen-devel

On Thu, 2012-06-14 at 13:21 +0100, Roger Pau Monne wrote:
> +void libxl__device_disk_local_detach(libxl__egc *egc,
> +                                     libxl__disk_local_state *dls)
>  {
> +    STATE_AO_GC(dls->ao);
>      int rc = 0;
> +    libxl_device_disk *disk = &dls->disk;
> +    libxl__device *device;
> +    libxl__ao_device *aodev = &dls->aodev;
> 
>      switch (disk->backend) {
>          case LIBXL_DISK_BACKEND_QDISK:
>              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, 0);
> +                GCNEW(device);
> +                rc = libxl__device_from_disk(gc, LIBXL_TOOLSTACK_DOMID,
> +                                             disk, device);
> +                if (rc != 0) goto out;
> +
> +                libxl__prepare_ao_device(ao, aodev);
> +                aodev->action = DEVICE_DISCONNECT;
> +                aodev->dev = device;
> +                aodev->callback = local_device_detach_cb;
> +                aodev->force = 0;
> +                libxl__initiate_device_remove(egc, aodev);
>              }

You need
		else 
			dls->callback(...)

here otherwise in the case where the qdisk attach just used the raw file
directly it hangs.

You might want to consolidate both this and the default/PHYSTYPE_PHY
case which follows into a single "nothing to do, call callback" path?

> -            break;
> +            return;
>          default:
>              /*
>               * Nothing to do for PHYSTYPE_PHY.
>               * For other device types assume that the blktap2 process is
>               * needed by the soon to be started domain and do nothing.
>               */
> -            break;
> +            dls->callback(egc, dls, rc);
> +            return;
>      }
> 
> +out:
> +    assert(rc);
> +    dls->callback(egc, dls, rc);
> +    return;
> +}
> 
> -    return rc;
> +static void local_device_detach_cb(libxl__egc *egc, libxl__ao_device *aodev)
> +{
> +    STATE_AO_GC(aodev->ao);
> +    libxl__disk_local_state *dls = CONTAINER_OF(aodev, *dls, aodev);
> +
> +    if (aodev->rc) {
> +        LOGE(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);
> +        goto out;
> +    }
> +
> +out:
> +    dls->callback(egc, dls, aodev->rc);
> +    return;
>  }
> 
>  /******************************************************************************/
> diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c
> index 7ebc0df..182a975 100644
> --- a/tools/libxl/libxl_bootloader.c
> +++ b/tools/libxl/libxl_bootloader.c
> @@ -224,11 +224,6 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
>      if (bl->outputpath) libxl__remove_file(gc, bl->outputpath);
>      if (bl->outputdir) libxl__remove_directory(gc, bl->outputdir);
> 
> -    if (bl->diskpath) {
> -        libxl__device_disk_local_detach(gc, &bl->localdisk);
> -        free(bl->diskpath);
> -        bl->diskpath = 0;
> -    }
>      libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
>      libxl__datacopier_kill(&bl->keystrokes);
>      libxl__datacopier_kill(&bl->display);
> @@ -249,10 +244,40 @@ static void bootloader_setpaths(libxl__gc *gc, libxl__bootloader_state *bl)
>      bl->outputpath = GCSPRINTF(XEN_RUN_DIR "/bootloader.%"PRIu32".out", domid);
>  }
> 
> +/* Callbacks */
> +
> +static void bootloader_fisnihed_cb(libxl__egc *egc,
> +                                   libxl__disk_local_state *dls,
> +                                   int rc);
> +
>  static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
>                                  int rc)
>  {
>      bootloader_cleanup(egc, bl);
> +
> +    if (bl->diskpath) {
> +        bl->dls.callback = bootloader_fisnihed_cb;
> +        libxl__device_disk_local_detach(egc, &bl->dls);
> +        return;
> +    }
> +
> +    bl->callback(egc, bl, rc);
> +}
> +
> +static void bootloader_fisnihed_cb(libxl__egc *egc,
> +                                   libxl__disk_local_state *dls,
> +                                   int rc)
> +{
> +    STATE_AO_GC(dls->ao);
> +    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
> +
> +    free(bl->diskpath);
> +    bl->diskpath = 0;
> +
> +    if (rc) {
> +        LOG(ERROR, "unable to detach locally attached disk");
> +    }
> +
>      bl->callback(egc, bl, rc);
>  }
> 
> @@ -275,6 +300,16 @@ static void bootloader_abort(libxl__egc *egc,
> 
>  /*----- main flow of control -----*/
> 
> +/* Callbacks */
> +
> +static void bootloader_disk_attached_cb(libxl__egc *egc,
> +                                        libxl__disk_local_state *dls,
> +                                        int rc);
> +
> +static void bootloader_disk_failed_cb(libxl__egc *egc,
> +                                      libxl__disk_local_state *dls,
> +                                      int rc);
> +
>  void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
>  {
>      STATE_AO_GC(bl->ao);
> @@ -282,7 +317,6 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
>      uint32_t domid = bl->domid;
>      char *logfile_tmp = NULL;
>      int rc, r;
> -    const char *bootloader;
> 
>      libxl__bootloader_init(bl);
> 
> @@ -344,13 +378,38 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
>          goto out;
>      }
> 
> -    bl->diskpath = libxl__device_disk_local_attach(gc, bl->disk, &bl->localdisk,
> -            info->blkdev_start);
> -    if (!bl->diskpath) {
> -        rc = ERROR_FAIL;
> -        goto out;
> +    bl->dls.ao = ao;
> +    bl->dls.in_disk = bl->disk;
> +    bl->dls.blkdev_start = info->blkdev_start;
> +    bl->dls.callback = bootloader_disk_attached_cb;
> +    libxl__device_disk_local_attach(egc, &bl->dls);
> +    return;
> +
> + out:
> +    assert(rc);
> + out_ok:
> +    free(logfile_tmp);
> +    bootloader_callback(egc, bl, rc);
> +}
> +
> +static void bootloader_disk_attached_cb(libxl__egc *egc,
> +                                        libxl__disk_local_state *dls,
> +                                        int rc)
> +{
> +    STATE_AO_GC(dls->ao);
> +    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
> +    const libxl_domain_build_info *info = bl->info;
> +    const char *bootloader;
> +
> +    if (rc) {
> +        LOG(ERROR, "failed to attach local disk for bootloader execution");
> +        dls->callback = bootloader_disk_failed_cb;
> +        libxl__device_disk_local_detach(egc, dls);
> +        return;
>      }
> 
> +    bl->diskpath = bl->dls.diskpath;
> +
>      LOG(DEBUG, "Config bootloader value: %s", info->u.pv.bootloader);
> 
>      if ( !strcmp(info->u.pv.bootloader, "/usr/bin/pygrub") )
> @@ -389,11 +448,23 @@ void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
> 
>   out:
>      assert(rc);
> - out_ok:
> -    free(logfile_tmp);
>      bootloader_callback(egc, bl, rc);
>  }
> 
> +static void bootloader_disk_failed_cb(libxl__egc *egc,
> +                                      libxl__disk_local_state *dls,
> +                                      int rc)
> +{
> +    STATE_AO_GC(dls->ao);
> +    libxl__bootloader_state *bl = CONTAINER_OF(dls, *bl, dls);
> +
> +    if (rc) {
> +        LOG(ERROR, "failed to detach locally attached disk");
> +    }
> +
> +    bootloader_callback(egc, bl, ERROR_FAIL);
> +}
> +
>  static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
>  {
>      libxl__bootloader_state *bl = CONTAINER_OF(op, *bl, openpty);
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 0000d6b..85c21b4 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1245,17 +1245,6 @@ _hidden int libxl__device_from_disk(libxl__gc *gc, uint32_t domid,
>  _hidden int libxl__device_disk_add(libxl__gc *gc, uint32_t domid,
>          xs_transaction_t t, libxl_device_disk *disk);
> 
> -/*
> - * Make a disk available in this (the control) domain. Returns path to
> - * a device.
> - */
> -_hidden char * libxl__device_disk_local_attach(libxl__gc *gc,
> -        const libxl_device_disk *in_disk,
> -        libxl_device_disk *new_disk,
> -        const char *blkdev_start);
> -_hidden int libxl__device_disk_local_detach(libxl__gc *gc,
> -        libxl_device_disk *disk);
> -
>  _hidden char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid);
> 
>  struct libxl__xen_console_reader {
> @@ -1775,6 +1764,35 @@ struct libxl__ao_devices {
>  _hidden void libxl__initiate_device_remove(libxl__egc *egc,
>                                             libxl__ao_device *aodev);
> 
> +/*----- local disk attach: attach a disk locally to run the bootloader -----*/
> +
> +typedef struct libxl__disk_local_state libxl__disk_local_state;
> +typedef void libxl__disk_local_state_callback(libxl__egc*,
> +                                              libxl__disk_local_state*,
> +                                              int rc);
> +
> +struct libxl__disk_local_state {
> +    /* filled by the user */
> +    libxl__ao *ao;
> +    const libxl_device_disk *in_disk;
> +    libxl_device_disk disk;
> +    const char *blkdev_start;
> +    libxl__disk_local_state_callback *callback;
> +    /* filled by libxl__device_disk_local_attach */
> +    char *diskpath;
> +    /* private for implementation of local detach */
> +    libxl__ao_device aodev;
> +};
> +
> +/*
> + * Make a disk available in this (the control) domain. Calls dls->callback
> + * when finished.
> + */
> +_hidden void libxl__device_disk_local_attach(libxl__egc *egc,
> +                                             libxl__disk_local_state *dls);
> +_hidden void libxl__device_disk_local_detach(libxl__egc *egc,
> +                                             libxl__disk_local_state *dls);
> +
>  /*----- datacopier: copies data from one fd to another -----*/
> 
>  typedef struct libxl__datacopier_state libxl__datacopier_state;
> @@ -1872,7 +1890,7 @@ struct libxl__bootloader_state {
>       * the caller using libxl__device_disk_local_detach, but only
>       * after the domain's kernel and initramfs have been loaded into
>       * memory and the file references disposed of. */
> -    libxl_device_disk localdisk;
> +    libxl__disk_local_state dls;
>      uint32_t domid;
>      /* outputs:
>       *  - caller must initialise kernel and ramdisk to point to file
> --
> 1.7.7.5 (Apple Git-26)
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

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

end of thread, other threads:[~2012-07-03 15:14 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-14 12:21 [PATCH v6 00/13] execute hotplug scripts from libxl Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 01/13] libxl: change ao_device_remove to ao_device Roger Pau Monne
2012-06-15 16:45   ` Ian Jackson
2012-06-18  8:58     ` Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 02/13] libxl: move device model creation prototypes Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 03/13] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
2012-06-21 17:34   ` Ian Jackson
2012-06-14 12:21 ` [PATCH v6 04/13] libxl: move bootloader data strucutres and prototypes Roger Pau Monne
2012-06-21 17:35   ` Ian Jackson
2012-06-14 12:21 ` [PATCH v6 05/13] libxl: convert libxl__device_disk_local_attach to an async op Roger Pau Monne
2012-06-21 17:58   ` Ian Jackson
2012-06-26 10:27     ` Roger Pau Monne
2012-07-03 15:14   ` Ian Campbell
2012-06-14 12:21 ` [PATCH v6 06/13] libxl: convert libxl_device_disk_add " Roger Pau Monne
2012-06-22 11:33   ` Ian Jackson
2012-06-26 15:04     ` Roger Pau Monne
2012-06-26 15:14       ` Roger Pau Monne
2012-06-26 17:19       ` Ian Jackson
2012-06-27 17:35         ` Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 07/13] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
2012-06-22 11:37   ` Ian Jackson
2012-06-22 12:01     ` Ian Campbell
2012-06-26 16:17     ` Roger Pau Monne
2012-06-26 17:22       ` Ian Jackson
2012-06-28  9:53         ` Roger Pau Monne
2012-06-28  9:56           ` Ian Campbell
2012-06-28 13:30             ` Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 08/13] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
2012-07-03  8:33   ` Ian Campbell
2012-06-14 12:21 ` [PATCH v6 09/13] libxl: rename _IOEMU nic type to VIF_IOEMU Roger Pau Monne
2012-06-22 11:39   ` Ian Jackson
2012-06-14 12:21 ` [PATCH v6 10/13] libxl: set nic type to VIF by default Roger Pau Monne
2012-06-22 11:40   ` Ian Jackson
2012-06-26 16:20     ` Roger Pau Monne
2012-06-26 16:58       ` Pasi Kärkkäinen
2012-06-27  8:50         ` Ian Campbell
2012-06-28  9:22           ` Roger Pau Monne
2012-06-28  9:26             ` Ian Campbell
2012-06-28  9:41               ` Roger Pau Monne
2012-06-28  9:54                 ` Ian Campbell
2012-06-28 10:07                   ` Roger Pau Monne
2012-06-28 10:10                     ` Ian Campbell
2012-06-28 13:29                       ` Roger Pau Monne
2012-06-28  9:28             ` Roger Pau Monne
2012-06-26 17:22       ` Ian Jackson
2012-06-14 12:21 ` [PATCH v6 11/13] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
2012-06-14 12:21 ` [PATCH v6 12/13] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
2012-06-22 11:43   ` Ian Jackson
2012-06-14 12:21 ` [PATCH v6 13/13] libxl: call hotplug scripts for nic " Roger Pau Monne
2012-05-30 13:07   ` [PATCH v5 01/10] execute hotplug scripts " Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 01/10] libxl: change libxl__ao_device_remove to libxl__ao_device Roger Pau Monne
2012-06-07 10:53       ` Ian Jackson
2012-06-11 10:09         ` Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 02/10] libxl: move device model creation prototypes Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 03/10] libxl: convert libxl_domain_destroy to an async op Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 04/10] libxl: convert libxl_device_disk_add to an asyn op Roger Pau Monne
2012-06-07 11:38       ` Ian Jackson
2012-06-11 12:33         ` Roger Pau Monne
2012-06-07 14:20       ` Ian Jackson
2012-06-07 16:42         ` Roger Pau Monne
2012-06-07 16:47           ` Ian Jackson
2012-06-07 14:25       ` Ian Jackson
2012-06-07 16:55         ` Roger Pau Monne
2012-06-07 17:05           ` Ian Jackson
2012-06-07 17:07             ` Roger Pau Monne
2012-06-07 17:11               ` Ian Jackson
2012-05-30 13:07     ` [PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation Roger Pau Monne
2012-06-07 14:26       ` Ian Jackson
2012-05-30 13:07     ` [PATCH v5 06/10] libxl: add option to choose who executes hotplug scripts Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 07/10] libxl: set nic type to VIF by default Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 08/10] libxl: call hotplug scripts for disk devices from libxl Roger Pau Monne
2012-06-07 14:40       ` Ian Jackson
2012-05-30 13:07     ` [PATCH v5 09/10] libxl: call hotplug scripts for nic " Roger Pau Monne
2012-06-07 14:48       ` Ian Jackson
2012-06-11 14:34         ` Roger Pau Monne
2012-06-22 11:47         ` [PATCH v5 09/10] libxl: call hotplug scripts for nic devices from libxl [and 1 more messages] Ian Jackson
2012-06-26  8:57           ` Roger Pau Monne
2012-05-30 13:07     ` [PATCH v5 10/10] libxl: use libxl__xs_path_cleanup on device_destroy Roger Pau Monne
2012-06-07 14:50       ` Ian Jackson
2012-07-03  8:27 ` [PATCH v6 00/13] execute hotplug scripts from libxl Ian Campbell
2012-07-03  9:19 ` Ian Campbell
2012-07-03  9:26   ` Ian Campbell
2012-07-03 12:54   ` Ian Jackson
2012-07-03 13:04     ` Ian Campbell

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