Since we didn't opt to use one single event for device lifecycle for a
VM we are missing one last event if the device removal failed. This
event will be emitted once we asked to eject the device but for some
reason it is not possible.
---
 daemon/remote.c                  | 36 +++++++++++++++++
 include/libvirt/libvirt-domain.h | 21 ++++++++++
 src/conf/domain_event.c          | 84 ++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_event.h          |  7 ++++
 src/libvirt_private.syms         |  2 +
 src/remote/remote_driver.c       | 30 ++++++++++++++
 src/remote/remote_protocol.x     | 14 ++++++-
 src/remote_protocol-structs      |  6 +++
 tools/virsh-domain.c             | 18 +++++++++
 9 files changed, 217 insertions(+), 1 deletion(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 9db93ff..fde029d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1136,6 +1136,41 @@ remoteRelayDomainEventJobCompleted(virConnectPtr conn,
 }


+static int
+remoteRelayDomainEventDeviceRemovalFailed(virConnectPtr conn,
+                                          virDomainPtr dom,
+                                          const char *devAlias,
+                                          void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_domain_event_callback_device_removal_failed_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+        return -1;
+
+    VIR_DEBUG("Relaying domain device removal failed event %s %d %s, callback 
%d",
+              dom->name, dom->id, devAlias, callback->callbackID);
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+
+    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
+        return -1;
+
+    make_nonnull_domain(&data.dom, dom);
+    data.callbackID = callback->callbackID;
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  
REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED,
+                                  
(xdrproc_t)xdr_remote_domain_event_callback_device_removal_failed_msg,
+                                  &data);
+
+    return 0;
+}
+
+
+
 static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -1159,6 +1194,7 @@ static virConnectDomainEventGenericCallback 
domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
 };

 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 728b6eb..8220ab0 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3342,6 +3342,26 @@ typedef void 
(*virConnectDomainEventDeviceAddedCallback)(virConnectPtr conn,
                                                          const char *devAlias,
                                                          void *opaque);

+
+/**
+ * virConnectDomainEventDeviceRemovalFailedCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @devAlias: device alias
+ * @opaque: application specified data
+ *
+ * This callback occurs when it's certain that removal of a device failed.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED with
+ * virConnectDomainEventRegisterAny().
+ */
+typedef void (*virConnectDomainEventDeviceRemovalFailedCallback)(virConnectPtr 
conn,
+                                                                 virDomainPtr 
dom,
+                                                                 const char 
*devAlias,
+                                                                 void *opaque);
+
+
 /**
  * virConnectDomainEventMigrationIterationCallback:
  * @conn: connection object
@@ -3687,6 +3707,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_DEVICE_ADDED = 19,   /* 
virConnectDomainEventDeviceAddedCallback */
     VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION = 20, /* 
virConnectDomainEventMigrationIterationCallback */
     VIR_DOMAIN_EVENT_ID_JOB_COMPLETED = 21,  /* 
virConnectDomainEventJobCompletedCallback */
+    VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* 
virConnectDomainEventDeviceRemovalFailedCallback */

 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index a9107e5..58823e8 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -58,6 +58,7 @@ static virClassPtr virDomainEventAgentLifecycleClass;
 static virClassPtr virDomainEventDeviceAddedClass;
 static virClassPtr virDomainEventMigrationIterationClass;
 static virClassPtr virDomainEventJobCompletedClass;
+static virClassPtr virDomainEventDeviceRemovalFailedClass;

 static void virDomainEventDispose(void *obj);
 static void virDomainEventLifecycleDispose(void *obj);
@@ -77,6 +78,7 @@ static void virDomainEventAgentLifecycleDispose(void *obj);
 static void virDomainEventDeviceAddedDispose(void *obj);
 static void virDomainEventMigrationIterationDispose(void *obj);
 static void virDomainEventJobCompletedDispose(void *obj);
+static void virDomainEventDeviceRemovalFailedDispose(void *obj);

 static void
 virDomainEventDispatchDefaultFunc(virConnectPtr conn,
@@ -256,6 +258,16 @@ struct _virDomainEventJobCompleted {
 typedef struct _virDomainEventJobCompleted virDomainEventJobCompleted;
 typedef virDomainEventJobCompleted *virDomainEventJobCompletedPtr;

+struct _virDomainEventDeviceRemovalFailed {
+    virDomainEvent parent;
+
+    char *devAlias;
+};
+typedef struct _virDomainEventDeviceRemovalFailed 
virDomainEventDeviceRemovalFailed;
+typedef virDomainEventDeviceRemovalFailed 
*virDomainEventDeviceRemovalFailedPtr;
+
+
+
 static int
 virDomainEventsOnceInit(void)
 {
@@ -367,6 +379,12 @@ virDomainEventsOnceInit(void)
                       sizeof(virDomainEventJobCompleted),
                       virDomainEventJobCompletedDispose)))
         return -1;
