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

[Xen-devel] [PATCH 2/3] libxl: call hotplug scripts from libxl for vbd



This is a rather big change, that adds the necessary machinery to perform
hotplug script calling from libxl for Linux. This patch launches the necessary
scripts to attach and detach PHY and TAP backend types (Qemu doesn't use hotplug
scripts).

Here's a list of the major changes introduced:

 * libxl_device_disk_add makes use of the new event library and takes the
   optional parameter libxl_asyncop_how, to choose how the operation has to be
   issued (sync or async).

 * libxl_device_disk_add waits for backend to switch to state 2 (XenbusInitWait)
   and then launches the hotplug script.

 * libxl__devices_destroy no longer calls libxl__device_destroy, and instead
   calls libxl__initiate_device_remove, so we can disconnect the device and
   execute the necessary hotplug scripts instead of just deleting the backend
   entries. So libxl__devices_destroy now uses the event library, and so does
   libxl_domain_destroy.

 * Since libxl__devices_destroy calls multiple times
   libxl__initiate_device_remove, this function now returns a different value
   regarding the actions taken (if an event was added or not). The user has to
   call libxl__ao_complete after using this function if necessary.

 * The internal API for hotplug scripts has been added, which consists of one
   function; libxl__device_hotplug that takes the device and the action to
   execute.

 * Linux hotplug scripts are called by setting the necessary env variables to
   emulate udev rules, so there's no need to change them (although a rework to
   pass this as parameters insted of env variables would be suitable, so both
   NetBSD and Linux hotplug scripts take the same parameters).

Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
---
 tools/libxl/Makefile         |    3 +-
 tools/libxl/libxl.c          |  101 ++++++++++++++++++++++++++-----
 tools/libxl/libxl.h          |    7 ++-
 tools/libxl/libxl_create.c   |    4 +-
 tools/libxl/libxl_device.c   |  134 +++++++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl_dm.c       |    4 +-
 tools/libxl/libxl_hotplug.c  |   67 +++++++++++++++++++++
 tools/libxl/libxl_internal.h |   43 +++++++++++++-
 tools/libxl/libxl_linux.c    |  114 +++++++++++++++++++++++++++++++++++
 tools/libxl/xl_cmdimpl.c     |   14 ++--
 10 files changed, 453 insertions(+), 38 deletions(-)
 create mode 100644 tools/libxl/libxl_hotplug.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index b30d11f..ac8b810 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -53,7 +53,8 @@ LIBXL_LIBS += -lyajl
 LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
                        libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o \
                        libxl_internal.o libxl_utils.o libxl_uuid.o 
libxl_json.o \
-                       libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
+                       libxl_qmp.o libxl_event.o libxl_fork.o libxl_hotplug.o \
+                       $(LIBXL_OBJS-y)
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) 
$(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) -include $(XEN_ROOT)/tools/config.h
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 16ebef3..f253a6b 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1062,13 +1062,15 @@ 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)
+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);
     char *dom_path;
     char *vm_path;
     char *pid;
     int rc, dm_present;
+    int rc_ao = 0;
 
     rc = libxl_domain_info(ctx, NULL, domid);
     switch(rc) {
@@ -1110,7 +1112,8 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
 
         libxl__qmp_cleanup(gc, domid);
     }
-    if (libxl__devices_destroy(gc, domid) < 0)
+    rc_ao = libxl__devices_destroy(egc, ao, domid);
+    if (rc_ao < 0)
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 
                    "libxl__devices_destroy failed for %d", domid);
 
@@ -1133,9 +1136,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid)
         goto out;
     }
     rc = 0;
+
 out:
-    GC_FREE;
-    return rc;
+    if (rc_ao) return AO_ABORT(rc_ao);
+    return AO_INPROGRESS;
 }
 
 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, 
libxl_console_type type)
@@ -1313,9 +1317,11 @@ 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);
     flexarray_t *front;
     flexarray_t *back;
     char *dev;
@@ -1330,7 +1336,7 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *dis
         rc = ERROR_NOMEM;
         goto out;
     }
