[PATCH v4 08/14] qemu: Wire up MEMORY_DEVICE_SIZE_CHANGE event

Michal Privoznik mprivozn at redhat.com
Wed Jun 23 10:12:13 UTC 2021


As advertised in previous commit, this event is delivered to us
when virtio-mem module changes the allocation inside the guest.
It comes with one attribute - size - which holds the new size of
the virtio-mem (well, allocated size), in bytes.
Mind you, this is not necessarily the same number as 'requested
size'. It almost certainly will be when sizing the memory up, but
it might not be when sizing the memory down - the guest kernel
might be unable to free some blocks.

This actual size is reported in the domain XML as an output
element only.

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_domain.c              |  3 ++
 src/qemu/qemu_domain.h              |  1 +
 src/qemu/qemu_driver.c              | 37 +++++++++++++
 src/qemu/qemu_monitor.c             | 24 +++++++++
 src/qemu/qemu_monitor.h             | 20 +++++++
 src/qemu/qemu_monitor_json.c        | 24 +++++++++
 src/qemu/qemu_process.c             | 42 +++++++++++++++
 src/remote/remote_daemon_dispatch.c | 30 +++++++++++
 src/remote/remote_driver.c          | 32 +++++++++++
 src/remote/remote_protocol.x        | 14 ++++-
 src/remote_protocol-structs         |  7 +++
 tools/virsh-domain.c                | 20 +++++++
 17 files changed, 389 insertions(+), 1 deletion(-)

diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c
index 10c707e66b..1eec76c79d 100644
--- a/examples/c/misc/event-test.c
+++ b/examples/c/misc/event-test.c
@@ -982,6 +982,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,
@@ -1113,6 +1129,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 7ef8ac51e5..534063d15b 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4654,6 +4654,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:
@@ -4698,6 +4720,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 15a3baedf7..18539e348b 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -58,6 +58,7 @@ static virClass *virDomainEventDeviceRemovalFailedClass;
 static virClass *virDomainEventMetadataChangeClass;
 static virClass *virDomainEventBlockThresholdClass;
 static virClass *virDomainEventMemoryFailureClass;
+static virClass *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,
@@ -277,6 +279,15 @@ struct _virDomainEventMemoryFailure {
 };
 typedef struct _virDomainEventMemoryFailure virDomainEventMemoryFailure;
 
+struct _virDomainEventMemoryDeviceSizeChange {
+    virDomainEvent parent;
+
+    char *alias;
+    unsigned long long size;
+};
+typedef struct _virDomainEventMemoryDeviceSizeChange virDomainEventMemoryDeviceSizeChange;
+typedef virDomainEventMemoryDeviceSizeChange *virDomainEventMemoryDeviceSizeChangePtr;
+
 static int
 virDomainEventsOnceInit(void)
 {
@@ -324,6 +335,8 @@ virDomainEventsOnceInit(void)
         return -1;
     if (!VIR_CLASS_NEW(virDomainEventMemoryFailure, virDomainEventClass))
         return -1;
+    if (!VIR_CLASS_NEW(virDomainEventMemoryDeviceSizeChange, virDomainEventClass))
+        return -1;
     return 0;
 }
 
@@ -540,6 +553,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(virClass *klass,
@@ -1664,6 +1685,57 @@ virDomainEventMemoryFailureNewFromDom(virDomainPtr dom,
                                           recipient, action, flags);
 }
 
+
+static virObjectEvent *
+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 (virObjectEvent *)ev;
+}
+
+
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObj *obj,
+                                               const char *alias,
+                                               unsigned long long size)
+{
+    return virDomainEventMemoryDeviceSizeChangeNew(obj->def->id,
+                                                   obj->def->name,
+                                                   obj->def->uuid,
+                                                   alias,
+                                                   size);
+}
+
+
+virObjectEvent *
+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,
                                   virObjectEvent *event,
