[PATCH v2 09/13] Introduce MEMORY_DEVICE_SIZE_CHANGE event

Michal Privoznik mprivozn at redhat.com
Thu Feb 18 13:31:04 UTC 2021


New event is introduced that is emitted whenever guest
acknowledges allocation change request of a virtio-mem.
The aim is to let applications know when that happens,
because changes in allocation are not synchronous with
issuing the request. Under the hood, the event is
emitted whenever QEMU emits MEMORY_DEVICE_SIZE_CHANGE
event.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 examples/c/misc/event-test.c        | 17 ++++++
 include/libvirt/libvirt-domain.h    | 23 ++++++++
 src/conf/domain_event.c             | 84 +++++++++++++++++++++++++++++
 src/conf/domain_event.h             | 10 ++++
 src/libvirt_private.syms            |  2 +
 src/qemu/qemu_driver.c              |  6 +++
 src/remote/remote_daemon_dispatch.c | 30 +++++++++++
 src/remote/remote_driver.c          | 32 +++++++++++
 src/remote/remote_protocol.x        | 15 +++++-
 src/remote_protocol-structs         |  7 +++
 tools/virsh-domain.c                | 20 +++++++
 11 files changed, 245 insertions(+), 1 deletion(-)

diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c
index f164e825e1..e4b29ef67d 100644
--- a/examples/c/misc/event-test.c
+++ b/examples/c/misc/event-test.c
@@ -978,6 +978,22 @@ myDomainEventMemoryFailureCallback(virConnectPtr conn G_GNUC_UNUSED,
 }
 
 
+static int
+myDomainEventMemoryDeviceSizeChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
+                                            virDomainPtr dom,
+                                            const char *alias,
+                                            unsigned long long size,
+                                            void *opaque G_GNUC_UNUSED)
+{
+    /* Casts to uint64_t to work around mingw not knowing %lld */
+    printf("%s EVENT: Domain %s(%d) memory device size change: "
+           "alias: '%s' new size %" PRIu64 "'\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom),
+           alias, (uint64_t)size);
+    return 0;
+}
+
+
 static int
 myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED,
                                         virDomainPtr dom,
