size_t nqemuEventCallbacks;
daemonClientEventCallbackPtr *storageEventCallbacks;
size_t nstorageEventCallbacks;
+ daemonClientEventCallbackPtr *nodeDeviceEventCallbacks;
+ size_t nnodeDeviceEventCallbacks;
bool closeRegistered;
# if WITH_SASL
static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret);
static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot);
+static virNodeDevicePtr get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev);
static void make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
static void make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src);
static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
return ret;
}
+static bool
+remoteRelayNodeDeviceEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn,
+ virNodeDevicePtr dev)
+{
+ virNodeDeviceDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virNodeDeviceDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ def.name = dev->name;
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectNodeDeviceEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
static bool
remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
virConnectPtr conn, virDomainPtr dom)
verify(ARRAY_CARDINALITY(storageEventCallbacks) == VIR_STORAGE_POOL_EVENT_ID_LAST);
+static int
+remoteRelayNodeDeviceEventLifecycle(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_node_device_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
+ return -1;
+
+ VIR_DEBUG("Relaying node device lifecycle event %d, detail %d, callback %d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_node_device(&data.dev, dev);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = {
+ VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle),
+};
+
+verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST);
+
static void
remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
virDomainPtr dom,
}
VIR_FREE(priv->storageEventCallbacks);
+ for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {
+ int callbackID = priv->nodeDeviceEventCallbacks[i]->callbackID;
+ if (callbackID < 0) {
+ VIR_WARN("unexpected incomplete node device callback %zu", i);
+ continue;
+ }
+ VIR_DEBUG("Deregistering remote node device event relay %d",
+ callbackID);
+ priv->nodeDeviceEventCallbacks[i]->callbackID = -1;
+ if (virConnectNodeDeviceEventDeregisterAny(priv->conn,
+ callbackID) < 0)
+ VIR_WARN("unexpected node device event deregister failure");
+ }
+ VIR_FREE(priv->nodeDeviceEventCallbacks);
+
for (i = 0; i < priv->nqemuEventCallbacks; i++) {
int callbackID = priv->qemuEventCallbacks[i]->callbackID;
if (callbackID < 0) {
return rv;
}
+static int
+remoteDispatchConnectNodeDeviceEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_node_device_event_register_any_args *args,
+ remote_connect_node_device_event_register_any_ret *ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virNodeDevicePtr dev = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->dev &&
+ !(dev = get_nonnull_node_device(priv->conn, *args->dev)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_NODE_DEVICE_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported node device event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = client;
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->nodeDeviceEventCallbacks,
+ priv->nnodeDeviceEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectNodeDeviceEventRegisterAny(priv->conn,
+ dev,
+ args->eventID,
+ nodeDeviceEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0) {
+ VIR_SHRINK_N(priv->nodeDeviceEventCallbacks,
+ priv->nnodeDeviceEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ VIR_FREE(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(dev);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectNodeDeviceEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_node_device_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {
+ if (priv->nodeDeviceEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nnodeDeviceEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("node device event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectNodeDeviceEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->nodeDeviceEventCallbacks, i,
+ priv->nnodeDeviceEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
static int
qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
return virGetDomainSnapshot(dom, snapshot.name);
}
+static virNodeDevicePtr
+get_nonnull_node_device(virConnectPtr conn, remote_nonnull_node_device dev)
+{
+ return virGetNodeDevice(conn, dev.name);
+}
+
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
#include "domain_event.h"
#include "network_event.h"
#include "storage_event.h"
+#include "node_device_event.h"
#include "driver.h"
#include "virbuffer.h"
#include "remote_driver.h"
static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src);
static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
+static void
+make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
static void make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src);
static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
+static void
+remoteNodeDeviceBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+
static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
remoteStoragePoolBuildEventRefresh,
sizeof(remote_storage_pool_event_refresh_msg),
(xdrproc_t)xdr_remote_storage_pool_event_refresh_msg },
+ { REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE,
+ remoteNodeDeviceBuildEventLifecycle,
+ sizeof(remote_node_device_event_lifecycle_msg),
+ (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg },
};
static void
}
+static int
+remoteConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ int eventID,
+ virConnectNodeDeviceEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ int rv = -1;
+ struct private_data *priv = conn->privateData;
+ remote_connect_node_device_event_register_any_args args;
+ remote_connect_node_device_event_register_any_ret ret;
+ int callbackID;
+ int count;
+ remote_nonnull_node_device node_device;
+
+ remoteDriverLock(priv);
+
+ if ((count = virNodeDeviceEventStateRegisterClient(conn, priv->eventState,
+ dev, eventID, callback,
+ opaque, freecb,
+ &callbackID)) < 0)
+ goto done;
+
+ /* If this is the first callback for this eventID, we need to enable
+ * events on the server */
+ if (count == 1) {
+ args.eventID = eventID;
+ if (dev) {
+ make_nonnull_node_device(&node_device, dev);
+ args.dev = &node_device;
+ } else {
+ args.dev = NULL;
+ }
+
+ memset(&ret, 0, sizeof(ret));
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY,
+ (xdrproc_t) xdr_remote_connect_node_device_event_register_any_args, (char *) &args,
+ (xdrproc_t) xdr_remote_connect_node_device_event_register_any_ret, (char *) &ret) == -1) {
+ virObjectEventStateDeregisterID(conn, priv->eventState,
+ callbackID);
+ goto done;
+ }
+
+ virObjectEventStateSetRemote(conn, priv->eventState, callbackID,
+ ret.callbackID);
+ }
+
+ rv = callbackID;
+
+ done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static int
+remoteConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ struct private_data *priv = conn->privateData;
+ int rv = -1;
+ remote_connect_node_device_event_deregister_any_args args;
+ int eventID;
+ int remoteID;
+ int count;
+
+ remoteDriverLock(priv);
+
+ if ((eventID = virObjectEventStateEventID(conn, priv->eventState,
+ callbackID, &remoteID)) < 0)
+ goto done;
+
+ if ((count = virObjectEventStateDeregisterID(conn, priv->eventState,
+ callbackID)) < 0)
+ goto done;
+
+ /* If that was the last callback for this eventID, we need to disable
+ * events on the server */
+ if (count == 0) {
+ args.callbackID = remoteID;
+
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY,
+ (xdrproc_t) xdr_remote_connect_node_device_event_deregister_any_args, (char *) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ goto done;
+
+ }
+
+ rv = 0;
+
+ done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
static int
remoteConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
virDomainPtr dom,
remoteEventQueue(priv, event, msg->callbackID);
}
+static void
+remoteNodeDeviceBuildEventLifecycle(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_lifecycle_msg *msg = evdata;
+ virNodeDevicePtr dev;
+ virObjectEventPtr event = NULL;
+
+ dev = get_nonnull_node_device(conn, msg->dev);
+ if (!dev)
+ return;
+
+ event = virNodeDeviceEventLifecycleNew(dev->name, msg->event,
+ msg->detail);
+ virObjectUnref(dev);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
+
static void
remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
secret_dst->usageID = secret_src->usageID;
}
+static void
+make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src)
+{
+ dev_dst->name = dev_src->name;
+}
+
static void
make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
{
};
static virNodeDeviceDriver node_device_driver = {
+ .connectNodeDeviceEventDeregisterAny = remoteConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
+ .connectNodeDeviceEventRegisterAny = remoteConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
.nodeNumOfDevices = remoteNodeNumOfDevices, /* 0.5.0 */
.nodeListDevices = remoteNodeListDevices, /* 0.5.0 */
.connectListAllNodeDevices = remoteConnectListAllNodeDevices, /* 0.10.2 */
remote_nonnull_storage_pool pool;
};
+struct remote_connect_node_device_event_register_any_args {
+ int eventID;
+ remote_node_device dev;
+};
+
+struct remote_connect_node_device_event_register_any_ret {
+ int callbackID;
+};
+
+struct remote_connect_node_device_event_deregister_any_args {
+ int callbackID;
+};
+
+struct remote_node_device_event_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_node_device dev;
+ int event;
+ int detail;
+};
+
struct remote_domain_fsfreeze_args {
remote_nonnull_domain dom;
remote_nonnull_string mountpoints<REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX>; /* (const char **) */
* @generate: both
* @acl: none
*/
- REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH = 373
+ REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH = 373,
+
+ /**
+ * @generate: none
+ * @priority: high
+ * @acl: connect:search_node_devices
+ * @aclfilter: node_device:getattr
+ */
+ REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY = 374,
+
+ /**
+ * @generate: none
+ * @priority: high
+ * @acl: connect:read
+ */
+ REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY = 375,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376
};
int callbackID;
remote_nonnull_storage_pool pool;
};
+struct remote_connect_node_device_event_register_any_args {
+ int eventID;
+ remote_node_device dev;
+};
+struct remote_connect_node_device_event_register_any_ret {
+ int callbackID;
+};
+struct remote_connect_node_device_event_deregister_any_args {
+ int callbackID;
+};
+struct remote_node_device_event_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_node_device dev;
+ int event;
+ int detail;
+};
struct remote_domain_fsfreeze_args {
remote_nonnull_domain dom;
struct {
REMOTE_PROC_DOMAIN_GET_GUEST_VCPUS = 371,
REMOTE_PROC_DOMAIN_SET_GUEST_VCPUS = 372,
REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH = 373,
+ 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,
};