+    if (!(virDomainEventDeviceRemovalFailedClass =
+          virClassNew(virDomainEventClass,
+                      "virDomainEventDeviceRemovalFailed",
+                      sizeof(virDomainEventDeviceRemovalFailed),
+                      virDomainEventDeviceRemovalFailedDispose)))
+        return -1;
     return 0;
 }

@@ -494,6 +512,17 @@ virDomainEventDeviceAddedDispose(void *obj)
     VIR_FREE(event->devAlias);
 }

+
+static void
+virDomainEventDeviceRemovalFailedDispose(void *obj)
+{
+    virDomainEventDeviceRemovalFailedPtr event = obj;
+    VIR_DEBUG("obj=%p", event);
+
+    VIR_FREE(event->devAlias);
+}
+
+
 static void
 virDomainEventPMDispose(void *obj)
 {
@@ -1340,6 +1369,50 @@ virDomainEventDeviceAddedNewFromDom(virDomainPtr dom,
                                           devAlias);
 }

+
+static virObjectEventPtr
+virDomainEventDeviceRemovalFailedNew(int id,
+                                     const char *name,
+                                     unsigned char *uuid,
+                                     const char *devAlias)
+{
+    virDomainEventDeviceRemovalFailedPtr ev;
+
+    if (virDomainEventsInitialize() < 0)
+        return NULL;
+
+    if (!(ev = virDomainEventNew(virDomainEventDeviceAddedClass,
+                                 VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED,
+                                 id, name, uuid)))
+        return NULL;
+
+    if (VIR_STRDUP(ev->devAlias, devAlias) < 0)
+        goto error;
+
+    return (virObjectEventPtr)ev;
+
+ error:
+    virObjectUnref(ev);
+    return NULL;
+}
+
+virObjectEventPtr
+virDomainEventDeviceRemovalFailedNewFromObj(virDomainObjPtr obj,
+                                            const char *devAlias)
+{
+    return virDomainEventDeviceRemovalFailedNew(obj->def->id, obj->def->name,
+                                                obj->def->uuid, devAlias);
+}
+
+virObjectEventPtr
+virDomainEventDeviceRemovalFailedNewFromDom(virDomainPtr dom,
+                                            const char *devAlias)
+{
+    return virDomainEventDeviceRemovalFailedNew(dom->id, dom->name, dom->uuid,
+                                                devAlias);
+}
+
+
 static virObjectEventPtr
 virDomainEventAgentLifecycleNew(int id,
                                 const char *name,
@@ -1768,6 +1841,17 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
             goto cleanup;
         }

+    case VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED:
+        {
+            virDomainEventDeviceRemovalFailedPtr deviceRemovalFailedEvent;
+
+            deviceRemovalFailedEvent = 
(virDomainEventDeviceRemovalFailedPtr)event;
+            ((virConnectDomainEventDeviceRemovalFailedCallback)cb)(conn, dom,
+                                                                   
deviceRemovalFailedEvent->devAlias,
+                                                                   cbopaque);
+            goto cleanup;
+        }
+
     case VIR_DOMAIN_EVENT_ID_LAST:
         break;
     }
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 3eb13c8..54fa879 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -191,6 +191,13 @@ virObjectEventPtr
 virDomainEventDeviceAddedNewFromDom(virDomainPtr dom,
                                     const char *devAlias);
 virObjectEventPtr
+virDomainEventDeviceRemovalFailedNewFromObj(virDomainObjPtr obj,
+                                            const char *devAlias);
+virObjectEventPtr
+virDomainEventDeviceRemovalFailedNewFromDom(virDomainPtr dom,
+                                            const char *devAlias);
+
+virObjectEventPtr
 virDomainEventTunableNewFromObj(virDomainObjPtr obj,
                                 virTypedParameterPtr params,
                                 int nparams);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 684f06c..aff8622 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -496,6 +496,8 @@ virDomainEventControlErrorNewFromDom;
 virDomainEventControlErrorNewFromObj;
 virDomainEventDeviceAddedNewFromDom;
 virDomainEventDeviceAddedNewFromObj;
+virDomainEventDeviceRemovalFailedNewFromDom;
+virDomainEventDeviceRemovalFailedNewFromObj;
 virDomainEventDeviceRemovedNewFromDom;
 virDomainEventDeviceRemovedNewFromObj;
 virDomainEventDiskChangeNewFromDom;
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index b03c9ca..da94411 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -322,6 +322,10 @@ static void
 remoteDomainBuildEventCallbackDeviceAdded(virNetClientProgramPtr prog,
                                           virNetClientPtr client,
                                           void *evdata, void *opaque);