@@ -1109,6 +1125,7 @@ struct domainEventData domainEvents[] = {
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback),
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback),
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFailureCallback),
+    DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE, myDomainEventMemoryDeviceSizeChangeCallback),
 };
 
 struct storagePoolEventData {
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 8011cf9fe1..2c449b4f31 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4651,6 +4651,28 @@ typedef void (*virConnectDomainEventMemoryFailureCallback)(virConnectPtr conn,
                                                            unsigned int flags,
                                                            void *opaque);
 
+/**
+ * virConnectDomainEventMemoryDeviceSizeChangeCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @alias: memory device alias
+ * @size: new actual size of memory device (in KiB)
+ * @opaque: application specified data
+ *
+ * The callback occurs when the guest acknowledges request to change size of
+ * memory device (so far only virtio-mem model supports this). The @size then
+ * reflects the new amount of guest visible memory (in kibibytes).
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE with
+ * virConnectDomainEventRegisterAny().
+ */
+typedef void (*virConnectDomainEventMemoryDeviceSizeChangeCallback)(virConnectPtr conn,
+                                                                    virDomainPtr dom,
+                                                                    const char *alias,
+                                                                    unsigned long long size,
+                                                                    void *opaque);
+
 
 /**
  * VIR_DOMAIN_EVENT_CALLBACK:
@@ -4695,6 +4717,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_METADATA_CHANGE = 23, /* virConnectDomainEventMetadataChangeCallback */
     VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD = 24, /* virConnectDomainEventBlockThresholdCallback */
     VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE = 25,  /* virConnectDomainEventMemoryFailureCallback */
+    VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE = 26, /* virConnectDomainEventMemoryDeviceSizeChangeCallback */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 726a792dae..31f9cc34f1 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -58,6 +58,7 @@ static virClassPtr virDomainEventDeviceRemovalFailedClass;
 static virClassPtr virDomainEventMetadataChangeClass;
 static virClassPtr virDomainEventBlockThresholdClass;
 static virClassPtr virDomainEventMemoryFailureClass;
+static virClassPtr virDomainEventMemoryDeviceSizeChangeClass;
 
 static void virDomainEventDispose(void *obj);
 static void virDomainEventLifecycleDispose(void *obj);
@@ -81,6 +82,7 @@ static void virDomainEventDeviceRemovalFailedDispose(void *obj);
 static void virDomainEventMetadataChangeDispose(void *obj);
 static void virDomainEventBlockThresholdDispose(void *obj);
 static void virDomainEventMemoryFailureDispose(void *obj);
+static void virDomainEventMemoryDeviceSizeChangeDispose(void *obj);
 
 static void
 virDomainEventDispatchDefaultFunc(virConnectPtr conn,
@@ -299,6 +301,15 @@ struct _virDomainEventMemoryFailure {
 typedef struct _virDomainEventMemoryFailure virDomainEventMemoryFailure;
 typedef virDomainEventMemoryFailure *virDomainEventMemoryFailurePtr;
 
+struct _virDomainEventMemoryDeviceSizeChange {
+    virDomainEvent parent;
+
+    char *alias;
+    unsigned long long size;
+};
+typedef struct _virDomainEventMemoryDeviceSizeChange virDomainEventMemoryDeviceSizeChange;
+typedef virDomainEventMemoryDeviceSizeChange *virDomainEventMemoryDeviceSizeChangePtr;
+
 static int
 virDomainEventsOnceInit(void)
 {
@@ -346,6 +357,8 @@ virDomainEventsOnceInit(void)
         return -1;
     if (!VIR_CLASS_NEW(virDomainEventMemoryFailure, virDomainEventClass))
         return -1;
+    if (!VIR_CLASS_NEW(virDomainEventMemoryDeviceSizeChange, virDomainEventClass))
+        return -1;
     return 0;
 }
 
@@ -562,6 +575,14 @@ virDomainEventMemoryFailureDispose(void *obj)
     VIR_DEBUG("obj=%p", event);
 }
 
+static void
+virDomainEventMemoryDeviceSizeChangeDispose(void *obj)
+{
+    virDomainEventMemoryDeviceSizeChangePtr event = obj;
+    VIR_DEBUG("obj=%p", event);
+
+    g_free(event->alias);
+}
 
 static void *
 virDomainEventNew(virClassPtr klass,
@@ -1686,6 +1707,57 @@ virDomainEventMemoryFailureNewFromDom(virDomainPtr dom,
                                           recipient, action, flags);
 }
 
+
+static virObjectEventPtr
+virDomainEventMemoryDeviceSizeChangeNew(int id,
+                               const char *name,
+                               unsigned char *uuid,
+                               const char *alias,
+                               unsigned long long size)
+{
+    virDomainEventMemoryDeviceSizeChangePtr ev;
+
+    if (virDomainEventsInitialize() < 0)
+        return NULL;
+
+    if (!(ev = virDomainEventNew(virDomainEventMemoryDeviceSizeChangeClass,
+                                 VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE,
+                                 id, name, uuid)))
+        return NULL;
+
+    ev->alias = g_strdup(alias);
+    ev->size = size;
+
+    return (virObjectEventPtr)ev;
+}
+
+
+virObjectEventPtr
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObjPtr obj,
+                                               const char *alias,
+                                               unsigned long long size)
+{
+    return virDomainEventMemoryDeviceSizeChangeNew(obj->def->id,
+                                                   obj->def->name,
+                                                   obj->def->uuid,
+                                                   alias,
+                                                   size);
+}
+
+
+virObjectEventPtr
+virDomainEventMemoryDeviceSizeChangeNewFromDom(virDomainPtr dom,
+                                               const char *alias,
+                                               unsigned long long size)
+{
+    return virDomainEventMemoryDeviceSizeChangeNew(dom->id,
+                                                   dom->name,
+                                                   dom->uuid,
+                                                   alias,
+                                                   size);
+}
+
+
 static void
 virDomainEventDispatchDefaultFunc(virConnectPtr conn,
                                   virObjectEventPtr event,
@@ -1982,6 +2054,18 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
             goto cleanup;
         }
 
+    case VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE:
+        {
+            virDomainEventMemoryDeviceSizeChangePtr memoryDeviceSizeChangeEvent;
+
+            memoryDeviceSizeChangeEvent = (virDomainEventMemoryDeviceSizeChangePtr)event;
+            ((virConnectDomainEventMemoryDeviceSizeChangeCallback)cb)(conn, dom,
+                                                                      memoryDeviceSizeChangeEvent->alias,
+                                                                      memoryDeviceSizeChangeEvent->size,
+                                                                      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 13a1c56ce1..717d1c7307 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -267,6 +267,16 @@ virDomainEventMemoryFailureNewFromDom(virDomainPtr dom,
                                       int action,
                                       unsigned int flags);
 
+virObjectEventPtr
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObjPtr obj,
+                                               const char *alias,
+                                               unsigned long long size);
+
+virObjectEventPtr
+virDomainEventMemoryDeviceSizeChangeNewFromDom(virDomainPtr dom,
+                                               const char *alias,
+                                               unsigned long long size);
+
 int
 virDomainEventStateRegister(virConnectPtr conn,
                             virObjectEventStatePtr state,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4f362e3c54..e4c8dd7c1e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -708,6 +708,8 @@ virDomainEventLifecycleNew;
 virDomainEventLifecycleNewFromDef;
 virDomainEventLifecycleNewFromDom;
 virDomainEventLifecycleNewFromObj;
+virDomainEventMemoryDeviceSizeChangeNewFromDom;
+virDomainEventMemoryDeviceSizeChangeNewFromObj;
 virDomainEventMemoryFailureNewFromDom;
 virDomainEventMemoryFailureNewFromObj;
 virDomainEventMetadataChangeNewFromDom;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 995faf2abc..0d12939021 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4285,6 +4285,7 @@ processMemoryDeviceSizeChange(virQEMUDriverPtr driver,
                               qemuMonitorMemoryDeviceSizeChangePtr info)
 {
     virDomainMemoryDefPtr mem = NULL;
+    virObjectEventPtr event = NULL;
 
     if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
         return;
@@ -4302,8 +4303,13 @@ processMemoryDeviceSizeChange(virQEMUDriverPtr driver,
 
     mem->actualsize = VIR_DIV_UP(info->size, 1024);
 
+    event = virDomainEventMemoryDeviceSizeChangeNewFromObj(vm,
+                                                           info->devAlias,
+                                                           mem->actualsize);
+
  endjob:
     qemuDomainObjEndJob(driver, vm);
+    virObjectEventStateQueue(driver->domainEventState, event);
 }
 
 
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index e9f2a0ce5b..1ea79d0cf9 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -1333,6 +1333,35 @@ remoteRelayDomainEventMemoryFailure(virConnectPtr conn,
 }
 
 
+static int
+remoteRelayDomainEventMemoryDeviceSizeChange(virConnectPtr conn,
+                                             virDomainPtr dom,
+                                             const char *alias,
+                                             unsigned long long size,
+                                             void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_domain_event_memory_device_size_change_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+        return -1;
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+    data.callbackID = callback->callbackID;
+    data.alias = g_strdup(alias);
+    data.size = size;
+    make_nonnull_domain(&data.dom, dom);
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
+                                  (xdrproc_t)xdr_remote_domain_event_memory_device_size_change_msg,
+                                  &data);
+    return 0;
+}
+
+
 static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -1360,6 +1389,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryDeviceSizeChange),
 };
 
 G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a83cd866e7..7155179744 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -410,6 +410,10 @@ remoteDomainBuildEventMemoryFailure(virNetClientProgramPtr prog,
                                     void *evdata, void *opaque);
 
 static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgramPtr prog,
+                                             virNetClientPtr client,
+                                             void *evdata, void *opaque);
+static void
 remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog G_GNUC_UNUSED,
                                          virNetClientPtr client G_GNUC_UNUSED,
                                          void *evdata, void *opaque);
