[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] libxl: call hotplug scripts for disk devices from libxl
# HG changeset patch # User Roger Pau Monne <roger.pau@xxxxxxxxxx> # Date 1343317654 -3600 # Node ID 24dac62c0458bee85a8b7398c4c47094f503acb1 # Parent 0d98248a77ce87ed0a0766a2c50d884bb2687790 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. Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx> Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> Committed-by: Ian Campbell <ian.campbell@xxxxxxxxxx> --- diff -r 0d98248a77ce -r 24dac62c0458 tools/hotplug/Linux/xen-backend.rules --- a/tools/hotplug/Linux/xen-backend.rules Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/hotplug/Linux/xen-backend.rules Thu Jul 26 16:47:34 2012 +0100 @@ -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 -r 0d98248a77ce -r 24dac62c0458 tools/hotplug/Linux/xen-hotplug-common.sh --- a/tools/hotplug/Linux/xen-hotplug-common.sh Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/hotplug/Linux/xen-hotplug-common.sh Thu Jul 26 16:47:34 2012 +0100 @@ -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 -r 0d98248a77ce -r 24dac62c0458 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/libxl/libxl.c Thu Jul 26 16:47:34 2012 +0100 @@ -1858,6 +1858,11 @@ static void device_disk_add(libxl__egc * 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: @@ -1873,6 +1878,11 @@ static void device_disk_add(libxl__egc * 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 -r 0d98248a77ce -r 24dac62c0458 tools/libxl/libxl_device.c --- a/tools/libxl/libxl_device.c Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/libxl/libxl_device.c Thu Jul 26 16:47:34 2012 +0100 @@ -412,9 +412,12 @@ void libxl__prepare_ao_device(libxl__ao aodev->ao = ao; aodev->rc = 0; aodev->dev = NULL; - /* Initialize timer for QEMU Bodge */ + /* Initialize timer for QEMU Bodge and hotplug execution */ libxl__ev_time_init(&aodev->timeout); aodev->active = 1; + /* We init this here because we might call device_hotplug_done + * without actually calling any hotplug script */ + libxl__ev_child_init(&aodev->child); } void libxl__prepare_ao_devices(libxl__ao *ao, libxl__ao_devices *aodevs) @@ -624,6 +627,15 @@ static void device_backend_callback(libx 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_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__wait_device_connection(libxl__egc *egc, libxl__ao_device *aodev) @@ -649,7 +661,7 @@ void libxl__wait_device_connection(libxl * If Qemu is running, it will set the state of the device to * 4 directly, without waiting in state 2 for any hotplug execution. */ - device_hotplug_done(egc, aodev); + device_hotplug(egc, aodev); return; } @@ -783,6 +795,9 @@ static void device_qemu_timeout(libxl__e rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6"); if (rc) goto out; + device_hotplug(egc, aodev); + return; + out: aodev->rc = rc; device_hotplug_done(egc, aodev); @@ -808,6 +823,9 @@ static void device_backend_callback(libx goto out; } + device_hotplug(egc, aodev); + return; + out: aodev->rc = rc; device_hotplug_done(egc, aodev); @@ -820,6 +838,111 @@ static void device_backend_cleanup(libxl libxl__ev_devstate_cancel(gc, &aodev->backend_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 */ + rc = libxl__ev_time_register_rel(gc, &aodev->timeout, + 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, timeout); + STATE_AO_GC(aodev->ao); + + libxl__ev_time_deregister(gc, &aodev->timeout); + + 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); + char *be_path = libxl__device_backend_path(gc, aodev->dev); + char *hotplug_error; + + if (status) { + libxl_report_child_exitstatus(CTX, LIBXL__LOG_ERROR, + aodev->what, pid, status); + hotplug_error = libxl__xs_read(gc, XBT_NULL, + GCSPRINTF("%s/hotplug-error", be_path)); + if (hotplug_error) + LOG(ERROR, "script: %s", hotplug_error); + 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); @@ -828,6 +951,11 @@ static void device_hotplug_done(libxl__e xs_transaction_t t = 0; int rc; + /* Clean events and check reentrancy */ + libxl__ev_time_deregister(gc, &aodev->timeout); + assert(!libxl__ev_child_inuse(&aodev->child)); + + /* Clean xenstore if it's a disconnection */ if (aodev->action == DEVICE_DISCONNECT) { for (;;) { rc = libxl__xs_transaction_start(gc, &t); diff -r 0d98248a77ce -r 24dac62c0458 tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/libxl/libxl_internal.h Thu Jul 26 16:47:34 2012 +0100 @@ -74,6 +74,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_QEMU_BODGE_TIMEOUT 2 #define LIBXL_XENCONSOLE_LIMIT 1048576 @@ -1832,11 +1833,14 @@ struct libxl__ao_device { int active; int rc; libxl__ev_devstate backend_ds; - /* Bodge for Qemu devices */ + /* Bodge for Qemu devices, also used for timeout of hotplug execution */ libxl__ev_time timeout; /* 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_child child; }; /* Helper struct to simply the plug/unplug of multiple devices at the same @@ -1966,6 +1970,20 @@ _hidden void libxl__wait_device_connecti _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 -r 0d98248a77ce -r 24dac62c0458 tools/libxl/libxl_linux.c --- a/tools/libxl/libxl_linux.c Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/libxl/libxl_linux.c Thu Jul 26 16:47:34 2012 +0100 @@ -77,3 +77,100 @@ char *libxl__devid_to_localdev(libxl__gc "%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 = 1; + +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); + break; + default: + /* No need to execute any hotplug scripts */ + rc = 0; + break; + } + +out: + return rc; +} diff -r 0d98248a77ce -r 24dac62c0458 tools/libxl/libxl_netbsd.c --- a/tools/libxl/libxl_netbsd.c Thu Jul 26 16:47:33 2012 +0100 +++ b/tools/libxl/libxl_netbsd.c Thu Jul 26 16:47:34 2012 +0100 @@ -30,3 +30,11 @@ char *libxl__devid_to_localdev(libxl__gc /* 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; +} _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |