From: Jovanka Gulicoska Date: Thu, 11 Aug 2016 15:15:23 +0000 (+0200) Subject: Introduce node device update event as top level event X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=43a6b37b24aef46588cfc319b25c615828b94fb2;p=libvirt.git Introduce node device update event as top level event This event is emitted when a nodedev XML definition is updated, like when cdrom media is changed in a cdrom block device. Also includes node device update event implementation for udev backend, virsh nodedev-event support, and event-test support --- diff --git a/daemon/remote.c b/daemon/remote.c index 9e75472ba8..155e9b047d 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1388,8 +1388,37 @@ remoteRelayNodeDeviceEventLifecycle(virConnectPtr conn, return 0; } +static int +remoteRelayNodeDeviceEventUpdate(virConnectPtr conn, + virNodeDevicePtr dev, + void *opaque) +{ + daemonClientEventCallbackPtr callback = opaque; + remote_node_device_event_update_msg data; + + if (callback->callbackID < 0 || + !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev)) + return -1; + + VIR_DEBUG("Relaying node device update event callback %d", + callback->callbackID); + + /* build return data */ + memset(&data, 0, sizeof(data)); + make_nonnull_node_device(&data.dev, dev); + data.callbackID = callback->callbackID; + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE, + (xdrproc_t)xdr_remote_node_device_event_update_msg, + &data); + + return 0; +} + static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = { VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle), + VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventUpdate), }; verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST); diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c index 2f9756ad4a..730cb8ba22 100644 --- a/examples/object-events/event-test.c +++ b/examples/object-events/event-test.c @@ -717,6 +717,17 @@ myNodeDeviceEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, } +static int +myNodeDeviceEventUpdateCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeDevicePtr dev, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Node device %s update\n", __func__, + virNodeDeviceGetName(dev)); + return 0; +} + + static void eventTypedParamsPrint(virTypedParameterPtr params, int nparams) @@ -989,6 +1000,7 @@ struct nodeDeviceEventData { struct nodeDeviceEventData nodeDeviceEvents[] = { NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventCallback), + NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback), }; /* make sure that the events are kept in sync */ diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index 4ab6917a9d..4ff8b416ae 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -138,6 +138,7 @@ int virNodeDeviceDestroy (virNodeDevicePtr dev); */ typedef enum { VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE = 0, /* virConnectNodeDeviceEventLifecycleCallback */ + VIR_NODE_DEVICE_EVENT_ID_UPDATE = 1, /* virConnectNodeDeviceEventUpdateCallback */ # ifdef VIR_ENUM_SENTINELS VIR_NODE_DEVICE_EVENT_ID_LAST diff --git a/src/conf/node_device_event.c b/src/conf/node_device_event.c index 61bc912723..312ef512d1 100644 --- a/src/conf/node_device_event.c +++ b/src/conf/node_device_event.c @@ -48,10 +48,20 @@ struct _virNodeDeviceEventLifecycle { typedef struct _virNodeDeviceEventLifecycle virNodeDeviceEventLifecycle; typedef virNodeDeviceEventLifecycle *virNodeDeviceEventLifecyclePtr; +struct _virNodeDeviceEventUpdate { + virNodeDeviceEvent parent; + + bool dummy; +}; +typedef struct _virNodeDeviceEventUpdate virNodeDeviceEventUpdate; +typedef virNodeDeviceEventUpdate *virNodeDeviceEventUpdatePtr; + static virClassPtr virNodeDeviceEventClass; static virClassPtr virNodeDeviceEventLifecycleClass; +static virClassPtr virNodeDeviceEventUpdateClass; static void virNodeDeviceEventDispose(void *obj); static void virNodeDeviceEventLifecycleDispose(void *obj); +static void virNodeDeviceEventUpdateDispose(void *obj); static int virNodeDeviceEventsOnceInit(void) @@ -68,6 +78,12 @@ virNodeDeviceEventsOnceInit(void) sizeof(virNodeDeviceEventLifecycle), virNodeDeviceEventLifecycleDispose))) return -1; + if (!(virNodeDeviceEventUpdateClass = + virClassNew(virNodeDeviceEventClass, + "virNodeDeviceEventUpdate", + sizeof(virNodeDeviceEventUpdate), + virNodeDeviceEventUpdateDispose))) + return -1; return 0; } @@ -89,6 +105,14 @@ virNodeDeviceEventLifecycleDispose(void *obj) } +static void +virNodeDeviceEventUpdateDispose(void *obj) +{ + virNodeDeviceEventUpdatePtr event = obj; + VIR_DEBUG("obj=%p", event); +} + + static void virNodeDeviceEventDispatchDefaultFunc(virConnectPtr conn, virObjectEventPtr event, @@ -114,6 +138,13 @@ virNodeDeviceEventDispatchDefaultFunc(virConnectPtr conn, goto cleanup; } + case VIR_NODE_DEVICE_EVENT_ID_UPDATE: + { + ((virConnectNodeDeviceEventGenericCallback)cb)(conn, dev, + cbopaque); + goto cleanup; + } + case VIR_NODE_DEVICE_EVENT_ID_LAST: break; } @@ -232,3 +263,27 @@ virNodeDeviceEventLifecycleNew(const char *name, return (virObjectEventPtr)event; } + + +/** + * virNodeDeviceEventUpdateNew: + * @name: name of the node device object the event describes + * + * Create a new node device update event. + */ +virObjectEventPtr +virNodeDeviceEventUpdateNew(const char *name) +{ + virNodeDeviceEventUpdatePtr event; + + if (virNodeDeviceEventsInitialize() < 0) + return NULL; + + if (!(event = virObjectEventNew(virNodeDeviceEventUpdateClass, + virNodeDeviceEventDispatchDefaultFunc, + VIR_NODE_DEVICE_EVENT_ID_UPDATE, + 0, name, NULL, name))) + return NULL; + + return (virObjectEventPtr)event; +} diff --git a/src/conf/node_device_event.h b/src/conf/node_device_event.h index 9c99633d6d..5a32d33abe 100644 --- a/src/conf/node_device_event.h +++ b/src/conf/node_device_event.h @@ -56,4 +56,7 @@ virNodeDeviceEventLifecycleNew(const char *name, int type, int detail); +virObjectEventPtr +virNodeDeviceEventUpdateNew(const char *name); + #endif diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 419c33d677..a32ce1c586 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -687,6 +687,7 @@ virNodeDeviceObjUnlock; # conf/node_device_event.h virNodeDeviceEventLifecycleNew; virNodeDeviceEventStateRegisterID; +virNodeDeviceEventUpdateNew; # conf/numa_conf.h diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 4182d5b2c9..ddf3d8868e 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1147,6 +1147,8 @@ static int udevAddOneDevice(struct udev_device *device) event = virNodeDeviceEventLifecycleNew(dev->def->name, VIR_NODE_DEVICE_EVENT_CREATED, 0); + else + event = virNodeDeviceEventUpdateNew(dev->def->name); virNodeDeviceObjUnlock(dev); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 6637a1d043..68b843442f 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -374,6 +374,11 @@ remoteNodeDeviceBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED virNetClientPtr client ATTRIBUTE_UNUSED, void *evdata, void *opaque); +static void +remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque); + static void remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, @@ -565,6 +570,10 @@ static virNetClientProgramEvent remoteEvents[] = { remoteNodeDeviceBuildEventLifecycle, sizeof(remote_node_device_event_lifecycle_msg), (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg }, + { REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE, + remoteNodeDeviceBuildEventUpdate, + sizeof(remote_node_device_event_update_msg), + (xdrproc_t)xdr_remote_node_device_event_update_msg }, }; static void @@ -5285,6 +5294,27 @@ remoteNodeDeviceBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED remoteEventQueue(priv, event, msg->callbackID); } +static void +remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_node_device_event_update_msg *msg = evdata; + virNodeDevicePtr dev; + virObjectEventPtr event = NULL; + + dev = get_nonnull_node_device(conn, msg->dev); + if (!dev) + return; + + event = virNodeDeviceEventUpdateNew(dev->name); + virObjectUnref(dev); + + remoteEventQueue(priv, event, msg->callbackID); +} + static void remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index b4fd057fd7..49db0717ef 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3151,6 +3151,11 @@ struct remote_node_device_event_lifecycle_msg { int detail; }; +struct remote_node_device_event_update_msg { + int callbackID; + remote_nonnull_node_device dev; +}; + struct remote_domain_fsfreeze_args { remote_nonnull_domain dom; remote_nonnull_string mountpoints; /* (const char **) */ @@ -5923,5 +5928,11 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376 + REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 24401d1f74..4552913271 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2587,6 +2587,10 @@ struct remote_node_device_event_lifecycle_msg { int event; int detail; }; +struct remote_node_device_event_update_msg { + int callbackID; + remote_nonnull_node_device dev; +}; struct remote_domain_fsfreeze_args { remote_nonnull_domain dom; struct { @@ -3164,4 +3168,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY = 374, REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY = 375, REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376, + REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377, }; diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index d3d3fc11fc..7676dcc486 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -756,19 +756,21 @@ virshNodeDeviceEventToString(int event) return str ? _(str) : _("unknown"); } +struct vshEventCallback { + const char *name; + virConnectNodeDeviceEventGenericCallback cb; +}; +typedef struct vshEventCallback vshEventCallback; + struct virshNodeDeviceEventData { vshControl *ctl; bool loop; bool timestamp; int count; + vshEventCallback *cb; }; typedef struct virshNodeDeviceEventData virshNodeDeviceEventData; -VIR_ENUM_DECL(virshNodeDeviceEventId) -VIR_ENUM_IMPL(virshNodeDeviceEventId, - VIR_NODE_DEVICE_EVENT_ID_LAST, - "lifecycle") - static void vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeDevicePtr dev, @@ -800,6 +802,45 @@ vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, vshEventDone(data->ctl); } +static void +vshEventGenericPrint(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeDevicePtr dev, + void *opaque) +{ + virshNodeDeviceEventData *data = opaque; + + if (!data->loop && data->count) + return; + + if (data->timestamp) { + char timestamp[VIR_TIME_STRING_BUFLEN]; + + if (virTimeStringNowRaw(timestamp) < 0) + timestamp[0] = '\0'; + + vshPrint(data->ctl, _("%s: event '%s'' for node device %s\n"), + timestamp, + data->cb->name, + virNodeDeviceGetName(dev)); + } else { + vshPrint(data->ctl, _("event '%s' for node device %s\n"), + data->cb->name, + virNodeDeviceGetName(dev)); + } + + data->count++; + if (!data->loop) + vshEventDone(data->ctl); +} + +static vshEventCallback vshEventCallbacks[] = { + { "lifecycle", + VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), }, + { "update", vshEventGenericPrint, } +}; +verify(VIR_NODE_DEVICE_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks)); + + static const vshCmdInfo info_node_device_event[] = { {.name = "help", .data = N_("Node Device Events") @@ -855,7 +896,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd) size_t i; for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++) - vshPrint(ctl, "%s\n", virshNodeDeviceEventIdTypeToString(i)); + vshPrint(ctl, "%s\n", vshEventCallbacks[i].name); return true; } @@ -865,7 +906,11 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd) vshError(ctl, "%s", _("either --list or event type is required")); return false; } - if ((event = virshNodeDeviceEventIdTypeFromString(eventName)) < 0) { + + for (event = 0; event < VIR_NODE_DEVICE_EVENT_ID_LAST; event++) + if (STREQ(eventName, vshEventCallbacks[event].name)) + break; + if (event == VIR_NODE_DEVICE_EVENT_ID_LAST) { vshError(ctl, _("unknown event type %s"), eventName); return false; } @@ -874,6 +919,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd) data.loop = vshCommandOptBool(cmd, "loop"); data.timestamp = vshCommandOptBool(cmd, "timestamp"); data.count = 0; + data.cb = &vshEventCallbacks[event]; if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) return false; if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) @@ -890,7 +936,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd) goto cleanup; if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event, - VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), + data.cb->cb, &data, NULL)) < 0) goto cleanup; switch (vshEventWait(ctl)) {