@@ -624,6 +628,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteDomainBuildEventMemoryFailure,
       sizeof(remote_domain_event_memory_failure_msg),
       (xdrproc_t)xdr_remote_domain_event_memory_failure_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
+      remoteDomainBuildEventMemoryDeviceSizeChange,
+      sizeof(remote_domain_event_memory_device_size_change_msg),
+      (xdrproc_t)xdr_remote_domain_event_memory_device_size_change_msg },
 };
 
 static void
@@ -5463,6 +5471,30 @@ remoteDomainBuildEventMemoryFailure(virNetClientProgramPtr prog G_GNUC_UNUSED,
 }
 
 
+static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgramPtr prog G_GNUC_UNUSED,
+                                             virNetClientPtr client G_GNUC_UNUSED,
+                                             void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    remote_domain_event_memory_device_size_change_msg *msg = evdata;
+    struct private_data *priv = conn->privateData;
+    virDomainPtr dom;
+    virObjectEventPtr event = NULL;
+
+    if (!(dom = get_nonnull_domain(conn, msg->dom)))
+        return;
+
+    event = virDomainEventMemoryDeviceSizeChangeNewFromDom(dom,
+                                                           msg->alias,
+                                                           msg->size);
+
+    virObjectUnref(dom);
+
+    virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackID);
+}
+
+
 static int
 remoteStreamSend(virStreamPtr st,
                  const char *data,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index d3724bc305..d154bde7db 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3812,6 +3812,13 @@ struct remote_domain_get_messages_ret {
 };
 
 
+struct remote_domain_event_memory_device_size_change_msg {
+    int callbackID;
+    remote_nonnull_domain dom;
+    remote_nonnull_string alias;
+    unsigned hyper size;
+};
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -6733,5 +6740,11 @@ enum remote_procedure {
      * @generate: none
      * @acl: domain:read
      */
-    REMOTE_PROC_DOMAIN_GET_MESSAGES = 426
+    REMOTE_PROC_DOMAIN_GET_MESSAGES = 426,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 427
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index c0c034ac6a..37120be91b 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -3172,6 +3172,12 @@ struct remote_domain_get_messages_ret {
                 remote_nonnull_string * msgs_val;
         } msgs;
 };
+struct remote_domain_event_memory_device_size_change_msg {
+        int                        callbackID;
+        remote_nonnull_domain      dom;
+        remote_nonnull_string      alias;
+        uint64_t                   size;
+};
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3599,4 +3605,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET = 424,
         REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET = 425,
         REMOTE_PROC_DOMAIN_GET_MESSAGES = 426,
+        REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 427,
 };
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index d40995f44d..49ddd69d1b 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13503,6 +13503,24 @@ virshEventMemoryFailurePrint(virConnectPtr conn G_GNUC_UNUSED,
 }
 
 
+static void
+virshEventMemoryDeviceSizeChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+                                      virDomainPtr dom,
+                                      const char *alias,
+                                      unsigned long long size,
+                                      void *opaque)
+{
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAsprintf(&buf,
+                      _("event 'memory-device-size-change' for domain '%s':\n"
+                        "alias: %s\nsize: %llu\n"),
+                      virDomainGetName(dom), alias, size);
+
+    virshEventPrint(opaque, &buf);
+}
+
+
 virshDomainEventCallback virshDomainEventCallbacks[] = {
     { "lifecycle",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
@@ -13554,6 +13572,8 @@ virshDomainEventCallback virshDomainEventCallbacks[] = {
       VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
     { "memory-failure",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryFailurePrint), },
+    { "memory-device-size-change",
+      VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), },
 };
 G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks));
 
-- 
2.26.2




More information about the libvir-list mailing list