@@ -1960,6 +2032,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 2a59e613cd..4a9f6b988b 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);
 
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromObj(virDomainObj *obj,
+                                               const char *alias,
+                                               unsigned long long size);
+
+virObjectEvent *
+virDomainEventMemoryDeviceSizeChangeNewFromDom(virDomainPtr dom,
+                                               const char *alias,
+                                               unsigned long long size);
+
 int
 virDomainEventStateRegister(virConnectPtr conn,
                             virObjectEventState *state,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0721e13143..e25866c60b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -719,6 +719,8 @@ virDomainEventLifecycleNew;
 virDomainEventLifecycleNewFromDef;
 virDomainEventLifecycleNewFromDom;
 virDomainEventLifecycleNewFromObj;
+virDomainEventMemoryDeviceSizeChangeNewFromDom;
+virDomainEventMemoryDeviceSizeChangeNewFromObj;
 virDomainEventMemoryFailureNewFromDom;
 virDomainEventMemoryFailureNewFromObj;
 virDomainEventMetadataChangeNewFromDom;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index d4ad29fac4..91a598c208 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -11007,6 +11007,9 @@ qemuProcessEventFree(struct qemuProcessEvent *event)
     case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE:
         virObjectUnref(event->data);
         break;
+    case QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE:
+        qemuMonitorMemoryDeviceSizeChangeFree(event->data);
+        break;
     case QEMU_PROCESS_EVENT_PR_DISCONNECT:
     case QEMU_PROCESS_EVENT_LAST:
         break;
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index acf6ca5ab6..282ae345d5 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -430,6 +430,7 @@ typedef enum {
     QEMU_PROCESS_EVENT_PR_DISCONNECT,
     QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED,
     QEMU_PROCESS_EVENT_GUEST_CRASHLOADED,
+    QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE,
 
     QEMU_PROCESS_EVENT_LAST
 } qemuProcessEventType;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a638c67f1e..996f97b526 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4300,6 +4300,40 @@ processGuestCrashloadedEvent(virQEMUDriver *driver,
 }
 
 
+static void
+processMemoryDeviceSizeChange(virQEMUDriver *driver,
+                              virDomainObj *vm,
+                              qemuMonitorMemoryDeviceSizeChange *info)
+{
+    virDomainMemoryDef *mem = NULL;
+    virObjectEvent *event = NULL;
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        return;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain is not running");
+        goto endjob;
+    }
+
+    mem = virDomainMemoryFindByDeviceAlias(vm->def, info->devAlias);
+    if (!mem) {
+        VIR_DEBUG("Memory device '%s' not found", info->devAlias);
+        goto endjob;
+    }
+
+    mem->actualsize = VIR_DIV_UP(info->size, 1024);
+
+    event = virDomainEventMemoryDeviceSizeChangeNewFromObj(vm,
+                                                           info->devAlias,
+                                                           mem->actualsize);
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+    virObjectEventStateQueue(driver->domainEventState, event);
+}
+
+
 static void qemuProcessEventHandler(void *data, void *opaque)
 {
     struct qemuProcessEvent *processEvent = data;
@@ -4349,6 +4383,9 @@ static void qemuProcessEventHandler(void *data, void *opaque)
     case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED:
         processGuestCrashloadedEvent(driver, vm);
         break;
+    case QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE:
+        processMemoryDeviceSizeChange(driver, vm, processEvent->data);
+        break;
     case QEMU_PROCESS_EVENT_LAST:
         break;
     }
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index be04684585..aeaa7ee975 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1446,6 +1446,20 @@ qemuMonitorEmitSpiceMigrated(qemuMonitor *mon)
 }
 
 
+int
+qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon,
+                                      const char *devAlias,
+                                      unsigned long long size)
+{
+    int ret = -1;
+    VIR_DEBUG("mon=%p, devAlias='%s', size=%llu", mon, devAlias, size);
+
+    QEMU_MONITOR_CALLBACK(mon, ret, domainMemoryDeviceSizeChange, mon->vm, devAlias, size);
+
+    return ret;
+}
+
+
 int
 qemuMonitorEmitMemoryFailure(qemuMonitor *mon,
                              qemuMonitorEventMemoryFailure *mfp)
@@ -4393,6 +4407,16 @@ qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGidStatus *info)
 }
 
 
+void
+qemuMonitorMemoryDeviceSizeChangeFree(qemuMonitorMemoryDeviceSizeChangePtr info)
+{
+    if (!info)
+        return;
+
+    g_free(info->devAlias);
+}
+
+
 int
 qemuMonitorSetWatchdogAction(qemuMonitor *mon,
                              const char *action)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index b5de5711e0..1c69a86af0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -101,6 +101,14 @@ struct _qemuMonitorRdmaGidStatus {
 };
 
 