-    back = flexarray_make(16, 1);
+    back = flexarray_make(18, 1);
     if (!back) {
         rc = ERROR_NOMEM;
         goto out_free;
@@ -1361,6 +1367,11 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t 
domid, libxl_device_disk *dis
             flexarray_append(back, "params");
             flexarray_append(back, dev);
 
+            flexarray_append(back, "script");
+            flexarray_append(back, libxl__sprintf(gc, "%s/%s",
+                                                  libxl_xen_script_dir_path(),
+                                                  "block"));
+
             assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD);
             break;
         case LIBXL_DISK_BACKEND_TAP:
@@ -1374,6 +1385,11 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t 
domid, libxl_device_disk *dis
                 libxl__device_disk_string_of_format(disk->format),
                 disk->pdev_path));
 
+            flexarray_append(back, "script");
+            flexarray_append(back, libxl__sprintf(gc, "%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:
@@ -1420,14 +1436,23 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t 
domid, libxl_device_disk *dis
                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
                              libxl__xs_kvs_of_flexarray(gc, front, 
front->count));
 
+    if (disk->backend == LIBXL_DISK_BACKEND_PHY ||
+        disk->backend == LIBXL_DISK_BACKEND_TAP) {
+        rc = libxl__initiate_device_add(egc, ao, &device);
+        if (rc) goto out_free;
+    } else {
+        /* no need to execute hotplug scripts */
+        libxl__ao_complete(egc, ao, 0);
+    }
+
     rc = 0;
 
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    GC_FREE;
-    return rc;
+    if (rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
 }
 
 int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid,
@@ -1442,7 +1467,18 @@ int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t 
domid,
     if (rc != 0) goto out;
 
     rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    switch(rc) {
+    case 1:
+        /* event added */
+        break;
+    case 0:
+        /* no event added */
+        libxl__ao_complete(egc, ao, 0);
+        break;
+    default:
+        /* error */
+        goto out;
+    }
 
     return AO_INPROGRESS;
 
@@ -1666,11 +1702,11 @@ 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);
+    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);
+        libxl_device_disk_add(ctx, stubdomid, disk, 0);
     }
 out:
     for (i = 0; i < num; i++)
@@ -1909,7 +1945,18 @@ int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t 
domid,
     if (rc != 0) goto out;
 
     rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    switch(rc) {
+    case 1:
+        /* event added */
+        break;
+    case 0:
+        /* no event added */
+        libxl__ao_complete(egc, ao, 0);
+        break;
+    default:
+        /* error */
+        goto out;
+    }
 
     return AO_INPROGRESS;
 
@@ -2256,7 +2303,18 @@ int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t 
domid,
     if (rc != 0) goto out;
 
     rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    switch(rc) {
+    case 1:
+        /* event added */
+        break;
+    case 0:
+        /* no event added */
+        libxl__ao_complete(egc, ao, 0);
+        break;
+    default:
+        /* error */
+        goto out;
+    }
 
     return AO_INPROGRESS;
 
@@ -2389,7 +2447,18 @@ int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t 
domid,
     if (rc != 0) goto out;
 
     rc = libxl__initiate_device_remove(egc, ao, &device);
-    if (rc) goto out;
+    switch(rc) {
+    case 1:
+        /* event added */
+        break;
+    case 0:
+        /* no event added */
+        libxl__ao_complete(egc, ao, 0);
+        break;
+    default:
+        /* error */
+        goto out;
+    }
 
     return AO_INPROGRESS;
 
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 50bae2f..b7347be 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -394,7 +394,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, 
libxl_domain_suspend_info *info,
 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid);
-int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid);
+int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid,
+                         const libxl_asyncop_how *ao_how);
 int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, 
libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid);
 
 /* get max. number of cpus supported by hypervisor */
@@ -523,7 +524,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 3675afe..de598ad 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -598,7 +598,7 @@ static int do_domain_create(libxl__gc *gc, 
libxl_domain_config *d_config,
     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]);
+        ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i], 0);
         if (ret) {
             LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                        "cannot add disk %d to domain: %d", i, ret);