+static void
+remoteDomainBuildEventCallbackDeviceRemovalFailed(virNetClientProgramPtr prog,
+                                                  virNetClientPtr client,
+                                                  void *evdata, void *opaque);

 static void
 remoteDomainBuildEventBlockJob2(virNetClientProgramPtr prog,
@@ -528,6 +532,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteDomainBuildEventCallbackJobCompleted,
       sizeof(remote_domain_event_callback_job_completed_msg),
       (xdrproc_t)xdr_remote_domain_event_callback_job_completed_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED,
+      remoteDomainBuildEventCallbackDeviceRemovalFailed,
+      sizeof(remote_domain_event_callback_device_removal_failed_msg),
+      (xdrproc_t)xdr_remote_domain_event_callback_device_removal_failed_msg },
 };

 static void
@@ -4829,6 +4837,28 @@ 
remoteDomainBuildEventCallbackDeviceAdded(virNetClientProgramPtr prog ATTRIBUTE_
     remoteEventQueue(priv, event, msg->callbackID);
 }

+
+static void
+remoteDomainBuildEventCallbackDeviceRemovalFailed(virNetClientProgramPtr prog 
ATTRIBUTE_UNUSED,
+                                                  virNetClientPtr client 
ATTRIBUTE_UNUSED,
+                                                  void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    remote_domain_event_callback_device_added_msg *msg = evdata;
+    struct private_data *priv = conn->privateData;
+    virDomainPtr dom;
+    virObjectEventPtr event = NULL;
+
+    if (!(dom = get_nonnull_domain(conn, msg->dom)))
+        return;
+
+    event = virDomainEventDeviceRemovalFailedNewFromDom(dom, msg->devAlias);
+
+    virObjectUnref(dom);
+
+    remoteEventQueue(priv, event, msg->callbackID);
+}
+
 static void
 remoteDomainBuildEventCallbackTunable(virNetClientProgramPtr prog 
ATTRIBUTE_UNUSED,
                                       virNetClientPtr client ATTRIBUTE_UNUSED,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 8bda792..bab8ef2 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3261,6 +3261,12 @@ struct remote_domain_migrate_start_post_copy_args {
     unsigned int flags;
 };

+struct remote_domain_event_callback_device_removal_failed_msg {
+    int callbackID;
+    remote_nonnull_domain dom;
+    remote_nonnull_string devAlias;
+};
+
 /*----- Protocol. -----*/

 /* Define the program number, protocol version and procedure numbers here. */
@@ -5781,5 +5787,11 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:write
      */
-    REMOTE_PROC_DOMAIN_SET_PERF_EVENTS = 366
+    REMOTE_PROC_DOMAIN_SET_PERF_EVENTS = 366,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED = 367
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 6dddd52..fe1b8a8 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2730,6 +2730,11 @@ struct remote_domain_migrate_start_post_copy_args {
         remote_nonnull_domain      dom;
         u_int                      flags;
 };
+struct remote_domain_event_callback_device_removal_failed_msg {
+        int                        callbackID;
+        remote_nonnull_domain      dom;
+        remote_nonnull_string      devAlias;
+};
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3097,4 +3102,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_MIGRATE_START_POST_COPY = 364,
         REMOTE_PROC_DOMAIN_GET_PERF_EVENTS = 365,
         REMOTE_PROC_DOMAIN_SET_PERF_EVENTS = 366,
+        REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED = 367,
 };
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 36d0353..6d4265c 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -12301,6 +12301,22 @@ virshEventJobCompletedPrint(virConnectPtr conn 
ATTRIBUTE_UNUSED,
     virshEventPrint(opaque, &buf);
 }

+
+static void
+virshEventDeviceRemovalFailedPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                   virDomainPtr dom,
+                                   const char *alias,
+                                   void *opaque)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAsprintf(&buf, _("event 'device-removal-failed' for domain %s: 
%s\n"),
+                      virDomainGetName(dom),
+                      alias);
+    virshEventPrint(opaque, &buf);
+}
+
+
 static vshEventCallback vshEventCallbacks[] = {
     { "lifecycle",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
@@ -12344,6 +12360,8 @@ static vshEventCallback vshEventCallbacks[] = {
       VIR_DOMAIN_EVENT_CALLBACK(virshEventMigrationIterationPrint), },
     { "job-completed",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
+    { "device-removal-failed",
+      VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
 };
 verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));

-- 
2.8.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to