+typedef struct _qemuMonitorMemoryDeviceSizeChange qemuMonitorMemoryDeviceSizeChange;
+typedef qemuMonitorMemoryDeviceSizeChange *qemuMonitorMemoryDeviceSizeChangePtr;
+struct _qemuMonitorMemoryDeviceSizeChange {
+    char *devAlias;
+    unsigned long long size;
+};
+
+
 typedef enum {
     QEMU_MONITOR_JOB_TYPE_UNKNOWN, /* internal value, not exposed by qemu */
     QEMU_MONITOR_JOB_TYPE_COMMIT,
@@ -145,6 +153,7 @@ struct _qemuMonitorJobInfo {
 char *qemuMonitorGuestPanicEventInfoFormatMsg(qemuMonitorEventPanicInfo *info);
 void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfo *info);
 void qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGidStatus *info);
+void qemuMonitorMemoryDeviceSizeChangeFree(qemuMonitorMemoryDeviceSizeChange *info);
 
 typedef void (*qemuMonitorDestroyCallback)(qemuMonitor *mon,
                                            virDomainObj *vm,
@@ -364,6 +373,12 @@ typedef int (*qemuMonitorDomainMemoryFailureCallback)(qemuMonitor *mon,
                                                       qemuMonitorEventMemoryFailure *mfp,
                                                       void *opaque);
 
+typedef int (*qemuMonitorDomainMemoryDeviceSizeChange)(qemuMonitor *mon,
+                                                       virDomainObj *vm,
+                                                       const char *alias,
+                                                       unsigned long long size,
+                                                       void *opaque);
+
 typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
 struct _qemuMonitorCallbacks {
     qemuMonitorDestroyCallback destroy;
@@ -400,6 +415,7 @@ struct _qemuMonitorCallbacks {
     qemuMonitorDomainRdmaGidStatusChangedCallback domainRdmaGidStatusChanged;
     qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded;
     qemuMonitorDomainMemoryFailureCallback domainMemoryFailure;
+    qemuMonitorDomainMemoryDeviceSizeChange domainMemoryDeviceSizeChange;
 };
 
 qemuMonitor *qemuMonitorOpen(virDomainObj *vm,
@@ -496,6 +512,10 @@ int qemuMonitorEmitSerialChange(qemuMonitor *mon,
                                 bool connected);
 int qemuMonitorEmitSpiceMigrated(qemuMonitor *mon);
 
+int qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon,
+                                          const char *devAlias,
+                                          unsigned long long size);
+
 int qemuMonitorEmitMemoryFailure(qemuMonitor *mon,
                                  qemuMonitorEventMemoryFailure *mfp);
 
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index d3db88a389..57b78cd686 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -113,6 +113,7 @@ static void qemuMonitorJSONHandleDumpCompleted(qemuMonitor *mon, virJSONValue *d
 static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon, virJSONValue *data);
 static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon, virJSONValue *data);
 static void qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon, virJSONValue *data);
