diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-nodedev.h index cd0b5486fc7b6b55ed65f232d25fc09d5f4881ef..4ab6917a9dad4a619d0ba726af9d129d3343241b 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -121,5 +121,95 @@ virNodeDevicePtr virNodeDeviceCreateXML (virConnectPtr conn, int virNodeDeviceDestroy (virNodeDevicePtr dev); +/** + * VIR_NODE_DEVICE_EVENT_CALLBACK: + * + * Used to cast the event specific callback into the generic one + * for use for virConnectNodeDeviceEventRegisterAny() + */ +# define VIR_NODE_DEVICE_EVENT_CALLBACK(cb)((virConnectNodeDeviceEventGenericCallback)(cb)) + +/** + * virNodeDeviceEventID: + * + * An enumeration of supported eventId parameters for + * virConnectNodeDeviceEventRegisterAny(). Each event id determines which + * signature of callback function will be used. + */ +typedef enum { + VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE = 0, /* virConnectNodeDeviceEventLifecycleCallback */ + +# ifdef VIR_ENUM_SENTINELS + VIR_NODE_DEVICE_EVENT_ID_LAST + /* + * NB: this enum value will increase over time as new events are + * added to the libvirt API. It reflects the last event ID supported + * by this version of the libvirt API. + */ +# endif +} virNodeDeviceEventID; + +/** + * virConnectNodeDeviceEventGenericCallback: + * @conn: the connection pointer + * @dev: the node device pointer + * @opaque: application specified data + * + * A generic node device event callback handler, for use with + * virConnectNodeDeviceEventRegisterAny(). Specific events usually + * have a customization with extra parameters, often with @opaque being + * passed in a different parameter position; use + * VIR_NODE_DEVICE_EVENT_CALLBACK() when registering an appropriate handler. + */ +typedef void (*virConnectNodeDeviceEventGenericCallback)(virConnectPtr conn, + virNodeDevicePtr dev, + void *opaque); + +/* Use VIR_NODE_DEVICE_EVENT_CALLBACK() to cast the 'cb' parameter */ +int virConnectNodeDeviceEventRegisterAny(virConnectPtr conn, + virNodeDevicePtr dev, /* optional, to filter */ + int eventID, + virConnectNodeDeviceEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +int virConnectNodeDeviceEventDeregisterAny(virConnectPtr conn, + int callbackID); + +/** + * virNodeDeviceEventLifecycleType: + * + * a virNodeDeviceEventLifecycleType is emitted during node device + * lifecycle events + */ +typedef enum { + VIR_NODE_DEVICE_EVENT_CREATED = 0, + VIR_NODE_DEVICE_EVENT_DELETED = 1, + +# ifdef VIR_ENUM_SENTINELS + VIR_NODE_DEVICE_EVENT_LAST +# endif +} virNodeDeviceEventLifecycleType; + +/** + * virConnectNodeDeviceEventLifecycleCallback: + * @conn: connection object + * @dev: node device on which the event occurred + * @event: The specific virNodeDeviceEventLifeCycleType which occurred + * @detail: contains some details on the reason of the event. + * @opaque: application specified data + * + * This callback is called when a node device lifecycle action is performed, + * like added or removed. + * + * The callback signature to use when registering for an event of type + * VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE with + * virConnectNodeDeviceEventRegisterAny() + */ +typedef void (*virConnectNodeDeviceEventLifecycleCallback)(virConnectPtr conn, + virNodeDevicePtr dev, + int event, + int detail, + void *opaque); #endif /* __VIR_LIBVIRT_NODEDEV_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index a6b6c9cf124c8b862ec7d49284ee75e4e4bdbfb4..25dbc842d866c607c8da4efefd23a83925ae5c60 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -70,6 +70,7 @@ src/libvirt-domain.c src/libvirt-host.c src/libvirt-lxc.c src/libvirt-network.c +src/libvirt-nodedev.c src/libvirt-nwfilter.c src/libvirt-qemu.c src/libvirt-secret.c diff --git a/src/datatypes.h b/src/datatypes.h index 996506b6d57adfe047eca1562c6cdb204a4970d3..2b6adb4c45b0703cd16f58e392040d43fb0d0984 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -196,6 +196,19 @@ extern virClassPtr virAdmClientClass; } \ } while (0) +# define virCheckNodeDeviceGoto(obj, label) \ + do { \ + virNodeDevicePtr _dev= (obj); \ + if (!virObjectIsClass(_dev, virNodeDeviceClass) || \ + !virObjectIsClass(_dev->conn, virConnectClass)) { \ + virReportErrorHelper(VIR_FROM_NODEDEV, \ + VIR_ERR_INVALID_NODE_DEVICE, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + # define virCheckSecretReturn(obj, retval) \ do { \ virSecretPtr _secret = (obj); \ diff --git a/src/driver-nodedev.h b/src/driver-nodedev.h index e846612d3179cf4ed8bc232e2d5096445c230c20..5eae2391c7145fec19bd9a6a4d73d843b21305ed 100644 --- a/src/driver-nodedev.h +++ b/src/driver-nodedev.h @@ -75,6 +75,18 @@ typedef virNodeDevicePtr typedef int (*virDrvNodeDeviceDestroy)(virNodeDevicePtr dev); +typedef int +(*virDrvConnectNodeDeviceEventRegisterAny)(virConnectPtr conn, + virNodeDevicePtr dev, + int eventID, + virConnectNodeDeviceEventGenericCallback cb, + void *opaque, + virFreeCallback freecb); + +typedef int +(*virDrvConnectNodeDeviceEventDeregisterAny)(virConnectPtr conn, + int callbackID); + typedef struct _virNodeDeviceDriver virNodeDeviceDriver; @@ -92,6 +104,8 @@ struct _virNodeDeviceDriver { virDrvNodeNumOfDevices nodeNumOfDevices; virDrvNodeListDevices nodeListDevices; virDrvConnectListAllNodeDevices connectListAllNodeDevices; + virDrvConnectNodeDeviceEventRegisterAny connectNodeDeviceEventRegisterAny; + virDrvConnectNodeDeviceEventDeregisterAny connectNodeDeviceEventDeregisterAny; virDrvNodeDeviceLookupByName nodeDeviceLookupByName; virDrvNodeDeviceLookupSCSIHostByWWN nodeDeviceLookupSCSIHostByWWN; virDrvNodeDeviceGetXMLDesc nodeDeviceGetXMLDesc; diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c index c1ca5750511a5f025106bd024893442de8707bd8..e4e98368ff79d9d7eb928bd34c3cefb9804b11d4 100644 --- a/src/libvirt-nodedev.c +++ b/src/libvirt-nodedev.c @@ -753,3 +753,130 @@ virNodeDeviceDestroy(virNodeDevicePtr dev) virDispatchError(dev->conn); return -1; } + + +/** + * virConnectNodeDeviceEventRegisterAny: + * @conn: pointer to the connection + * @dev: pointer to the node device + * @eventID: the event type to receive + * @cb: callback to the function handling node device events + * @opaque: opaque data to pass on to the callback + * @freecb: optional function to deallocate opaque when not used anymore + * + * Adds a callback to receive notifications of arbitrary node device events + * occurring on a node device. This function requires that an event loop + * has been previously registered with virEventRegisterImpl() or + * virEventRegisterDefaultImpl(). + * + * If @dev is NULL, then events will be monitored for any node device. + * If @dev is non-NULL, then only the specific node device will be monitored. + * + * Most types of events have a callback providing a custom set of parameters + * for the event. When registering an event, it is thus necessary to use + * the VIR_NODE_DEVICE_EVENT_CALLBACK() macro to cast the + * supplied function pointer to match the signature of this method. + * + * The virNodeDevicePtr object handle passed into the callback upon delivery + * of an event is only valid for the duration of execution of the callback. + * If the callback wishes to keep the node device object after the callback + * returns, it shall take a reference to it, by calling virNodeDeviceRef(). + * The reference can be released once the object is no longer required + * by calling virNodeDeviceFree(). + * + * The return value from this method is a positive integer identifier + * for the callback. To unregister a callback, this callback ID should + * be passed to the virConnectNodeDeviceEventDeregisterAny() method. + * + * Returns a callback identifier on success, -1 on failure. + */ +int +virConnectNodeDeviceEventRegisterAny(virConnectPtr conn, + virNodeDevicePtr dev, + int eventID, + virConnectNodeDeviceEventGenericCallback cb, + void *opaque, + virFreeCallback freecb) +{ + VIR_DEBUG("conn=%p, nodeDevice=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p", + conn, dev, eventID, cb, opaque, freecb); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + if (dev) { + virCheckNodeDeviceGoto(dev, error); + if (dev->conn != conn) { + virReportInvalidArg(dev, + _("node device '%s' in %s must match connection"), + dev->name, __FUNCTION__); + goto error; + } + } + virCheckNonNullArgGoto(cb, error); + virCheckNonNegativeArgGoto(eventID, error); + + if (eventID >= VIR_NODE_DEVICE_EVENT_ID_LAST) { + virReportInvalidArg(eventID, + _("eventID in %s must be less than %d"), + __FUNCTION__, VIR_NODE_DEVICE_EVENT_ID_LAST); + goto error; + } + + if (conn->nodeDeviceDriver && + conn->nodeDeviceDriver->connectNodeDeviceEventRegisterAny) { + int ret; + ret = conn->nodeDeviceDriver->connectNodeDeviceEventRegisterAny(conn, + dev, + eventID, + cb, + opaque, + freecb); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(conn); + return -1; +} + + +/** + * virConnectNodeDeviceEventDeregisterAny: + * @conn: pointer to the connection + * @callbackID: the callback identifier + * + * Removes an event callback. The callbackID parameter should be the + * value obtained from a previous virConnectNodeDeviceEventRegisterAny() method. + * + * Returns 0 on success, -1 on failure. + */ +int +virConnectNodeDeviceEventDeregisterAny(virConnectPtr conn, + int callbackID) +{ + VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); + + virResetLastError(); + + virCheckConnectReturn(conn, -1); + virCheckNonNegativeArgGoto(callbackID, error); + + if (conn->nodeDeviceDriver && + conn->nodeDeviceDriver->connectNodeDeviceEventDeregisterAny) { + int ret; + ret = conn->nodeDeviceDriver->connectNodeDeviceEventDeregisterAny(conn, + callbackID); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b6d2dfdba3271211561772ea4b708946f98b1ea4..e01604cad8540ef1e8604e3ad6b089b368bb2146 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -740,4 +740,10 @@ LIBVIRT_2.0.0 { virDomainSetGuestVcpus; } LIBVIRT_1.3.3; +LIBVIRT_2.2.0 { + global: + virConnectNodeDeviceEventRegisterAny; + virConnectNodeDeviceEventDeregisterAny; +} LIBVIRT_2.0.0; + # .... define new API here using predicted next version number ....