[libvirt] [PATCH 4/7] qemu: hotplug: Add support for signalling device unplug failure

Peter Krempa pkrempa at redhat.com
Tue Apr 5 15:09:20 UTC 2016


Similarly to the DEVICE_DELETED event we will be able to tell when
unplug of certain device types will be rejected by the guest OS. Wire up
the device deletion signalling code to allow handling this.
---
 src/qemu/qemu_domain.h  | 17 ++++++++++++++++-
 src/qemu/qemu_hotplug.c | 30 +++++++++++++++++++++---------
 src/qemu/qemu_hotplug.h |  3 ++-
 src/qemu/qemu_process.c |  2 +-
 4 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 2b92a90..84b4b16 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -148,6 +148,20 @@ struct qemuDomainJobObj {
 typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver,
                                           virDomainObjPtr vm);

+/* helper data types for async device unplug */
+typedef enum {
+    QEMU_DOMAIN_UNPLUG_DEVICE_STATUS_NONE = 0,
+    QEMU_DOMAIN_UNPLUG_DEVICE_STATUS_OK,
+    QEMU_DOMAIN_UNPLUG_DEVICE_STATUS_GUEST_REJECTED,
+} qemuDomainUnplugDeviceStatus;
+
+typedef struct _qemuDomainUnplugDevice qemuDomainUnplugDevice;
+typedef qemuDomainUnplugDevice *qemuDomainUnplugDevicePtr;
+struct _qemuDomainUnplugDevice {
+    const char *alias;
+    qemuDomainUnplugDeviceStatus status;
+};
+
 typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
 typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
 struct _qemuDomainObjPrivate {
@@ -198,7 +212,8 @@ struct _qemuDomainObjPrivate {

     virPerfPtr perf;

-    const char *unpluggingDevice; /* alias of the device that is being unplugged */
+    qemuDomainUnplugDevice unplug;
+
     char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */

     bool hookRun;  /* true if there was a hook run over this domain */
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 134f458..bd0599f 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3337,20 +3337,24 @@ qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;

-    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
-        priv->unpluggingDevice = info->alias;
-    else
-        priv->unpluggingDevice = NULL;
+    memset(&priv->unplug, 0, sizeof(priv->unplug));
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
+        return;
+
+    priv->unplug.alias = info->alias;
 }

 static void
 qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    priv->unpluggingDevice = NULL;
+    priv->unplug.alias = NULL;
 }

 /* Returns:
+ *  -1 Unplug of the device failed
+ *
  *   0 DEVICE_DELETED event is supported and removal of the device did not
  *     finish in qemuDomainRemoveDeviceWaitTime
  *
@@ -3373,17 +3377,23 @@ qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
         return 1;
     until += qemuDomainRemoveDeviceWaitTime;

-    while (priv->unpluggingDevice) {
+    while (priv->unplug.alias) {
         if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
             return 0;

         if (rc < 0) {
             VIR_WARN("Failed to wait on unplug condition for domain '%s' "
-                     "device '%s'", vm->def->name, priv->unpluggingDevice);
+                     "device '%s'", vm->def->name, priv->unplug.alias);
             return 1;
         }
     }

+    if (priv->unplug.status == QEMU_DOMAIN_UNPLUG_DEVICE_STATUS_GUEST_REJECTED) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("unplug of device was rejected by the guest"));
+        return -1;
+    }
+
     return 1;
 }

@@ -3395,12 +3405,14 @@ qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
  */
 bool
 qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
-                              const char *devAlias)
+                              const char *devAlias,
+                              qemuDomainUnplugDeviceStatus status)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;

-    if (STREQ_NULLABLE(priv->unpluggingDevice, devAlias)) {
+    if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
         qemuDomainResetDeviceRemoval(vm);
+        priv->unplug.status = status;
         virDomainObjBroadcast(vm);
         return true;
     }
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 4140da3..e6833f0 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -122,6 +122,7 @@ int qemuDomainRemoveDevice(virQEMUDriverPtr driver,
                            virDomainDeviceDefPtr dev);

 bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
-                                   const char *devAlias);
+                                   const char *devAlias,
+                                   qemuDomainUnplugDeviceStatus status);

 #endif /* __QEMU_HOTPLUG_H__ */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d9dca74..bbde32c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1359,7 +1359,7 @@ qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     VIR_DEBUG("Device %s removed from domain %p %s",
               devAlias, vm, vm->def->name);

-    if (qemuDomainSignalDeviceRemoval(vm, devAlias))
+    if (qemuDomainSignalDeviceRemoval(vm, devAlias, QEMU_DOMAIN_UNPLUG_DEVICE_STATUS_OK))
         goto cleanup;

     if (VIR_ALLOC(processEvent) < 0)
-- 
2.8.0




More information about the libvir-list mailing list