+static void qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, virJSONValue *data);
 
 typedef struct {
     const char *type;
@@ -133,6 +134,7 @@ static qemuEventHandler eventHandlers[] = {
     { "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, },
     { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
     { "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
+    { "MEMORY_DEVICE_SIZE_CHANGE", qemuMonitorJSONHandleMemoryDeviceSizeChange, },
     { "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, },
     { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
     { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
@@ -1320,6 +1322,28 @@ qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon,
 }
 
 
+static void
+qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon,
+                                            virJSONValue *data)
+{
+    const char *name;
+    unsigned long long size;
+
+    if (!(name = virJSONValueObjectGetString(data, "id"))) {
+        VIR_WARN("missing device alias in MEMORY_DEVICE_SIZE_CHANGE event");
+        return;
+    }
+
+    if (virJSONValueObjectGetNumberUlong(data, "size", &size) < 0) {
+        VIR_WARN("missing new size for '%s' in MEMORY_DEVICE_SIZE_CHANGE event", name);
+        return;
+    }
+
+
+    qemuMonitorEmitMemoryDeviceSizeChange(mon, name, size);
+}
+
+
 static void
 qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon,
                                    virJSONValue *data)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 62208048b0..78e5a65d5f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1919,6 +1919,47 @@ qemuProcessHandleMemoryFailure(qemuMonitor *mon G_GNUC_UNUSED,
 }
 
 
+static int
+qemuProcessHandleMemoryDeviceSizeChange(qemuMonitor *mon G_GNUC_UNUSED,
+                                        virDomainObj *vm,
+                                        const char *devAlias,
+                                        unsigned long long size,
+                                        void *opaque)
+{
+    virQEMUDriver *driver = opaque;
+    struct qemuProcessEvent *processEvent = NULL;
+    qemuMonitorMemoryDeviceSizeChange *info = NULL;
+    int ret = -1;
+
+    virObjectLock(vm);
+
+    VIR_DEBUG("Memory device '%s' changed size to '%llu' in domain '%s'",
+              devAlias, size, vm->def->name);
+
+    info = g_new0(qemuMonitorMemoryDeviceSizeChange, 1);
+    info->devAlias = g_strdup(devAlias);
+    info->size = size;
+
+    processEvent = g_new0(struct qemuProcessEvent, 1);
+    processEvent->eventType = QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHANGE;
+    processEvent->vm = virObjectRef(vm);
+    processEvent->data = g_steal_pointer(&info);
+
+    if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
+        qemuProcessEventFree(processEvent);
+        virObjectUnref(vm);
+        goto cleanup;
+    }
+
+    processEvent = NULL;
+    ret = 0;
+ cleanup:
+    qemuProcessEventFree(processEvent);
+    virObjectUnlock(vm);
+    return ret;
+}
+
+
 static qemuMonitorCallbacks monitorCallbacks = {
     .eofNotify = qemuProcessHandleMonitorEOF,
     .errorNotify = qemuProcessHandleMonitorError,
@@ -1952,6 +1993,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
     .domainRdmaGidStatusChanged = qemuProcessHandleRdmaGidStatusChanged,
     .domainGuestCrashloaded = qemuProcessHandleGuestCrashloaded,
     .domainMemoryFailure = qemuProcessHandleMemoryFailure,
+    .domainMemoryDeviceSizeChange = qemuProcessHandleMemoryDeviceSizeChange,
 };
 
 static void
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index 65aa20f7d1..ff81ecfa79 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -1334,6 +1334,35 @@ remoteRelayDomainEventMemoryFailure(virConnectPtr conn,
 }
 
 
+static int
+remoteRelayDomainEventMemoryDeviceSizeChange(virConnectPtr conn,
+                                             virDomainPtr dom,
+                                             const char *alias,
+                                             unsigned long long size,
+                                             void *opaque)
+{
+    daemonClientEventCallback *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),
@@ -1361,6 +1390,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 c03c68ec30..1f94be6cbc 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -410,6 +410,10 @@ remoteDomainBuildEventMemoryFailure(virNetClientProgram *prog,
                                     void *evdata, void *opaque);
 
 static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog,
+                                             virNetClient *client,
+                                             void *evdata, void *opaque);
+static void
 remoteConnectNotifyEventConnectionClosed(virNetClientProgram *prog G_GNUC_UNUSED,
                                          virNetClient *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
@@ -5436,6 +5444,30 @@ remoteDomainBuildEventMemoryFailure(virNetClientProgram *prog G_GNUC_UNUSED,
 }
 
 
+static void
+remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog G_GNUC_UNUSED,
+                                             virNetClient *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;
+    virObjectEvent *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 de69704b68..a45bdaa7e8 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3837,6 +3837,13 @@ struct remote_domain_start_dirty_rate_calc_args {
 };
 
 
+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. */
@@ -6784,6 +6791,11 @@ enum remote_procedure {
      * @priority: high
      * @acl: node_device:start
      */
-    REMOTE_PROC_NODE_DEVICE_CREATE = 430
+    REMOTE_PROC_NODE_DEVICE_CREATE = 430,
 
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 431
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 6b46328adc..7286c06ae8 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -3192,6 +3192,12 @@ struct remote_domain_start_dirty_rate_calc_args {
         int                        seconds;
         u_int                      flags;
 };
+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,
@@ -3623,4 +3629,5 @@ enum remote_procedure {
         REMOTE_PROC_NODE_DEVICE_DEFINE_XML = 428,
         REMOTE_PROC_NODE_DEVICE_UNDEFINE = 429,
         REMOTE_PROC_NODE_DEVICE_CREATE = 430,
+        REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 431,
 };
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index f2a5fb03a4..b69eb3e346 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13464,6 +13464,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), },
@@ -13515,6 +13533,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.31.1




More information about the libvir-list mailing list