@@ -721,7 +721,7 @@ static int do_domain_create(libxl__gc *gc, 
libxl_domain_config *d_config,
 
 error_out:
     if (domid)
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
 
     return ret;
 }
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index c7e057d..8acda75 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -356,26 +356,90 @@ int libxl__device_disk_dev_number(const char *virtpath, 
int *pdisk,
     return -1;
 }
 
+static int libxl__xs_path_cleanup(libxl__gc *gc, char *path)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    unsigned int nb = 0;
+    char *last;
+
+    if (!path)
+        return 0;
+
+    xs_rm(ctx->xsh, XBT_NULL, path);
+
+    for (last = strrchr(path, '/'); last != NULL; last = strrchr(path, '/')) {
+        *last = '\0';
+        if (!libxl__xs_directory(gc, XBT_NULL, path, &nb))
+            continue;
+        if (nb == 0) {
+            xs_rm(ctx->xsh, XBT_NULL, path);
+        }
+    }
+    return 0;
+}
 
 typedef struct {
     libxl__ao *ao;
     libxl__ev_devstate ds;
+    libxl__device *dev;
 } libxl__ao_device_remove;
 
+typedef struct {
+    libxl__ao *ao;
+    libxl__ev_devstate ds;
+    libxl__device *dev;
+} libxl__ao_device_add;
+
 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_add_cleanup(libxl__gc *gc,
+                               libxl__ao_device_add *aorm) {
+    if (!aorm) return;
+    libxl__ev_devstate_cancel(gc, &aorm->ds);
+}
+
 static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
                                    int rc) {
     libxl__ao_device_remove *aorm = CONTAINER_OF(ds, *aorm, ds);
     libxl__gc *gc = &aorm->ao->gc;
+    rc = libxl__device_hotplug(gc, aorm->dev, DISCONNECT);
+    if (rc)
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to execute hotplug script 
for"
+                                          " device %"PRIu32, dev->devid);
+    libxl__xs_path_cleanup(gc, libxl__device_backend_path(gc, aorm->dev));
     libxl__ao_complete(egc, aorm->ao, rc);
     device_remove_cleanup(gc, aorm);
 }
 
+static void device_add_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+                                int rc)
+{
+    libxl__ao_device_add *aorm = CONTAINER_OF(ds, *aorm, ds);
+    libxl__gc *gc = &aorm->ao->gc;
+    rc = libxl__device_hotplug(gc, aorm->dev, CONNECT);
+    if (rc)
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to execute hotplug script 
for"
+                                          " device %"PRIu32, dev->devid);
+    libxl__ao_complete(egc, aorm->ao, rc);
+    if (aorm)
+        libxl__ev_devstate_cancel(gc, &aorm->ds);
+    return;
+}
+
+/*
+ * Return codes:
+ * 1 Success and event(s) HAVE BEEN added
+ * 0 Success and NO events where added
+ * < 0 Error
+ *
+ * Since this function can be called several times, and several events
+ * can be added to the same context, the user has to call
+ * libxl__ao_complete when necessary (if no events are added).
+ */
 int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao,
                                   libxl__device *dev)
 {
@@ -392,7 +456,6 @@ int libxl__initiate_device_remove(libxl__egc *egc, 
libxl__ao *ao,
         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;
     }
 
@@ -413,6 +476,7 @@ retry_transaction:
 
     aorm = libxl__zalloc(gc, sizeof(*aorm));
     aorm->ao = ao;
+    aorm->dev = dev;
     libxl__ev_devstate_init(&aorm->ds);
 
     rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_remove_callback,
@@ -420,7 +484,7 @@ retry_transaction:
                                  LIBXL_DESTROY_TIMEOUT * 1000);
     if (rc) goto out_fail;
 
-    return 0;
+    return 1;
 
  out_fail:
     assert(rc);
@@ -428,8 +492,50 @@ retry_transaction:
     return rc;
 
  out_ok:
