aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/libxl/libxl.c229
-rw-r--r--tools/libxl/libxl.h15
-rw-r--r--tools/libxl/libxl_device.c193
-rw-r--r--tools/libxl/libxl_internal.h143
-rw-r--r--tools/libxl/xl_cmdimpl.c2
-rw-r--r--tools/ocaml/libs/xl/xenlight_stubs.c4
6 files changed, 390 insertions, 196 deletions
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 427774560b..ebc314b46d 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1503,6 +1503,31 @@ 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) {
+ if (aodev->dev) {
+ LOG(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);
+ } else {
+ LOG(ERROR, "unable to %s device",
+ aodev->action == DEVICE_CONNECT ? "add" : "remove");
+ }
+ 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;
@@ -1680,42 +1705,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)
@@ -2080,8 +2069,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:
@@ -2249,42 +2239,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)
@@ -2611,42 +2565,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)
@@ -2744,41 +2662,66 @@ 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 */
+/* The following functions are defined:
+ * libxl_device_disk_remove
+ * libxl_device_disk_destroy
+ * libxl_device_nic_remove
+ * libxl_device_nic_destroy
+ * libxl_device_vkb_remove
+ * libxl_device_vkb_destroy
+ * libxl_device_vfb_remove
+ * libxl_device_vfb_destroy
+ */
+#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 f5a8f877ea..c2d5c06154 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -679,7 +679,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,
@@ -696,7 +697,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,
@@ -707,14 +710,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 d33ac68545..5a07ffb35b 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -361,11 +361,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 *ao, libxl__ao_device *aodev)
+{
+ aodev->ao = ao;
+ aodev->rc = 0;
+ aodev->dev = NULL;
+ /* Initialize timer for QEMU Bodge */
+ libxl__ev_time_init(&aodev->timeout);
+}
int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
{
@@ -441,36 +446,81 @@ out:
/* Callbacks for device related operations */
-static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds,
+/*
+ * device_backend_callback is the main callback entry point, for both device
+ * addition and removal. It gets called if we reach the desired state
+ * (XenbusStateClosed or XenbusStateInitWait). After that, all this
+ * functions get called in the order displayed below.
+ *
+ * If new device types are added, they should only need to modify the
+ * specific hotplug scripts call, which can be found in each OS specific
+ * file. If this new devices don't need a hotplug script, no modification
+ * should be needed.
+ */
+
+/* This callback is part of the Qemu devices Badge */
+static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev,
+ const struct timeval *requested_abs);
+
+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)
+static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev);
+
+void libxl__initiate_device_remove(libxl__egc *egc,
+ libxl__ao_device *aodev)
{
- AO_GC;
+ STATE_AO_GC(aodev->ao);
xs_transaction_t t = 0;
- char *be_path = libxl__device_backend_path(gc, dev);
+ char *be_path = libxl__device_backend_path(gc, aodev->dev);
char *state_path = libxl__sprintf(gc, "%s/state", be_path);
char *online_path = GCSPRINTF("%s/online", be_path);
const char *state;
-
+ libxl_dominfo info;
+ uint32_t domid = aodev->dev->domid;
int rc = 0;
- libxl__ao_device_remove *aorm = 0;
+
+ libxl_dominfo_init(&info);
+ rc = libxl_domain_info(CTX, &info, domid);
+ if (rc) {
+ LOG(ERROR, "unable to get info for domain %d", domid);
+ goto out;
+ }
+ if (QEMU_BACKEND(aodev->dev) &&
+ (info.paused || info.dying || info.shutdown)) {
+ /*
+ * TODO: 4.2 Bodge due to QEMU, see comment on top of
+ * libxl__initiate_device_remove in libxl_internal.h
+ */
+ rc = libxl__ev_time_register_rel(gc, &aodev->timeout,
+ device_qemu_timeout,
+ LIBXL_QEMU_BODGE_TIMEOUT * 1000);
+ if (rc) {
+ LOG(ERROR, "unable to register timeout for Qemu device %s",
+ be_path);
+ goto out;
+ }
+ return;
+ }
for (;;) {
rc = libxl__xs_transaction_start(gc, &t);
if (rc) {
LOG(ERROR, "unable to start transaction");
- goto out_fail;
+ goto out;
}
+ if (aodev->force)
+ libxl__xs_path_cleanup(gc, t,
+ libxl__device_frontend_path(gc, aodev->dev));
+
rc = libxl__xs_read_checked(gc, t, state_path, &state);
if (rc) {
LOG(ERROR, "unable to read device state from path %s", state_path);
- goto out_fail;
+ goto out;
}
/*
@@ -481,53 +531,118 @@ int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao,
rc = libxl__xs_write_checked(gc, t, online_path, "0");
if (rc) {
LOG(ERROR, "unable to write to xenstore path %s", online_path);
- goto out_fail;
+ goto out;
}
rc = libxl__xs_write_checked(gc, t, state_path, "5");
if (rc) {
LOG(ERROR, "unable to write to xenstore path %s", state_path);
- goto out_fail;
+ goto out;
}
}
rc = libxl__xs_transaction_commit(gc, &t);
if (!rc) break;
- if (rc < 0) goto out_fail;
+ if (rc < 0) goto out;
}
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;
+ }
- libxl__ao_complete(egc, ao, 0);
- return 0;
+ libxl_dominfo_dispose(&info);
+ return;
- out_fail:
- assert(rc);
+out:
+ aodev->rc = rc;
+ libxl_dominfo_dispose(&info);
libxl__xs_transaction_abort(gc, &t);
- device_remove_cleanup(gc, aorm);
- return rc;
+ device_hotplug_done(egc, aodev);
+ return;
+}
+
+static void device_qemu_timeout(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);
+ char *be_path = libxl__device_backend_path(gc, aodev->dev);
+ char *state_path = GCSPRINTF("%s/state", be_path);
+ int rc = 0;
+
+ libxl__ev_time_deregister(gc, &aodev->timeout);
+
+ rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6");
+ if (rc) goto out;
+
+out:
+ aodev->rc = rc;
+ device_hotplug_done(egc, aodev);
}
-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;
+ }
+
+ if (rc) {
+ LOG(ERROR, "unable to disconnect device with path %s",
+ libxl__device_backend_path(gc, aodev->dev));
+ goto out;
+ }
+
+out:
+ aodev->rc = rc;
+ device_hotplug_done(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_hotplug_done(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 rc;
+
+ if (aodev->action == DEVICE_DISCONNECT) {
+ for (;;) {
+ rc = libxl__xs_transaction_start(gc, &t);
+ if (rc) goto out;
+
+ libxl__xs_path_cleanup(gc, t, fe_path);
+ libxl__xs_path_cleanup(gc, t, be_path);
+
+ rc = libxl__xs_transaction_commit(gc, &t);
+ if (!rc) break;
+ if (rc < 0) goto out;
+ }
+ }
+
+out:
+ 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 2781398be4..5d985ff9aa 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -74,6 +74,7 @@
#define LIBXL_DESTROY_TIMEOUT 10
#define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
+#define LIBXL_QEMU_BODGE_TIMEOUT 2
#define LIBXL_XENCONSOLE_LIMIT 1048576
#define LIBXL_XENCONSOLE_PROTOCOL "vt100"
#define LIBXL_MAXMEM_CONSTANT 1024
@@ -350,6 +351,12 @@ typedef struct {
libxl__device_kind kind;
} libxl__device;
+/* Used to know if backend of given device is QEMU */
+#define QEMU_BACKEND(dev) (\
+ (dev)->backend_kind == LIBXL__DEVICE_KIND_QDISK || \
+ (dev)->backend_kind == LIBXL__DEVICE_KIND_VFB || \
+ (dev)->backend_kind == LIBXL__DEVICE_KIND_VKBD)
+
#define XC_PCI_BDF "0x%x, 0x%x, 0x%x, 0x%x"
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
@@ -899,13 +906,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.
@@ -2007,6 +2007,135 @@ _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;
+ /* Bodge for Qemu devices */
+ libxl__ev_time timeout;
+};
+
+/*
+ * Algorithm for handling device removal (including domain
+ * destruction). This is somewhat subtle because we may already have
+ * killed the domain and caused the death of qemu.
+ *
+ * In current versions of qemu there is no mechanism for ensuring that
+ * the resources used by its devices (both emulated and any PV devices
+ * provided by qemu) are freed (eg, fds closed) before it shuts down,
+ * and no confirmation from a terminating qemu back to the toolstack.
+ *
+ * This will need to be fixed in Xen 4.3. In the meantime (Xen 4.2)
+ * we implement a bodge.
+ *
+ * WE WANT TO UNPLUG WE WANT TO SHUT DOWN OR DESTROY
+ * | |
+ * | LIBXL SENDS SIGHUP TO QEMU
+ * | .....................|........................
+ * | : XEN 4.3+ PLANNED | :
+ * | : QEMU TEARS DOWN ALL DEVICES :
+ * | : FREES RESOURCES (closing fds) :
+ * | : SETS PV BACKENDS TO STATE 5, :
+ * | : waits for PV frontends to shut down :
+ * | : SETS PV BACKENDS TO STATE 6 :
+ * | : | :
+ * | : QEMU NOTIFIES TOOLSTACK (via :
+ * | : xenstore) that it is exiting :
+ * | : QEMU EXITS (parent may be init) :
+ * | : | :
+ * | : TOOLSTACK WAITS FOR QEMU :
+ * | : notices qemu has finished :
+ * | :....................|.......................:
+ * | .--------------------'
+ * V V
+ * for each device
+ * we want to unplug/remove
+ * ..................|...........................................
+ * : V XEN 4.2 RACY BODGE :
+ * : device is provided by qemu :
+ * : | `-----------. :
+ * : something| V :
+ * : else, eg| domain (that is domain for which :
+ * : blkback| this PV device is the backend, :
+ * : | which might be the stub dm) :
+ * : | is still alive? :
+ * : | | | :
+ * : | |alive |dead :
+ * : |<-----------------' | :
+ * : | hopefully qemu is | :
+ * : | still running | :
+ * :............|................. | :
+ * ,----->| : we may be racing :
+ * | backend state? : with qemu's death :
+ * ^ | | : | :
+ * xenstore| |other |6 : WAIT 2.0s :
+ * conflict| | | : TIMEOUT :
+ * | WRITE B.E. | : | :
+ * | STATE:=5 | : hopefully qemu has :
+ * `---' | | : gone by now and :
+ * |ok | : freed its resources :
+ * | | : | :
+ * WAIT FOR | : SET B.E. :
+ * STATE==6 | : STATE:=6 :
+ * / | | :..........|...................:
+ * timeout/ ok| | |
+ * / | | |
+ * | RUN HOTPLUG <-'<----------------'
+ * | SCRIPT
+ * | |
+ * `---> NUKE
+ * BACKEND
+ * |
+ * DONE.
+ */
+
+/* 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.
+ *
+ * Once finished, aodev->callback will be executed.
+ */
+_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 84909fff1d..3b03e5d928 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5415,7 +5415,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;
}
diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c
index c712b2bd01..53751b13a9 100644
--- a/tools/ocaml/libs/xl/xenlight_stubs.c
+++ b/tools/ocaml/libs/xl/xenlight_stubs.c
@@ -351,7 +351,7 @@ value stub_xl_device_vkb_destroy(value info, value domid)
device_vkb_val(&gc, &lg, &c_info, info);
INIT_CTX();
- ret = libxl_device_vkb_destroy(ctx, Int_val(domid), &c_info);
+ ret = libxl_device_vkb_destroy(ctx, Int_val(domid), &c_info, 0);
if (ret != 0)
failwith_xl("vkb_hard_shutdown", &lg);
FREE_CTX();
@@ -405,7 +405,7 @@ value stub_xl_device_vfb_destroy(value info, value domid)
device_vfb_val(&gc, &lg, &c_info, info);
INIT_CTX();
- ret = libxl_device_vfb_destroy(ctx, Int_val(domid), &c_info);
+ ret = libxl_device_vfb_destroy(ctx, Int_val(domid), &c_info, 0);
if (ret != 0)
failwith_xl("vfb_hard_shutdown", &lg);
FREE_CTX();