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@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list