-    libxl__ao_complete(egc, ao, 0);
+    rc = libxl__device_hotplug(gc, dev, DISCONNECT);
+    libxl__xs_path_cleanup(gc, be_path);
+    return 0;
+}
+
+int libxl__initiate_device_add(libxl__egc *egc, libxl__ao *ao,
+                               libxl__device *dev)
+{
+    AO_GC;
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    char *be_path = libxl__device_backend_path(gc, 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_add *aorm = 0;
+
+    if (atoi(state) == XenbusStateInitWait)
+        goto out_ok;
+
+    aorm = libxl__zalloc(gc, sizeof(*aorm));
+    aorm->ao = ao;
+    aorm->dev = dev;
+    libxl__ev_devstate_init(&aorm->ds);
+
+    rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_add_callback,
+                                 state_path, XenbusStateInitWait,
+                                 LIBXL_INIT_TIMEOUT * 1000);
+    if (rc) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to initialize device %"
+                                          PRIu32, dev->devid);
+        libxl__ev_devstate_cancel(gc, &aorm->ds);
+        goto out_fail;
+    }
+
     return 0;
+
+out_fail:
+    assert(rc);
+    device_add_cleanup(gc, aorm);
+    return rc;
+out_ok:
+    rc = libxl__device_hotplug(gc, dev, CONNECT);
+    libxl__ao_complete(egc, ao, 0);
+    return rc;
 }
 
 int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
@@ -446,13 +552,14 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device 
*dev)
     return 0;
 }
 
-int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
+int libxl__devices_destroy(libxl__egc *egc, libxl__ao *ao, uint32_t domid)
 {
+    AO_GC;
     libxl_ctx *ctx = libxl__gc_owner(gc);
     char *path;
     unsigned int num_kinds, num_devs;
     char **kinds = NULL, **devs = NULL;
-    int i, j;
+    int i, j, events = 0, rc;
     libxl__device dev;
     libxl__device_kind kind;
 
@@ -482,11 +589,24 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid)
                 dev.domid = domid;
                 dev.kind = kind;
                 dev.devid = atoi(devs[j]);
-
-                libxl__device_destroy(gc, &dev);
+                rc = libxl__initiate_device_remove(egc, ao, &dev);
+                switch(rc) {
+                case 1:
+                    events++;
+                    break;
+                case 0:
+                    /* no events added */
+                    break;
+                default:
+                    LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Could not remove device 
"
+                                                      "%s", path);
+                }
             }
         }
     }
+    /* Check if any events where added */
+    if (!events)
+        libxl__ao_complete(egc, ao, 0);
 
     /* console 0 frontend directory is not under /local/domain/<domid>/device 
*/
     path = libxl__sprintf(gc, "/local/domain/%d/console/backend", domid);
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 30908d1..2d51a7f 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -790,7 +790,7 @@ retry_transaction:
             goto retry_transaction;
 
     for (i = 0; i < dm_config.num_disks; i++) {
-        ret = libxl_device_disk_add(ctx, dm_domid, &dm_config.disks[i]);
+        ret = libxl_device_disk_add(ctx, dm_domid, &dm_config.disks[i], 0);
         if (ret)
             goto out_free;
     }
@@ -1044,7 +1044,7 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t 
domid)
             goto out;
         }
         LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device model is a stubdom, 
domid=%d", stubdomid);
-        ret = libxl_domain_destroy(ctx, stubdomid);
+        ret = libxl_domain_destroy(ctx, stubdomid, 0);
         if (ret)
             goto out;
 
