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(a)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 76d4f3f6e8..0b77914715 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 038b17ce08..547b42b9e2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -714,6 +714,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 006c8fd1a4..6bcbc75fbc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4322,6 +4322,7 @@ processMemoryDeviceSizeChange(virQEMUDriverPtr driver,
qemuMonitorMemoryDeviceSizeChangePtr info)
{
virDomainMemoryDefPtr mem = NULL;
+ virObjectEventPtr event = NULL;
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
return;
@@ -4339,8 +4340,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 9700dba450..4af82dc809 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 31868269b1..b2394ec2a8 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 f8f36ce361..a4c5542ada 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13494,6 +13494,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), },
@@ -13545,6 +13563,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