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

[Xen-devel] [PATCH 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.

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.

Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
---
 tools/hotplug/Linux/xen-backend.rules     |    6 +-
 tools/hotplug/Linux/xen-hotplug-common.sh |    6 ++
 tools/libxl/Makefile                      |    3 +-
 tools/libxl/libxl_device.c                |   23 ++++-
 tools/libxl/libxl_hotplug.c               |   84 +++++++++++++++++++
 tools/libxl/libxl_internal.h              |   17 ++++
 tools/libxl/libxl_linux.c                 |  126 +++++++++++++++++++++++++++++
 7 files changed, 256 insertions(+), 9 deletions(-)
 create mode 100644 tools/libxl/libxl_hotplug.c

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/Makefile b/tools/libxl/Makefile
index 5d9227e..9abadff 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -66,7 +66,8 @@ 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_aoutils.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_device.c b/tools/libxl/libxl_device.c
index 6b0ce95..0b7beb7 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -380,6 +380,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:
@@ -393,6 +398,11 @@ void libxl__device_disk_add(libxl__egc *egc, uint32_t 
domid,
             flexarray_append(back, "tapdisk-params");
             flexarray_append(back, GCSPRINTF("%s:%s", 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:
@@ -760,7 +770,7 @@ out_fail:
 
 out_ok:
     assert(!rc);
-    aorm->callback(egc, aorm);
+    libxl__device_hotplug(egc, aorm);
     return;
 }
 
@@ -822,7 +832,7 @@ retry_transaction:
 
  out_ok:
     if (t) xs_transaction_end(ctx->xsh, t, 0);
-    aorm->callback(egc, aorm);
+    libxl__device_hotplug(egc, aorm);
     return;
 }
 
@@ -929,14 +939,17 @@ static void device_backend_callback(libxl__egc *egc, 
libxl__ev_devstate *ds,
     if (rc && aorm->action == DEVICE_CONNECT) {
         LOG(ERROR, "unable to connect device with path %s",
                    libxl__device_backend_path(gc, aorm->dev));
-        goto out;
+        goto error;
     } else if(rc) {
         LOG(DEBUG, "unable to disconnect device with path %s",
                    libxl__device_backend_path(gc, aorm->dev));
-        goto out;
+        goto error;
     }
 
-out:
+    libxl__device_hotplug(egc, aorm);
+    return;
+
+error:
     aorm->rc = rc;
     aorm->callback(egc, aorm);
     return;
diff --git a/tools/libxl/libxl_hotplug.c b/tools/libxl/libxl_hotplug.c
new file mode 100644
index 0000000..686a38d
--- /dev/null
+++ b/tools/libxl/libxl_hotplug.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012
+ * Author Roger Pau Monne <roger.pau@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 device_hotplug_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                   const struct timeval *requested_abs)
+{
+    libxl__ao_device *aorm = CONTAINER_OF(ev, *aorm, ev);
+    STATE_AO_GC(aorm->ao);
+
+    if (!aorm) return;
+    if (libxl__ev_child_inuse(&aorm->child)) {
+        if (kill(aorm->pid, SIGKILL)) {
+            LOGEV(ERROR, errno, "unable to kill hotplug script %s [%ld]",
+                                aorm->what, (unsigned long)aorm->pid);
+            goto out;
+        }
+    }
+
+out:
+    libxl__ev_time_deregister(gc, &aorm->ev);
+    return;
+}
+
+int libxl__hotplug_launch(libxl__gc *gc, libxl__ao_device *aorm,
+                          const char *arg0, char *const args[],
+                          char *const env[], libxl__ev_child_callback *death)
+{
+    int rc = 0;
+    pid_t pid = -1;
+
+    libxl__ev_time_init(&aorm->ev);
+    libxl__ev_child_init(&aorm->child);
+
+    rc = libxl__ev_time_register_rel(gc, &aorm->ev, device_hotplug_timeout,
+                                     LIBXL_HOTPLUG_TIMEOUT * 1000);
+    if (rc) {
+        LOGE(ERROR, "unable to register timeout for hotplug script %s", arg0);
+        goto out;
+    }
+
+    pid = libxl__ev_child_fork(gc, &aorm->child, death);
+    if (pid == -1) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (!pid) {
+        /* child */
+        libxl__exec(gc, -1, -1, -1, arg0, args, env);
+        LOGE(ERROR, "unable execute hotplug scripts for device %"PRIu32 " on "
+                    "dom %"PRIu32, aorm->dev->devid, aorm->dev->backend_domid);
+        abort();
+    }
+out:
+    if (libxl__ev_child_inuse(&aorm->child)) {
+        aorm->pid = pid;
+        /* we will get a callback when the child dies */
+        return 0;
+    }
+    libxl__ev_time_deregister(gc, &aorm->ev);
+    return rc;
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 7969a43..5e2bac5 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"
@@ -1813,6 +1814,11 @@ struct libxl__ao_device {
     int rc;
     libxl__ev_devstate ds;
     void *base;
+    /* device hotplug execution */
+    pid_t pid;
+    char *what;
+    libxl__ev_time ev;
+    libxl__ev_child child;
 };
 
 /* Internal AO operation to connect a disk device */
@@ -1840,6 +1846,17 @@ _hidden void libxl__initiate_device_add(libxl__egc*, 
libxl__ao_device *aorm);
 _hidden void libxl__initiate_device_remove(libxl__egc *egc,
                                            libxl__ao_device *aorm);
 
+/*
+ * libxl__hotplug_launch is an internal function that should not be used
+ * directly, all hotplug script calls have to implement and use
+ * libxl__device_hotplug.
+ */
+_hidden void libxl__device_hotplug(libxl__egc *egc, libxl__ao_device *aorm);
+_hidden int libxl__hotplug_launch(libxl__gc *gc, libxl__ao_device *aorm,
+                                  const char *arg0, char *const args[],
+                                  char *const env[],
+                                  libxl__ev_child_callback *death);
+
 /*----- Domain destruction -----*/
 
 /* Domain destruction has been splitted in two functions:
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index 925248b..315ce15 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -25,3 +25,129 @@ int libxl__try_phy_backend(mode_t st_mode)
 
     return 1;
 }
+
+/* Hotplug scripts helpers */
+
+static void cleanup(libxl__gc *gc, libxl__ao_device *aorm)
+{
+    if (!aorm) return;
+    libxl__ev_time_deregister(gc, &aorm->ev);
+}
+
+static void callback(libxl__egc *egc, libxl__ev_child *child,
+                                    pid_t pid, int status)
+{
+    libxl__ao_device *aorm = CONTAINER_OF(child, *aorm, child);
+    STATE_AO_GC(aorm->ao);
+
+    cleanup(gc, aorm);
+
+    if (status) {
+        libxl_report_child_exitstatus(CTX, aorm->rc ? LIBXL__LOG_ERROR
+                                                    : LIBXL__LOG_WARNING,
+                                      aorm->what, pid, status);
+        aorm->rc = ERROR_FAIL;
+    }
+    aorm->callback(egc, aorm);
+}
+
+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;
+    }
+
+    GCNEW_ARRAY(env, 9);
+    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;
+
+    return env;
+}
+
+/* Hotplug scripts caller functions */
+
+static int libxl__hotplug_disk(libxl__gc *gc, libxl__ao_device *aorm)
+{
+    char *be_path = libxl__device_backend_path(gc, aorm->dev);
+    char *script;
+    char **args, **env;
+    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);
+        return ERROR_FAIL;
+    }
+
+    env = get_hotplug_env(gc, aorm->dev);
+    if (!env)
+        return ERROR_FAIL;
+
+    GCNEW_ARRAY(args, 3);
+
+    args[nr++] = script;
+    args[nr++] = aorm->action == DEVICE_CONNECT ? "add" : "remove";
+    args[nr++] = NULL;
+
+    aorm->what = GCSPRINTF("%s %s", args[0], args[1]);
+    LOG(DEBUG, "calling hotplug script: %s %s", args[0], args[1]);
+    rc = libxl__hotplug_launch(gc, aorm, args[0], args, env, callback);
+    if (rc) {
+        goto out_free;
+    }
+
+    rc = 0;
+
+out_free:
+    return rc;
+}
+
+void libxl__device_hotplug(libxl__egc *egc, libxl__ao_device *aorm)
+{
+    STATE_AO_GC(aorm->ao);
+    char *disable_udev = libxl__xs_read(gc, XBT_NULL, DISABLE_UDEV_PATH);
+
+    /* Check if we have to run hotplug scripts */
+    if (!disable_udev) goto out;
+
+    switch (aorm->dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+        aorm->rc = libxl__hotplug_disk(gc, aorm);
+        if (aorm->rc) goto error;
+        break;
+    default:
+        /* If no need to execute any hotplug scripts,
+         * call the callback manually
+         */
+        aorm->rc = 0;
+        aorm->callback(egc, aorm);
+        break;
+    }
+
+    return;
+
+error:
+    assert(aorm->rc);
+    LOGE(ERROR, "unable to queue execution of hotplug script for device "
+                "with path %s", libxl__device_backend_path(gc, aorm->dev));
+out:
+    aorm->callback(egc, aorm);
+    return;
+}
-- 
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®.