diff --git a/tools/libxl/libxl_hotplug.c b/tools/libxl/libxl_hotplug.c
new file mode 100644
index 0000000..52dccb0
--- /dev/null
+++ b/tools/libxl/libxl_hotplug.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012
+ * Author Roger Pau Monne <roger.paumonne@xxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h" /* must come before any other headers */
+
+#include "libxl_internal.h"
+
+/*
+ * Generic hotplug helpers
+ *
+ * This helpers are both used by Linux and NetBSD hotplug script
+ * dispatcher functions.
+ */
+
+static void hotplug_exited(libxl__egc *egc, libxl__ev_child *child,
+                           pid_t pid, int status)
+{
+    libxl__hotplug_state *hs = CONTAINER_OF(child, *hs, child);
+    EGC_GC;
+
+    if (status) {
+        libxl_report_child_exitstatus(CTX, hs->rc ? LIBXL__LOG_ERROR
+                                                  : LIBXL__LOG_WARNING,
+                                      "hotplug child", pid, status);
+    }
+}
+
+int libxl__hotplug_exec(libxl__gc *gc, char *arg0, char **args, char **env)
+{
+    int rc = 0;
+    pid_t pid = -1;
+    libxl__hotplug_state *hs;
+
+    hs = libxl__zalloc(gc, sizeof(*hs));
+
+    pid = libxl__ev_child_fork(gc, &hs->child, hotplug_exited);
+    if (pid == -1) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (!pid) {
+        /* child */
+        signal(SIGCHLD, SIG_DFL);
+        libxl__exec(-1, -1, -1, arg0, args, env);
+    }
+out:
+    if (libxl__ev_child_inuse(&hs->child)) {
+        hs->rc = rc;
+        /* we will get a callback when the child dies */
+        return 0;
+    }
+
+    assert(rc);
+    return rc;
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2181774..a39346c 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -70,6 +70,7 @@
 #include "_libxl_types_internal_json.h"
 
 #define LIBXL_DESTROY_TIMEOUT 10
+#define LIBXL_INIT_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
 #define LIBXL_XENCONSOLE_LIMIT 1048576
 #define LIBXL_XENCONSOLE_PROTOCOL "vt100"
@@ -455,6 +456,37 @@ _hidden bool libxl__xs_mkdir(libxl__gc *gc, 
xs_transaction_t t,
 
 _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid);
 
+/*
+ * Hotplug handling
+ *
+ * Hotplug scripts are launched automatically by libxl at guest creation &
+ * shutdown/destroy.
+ */
+
+/* Action to pass to hotplug caller functions */
+typedef enum {
+    CONNECT = 1,
+    DISCONNECT = 2
+} libxl__hotplug_action;
+
+typedef struct libxl__hotplug_state libxl__hotplug_state;
+
+struct libxl__hotplug_state {
+    /* public, result, caller may only read in callback */
+    int rc;
+    /* private for implementation */
+    libxl__ev_child child;
+};
+
+/*
+ * libxl__hotplug_exec is an internal function that should not be used
+ * directly, all hotplug script calls have to implement and use
+ * libxl__device_hotplug.
+ */
+_hidden int libxl__device_hotplug(libxl__gc *gc, libxl__device *dev,
+                                  libxl__hotplug_action action);
+_hidden int libxl__hotplug_exec(libxl__gc *gc, char *arg0, char **args,
+                                char **env);
 
 /*
  * Event generation functions provided by the libxl event core to the
@@ -740,7 +772,8 @@ _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__devices_destroy(libxl__egc *egc, libxl__ao *ao,
+                                   uint32_t domid);
 _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state);
 
 /*
@@ -763,6 +796,14 @@ _hidden int libxl__wait_for_backend(libxl__gc *gc, char 
*be_path, char *state);
 _hidden int libxl__initiate_device_remove(libxl__egc*, libxl__ao*,
                                           libxl__device *dev);
 
+/* Arranges that dev will be added to the guest, and the
+ * hotplug scripts will be executed (if necessary). When
+ * this is done, the ao will be completed. An error
+ * return from libxl__initiate_device_add means that the ao
+ * will _not_ be completed and the caller must do so. */
+_hidden int libxl__initiate_device_add(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.
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 925248b..372b95d 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -25,3 +25,117 @@ 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)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    char *be_path = libxl__device_backend_path(gc, dev);
+    flexarray_t *f_env;
+    int nr = 0;
+
+    f_env = flexarray_make(11, 1);
+    if (!f_env) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "unable to create environment array");
+        return NULL;
+    }
+
+    flexarray_set(f_env, nr++, "script");
+    flexarray_set(f_env, nr++, libxl__xs_read(gc, XBT_NULL,
+                               libxl__sprintf(gc, "%s/%s",
+                                              be_path,
+                                              "script")));
+    flexarray_set(f_env, nr++, "XENBUS_TYPE");
+    flexarray_set(f_env, nr++, (char *)
+                  libxl__device_kind_to_string(dev->backend_kind));
+    flexarray_set(f_env, nr++, "XENBUS_PATH");
+    flexarray_set(f_env, nr++,
+                  libxl__sprintf(gc, "backend/%s/%u/%d",
+                  libxl__device_kind_to_string(dev->backend_kind),
+                  dev->domid, dev->devid));
+    flexarray_set(f_env, nr++, "XENBUS_BASE_PATH");
+    flexarray_set(f_env, nr++, "backend");
+    if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
+        flexarray_set(f_env, nr++, "vif");
+        flexarray_set(f_env, nr++,
+                      libxl__sprintf(gc, "%s%u.%d",
+                      libxl__device_kind_to_string(dev->backend_kind),
+                      dev->domid, dev->devid));
+    }
+    flexarray_set(f_env, nr++, NULL);
+
+    return (char **) flexarray_contents(f_env);
+}
+
+/* Hotplug scripts caller functions */
+
+static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
+                               libxl__hotplug_action action)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    char *be_path = libxl__device_backend_path(gc, dev);
+    char *script, *what;
+    char **args, **env;
+    int nr = 0, rc = 0;
+    flexarray_t *f_args;
+
+    script = libxl__xs_read(gc, XBT_NULL,
+                            libxl__sprintf(gc, "%s/%s", be_path, "script"));
+    if (!script) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to read script from %s",
+                                          be_path);
+        return -1;
+    }
+
+    env = get_hotplug_env(gc, dev);
+    if (!env)
+        return -1;
+
+    f_args = flexarray_make(3, 1);
+    if (!f_args) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to create arguments array");
+        return -1;
+    }
+
+    flexarray_set(f_args, nr++, script);
+    flexarray_set(f_args, nr++, action == CONNECT ? "add" : "remove");
+    flexarray_set(f_args, nr++, NULL);
+
+    args = (char **) flexarray_contents(f_args);
+    what = libxl__sprintf(gc, "%s %s", args[0],
+                          action == CONNECT ? "connect" : "disconnect");
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+               "Calling hotplug script: %s %s",
+               args[0], args[1]);
+    rc = libxl__hotplug_exec(gc, args[0], args, env);
+    if (rc) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable execute hotplug scripts for "
+                                          "device %"PRIu32, dev->devid);
+        goto out_free;
+    }
+
+    rc = 0;
+
+out_free:
+    free(env);
+    free(args);
+    return rc;
+}
+
+int libxl__device_hotplug(libxl__gc *gc, libxl__device *dev,
+                          libxl__hotplug_action action)
+{
+    int rc = 0;
+
+    switch (dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+        rc = libxl__hotplug_disk(gc, dev, action);
+        break;
+    default:
+        rc = 0;
+        break;
+    }
+
+    return rc;
+}
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 08815a3..01ff363 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1301,7 +1301,7 @@ static int handle_domain_death(libxl_ctx *ctx, uint32_t 
domid,
         /* fall-through */
     case LIBXL_ACTION_ON_SHUTDOWN_DESTROY:
         LOG("Domain %d needs to be cleaned up: destroying the domain", domid);
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
         break;
 
     case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY:
@@ -1862,7 +1862,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)
@@ -2339,7 +2339,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); }
 }
 
@@ -2613,7 +2613,7 @@ static int save_domain(const char *p, const char 
*filename, int checkpoint,
     if (checkpoint)
         libxl_domain_unpause(ctx, domid);
     else
-        libxl_domain_destroy(ctx, domid);
+        libxl_domain_destroy(ctx, domid, 0);
 
     exit(0);
 }
@@ -2846,7 +2846,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);
 
@@ -2964,7 +2964,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);
@@ -5011,7 +5011,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)


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


 


Rackspace

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