aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxl/libxl_device.c
diff options
context:
space:
mode:
authorRoger Pau Monne <roger.pau@citrix.com>2012-07-26 16:47:34 +0100
committerRoger Pau Monne <roger.pau@citrix.com>2012-07-26 16:47:34 +0100
commitb24dc64ef34437c958b40a71f510f404e0c4bbe4 (patch)
tree45d6b1f9269c422f0618918c64f4ba41752ddb7b /tools/libxl/libxl_device.c
parent24bc7a06aea0dd3cb3c9e0ba6c0367d54fdd503e (diff)
downloadxen-b24dc64ef34437c958b40a71f510f404e0c4bbe4.tar.gz
xen-b24dc64ef34437c958b40a71f510f404e0c4bbe4.tar.bz2
xen-b24dc64ef34437c958b40a71f510f404e0c4bbe4.zip
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@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'tools/libxl/libxl_device.c')
-rw-r--r--tools/libxl/libxl_device.c132
1 files changed, 130 insertions, 2 deletions
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index ed33f6f644..a80dee846f 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -412,9 +412,12 @@ void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev)
aodev->ao = ao;
aodev->rc = 0;
aodev->dev = NULL;
- /* Initialize timer for QEMU Bodge */
+ /* 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(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_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__egc *egc, libxl__ao_device *aodev)
* 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__egc *egc, libxl__ev_time *ev,
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(libxl__egc *egc, libxl__ev_devstate *ds,
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__gc *gc, libxl__ao_device *aodev)
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__egc *egc, libxl__ao_device *aodev)
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);