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 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 de2456812c..db66052ac2 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 df1cc1439e..932c873cc0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -704,6 +704,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 168c65cc3f..eaa111441a 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 b7ef1f4b26..90aaebc423 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 8d6790ccf2..537f82937d 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 2df38cef77..77ccd04167 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3799,6 +3799,13 @@ struct remote_domain_authorized_ssh_keys_set_args {
unsigned int flags;
};
+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. */
@@ -6714,5 +6721,11 @@ enum remote_procedure {
* @generate: none
* @acl: domain:write
*/
- REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET = 425
+ REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET = 425,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 426
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 9bcd14603d..2b18bbe791 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -3162,6 +3162,12 @@ struct remote_domain_authorized_ssh_keys_set_args {
} keys;
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,
@@ -3588,4 +3594,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE = 423,
REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET = 424,
REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET = 425,
+ REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE = 426,
};
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 98a87dd43c..9f349b9846 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -13502,6 +13502,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), },
@@ -13553,6 +13571,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