From nobody Mon Feb 9 00:26:26 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1619184373; cv=none; d=zohomail.com; s=zohoarc; b=UOZgm4620TpQDlq5KcWum0H55vhV+J4DSr+mWUOSvhky9INK6LcDp74K7cVjHXcEEBYu1F7aT+DDOF8nBBdfhAxyVKDfZ98cV90NsCHzF5I+c6F5vsKgLLH59R1F8FBEem9qaDFBUWIYKUKu3oMDgJo0NkKkinu5i/elctrN5TQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1619184373; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=AW57pVB8Xt8dfWZ27kBtkZDMruX/xTOylTIe4MlNsyY=; b=UHvSSft1X6SwWXAuUZt88jaJhiB5hc/Bc8I3td8oV4DOUjd9ckOdT8FYsoi3TyUkdpu9hyv0KCIs8YwVS94VqyTmfJJBhi3ZeH87AVOHxxJQkOYJfSoZYeogeYW2jLPGUFAVyy7IE1FtcMhDcj4gjt1IQvVNOCdSfIIyS7g6QtI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1619184373365782.5149932263616; Fri, 23 Apr 2021 06:26:13 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-537-subOQJicNhmFVhrvteXyhg-1; Fri, 23 Apr 2021 09:25:07 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 46165343AB; Fri, 23 Apr 2021 13:24:59 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1B80C19C71; Fri, 23 Apr 2021 13:24:59 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D33C61806D25; Fri, 23 Apr 2021 13:24:58 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 13NDOqlV021604 for ; Fri, 23 Apr 2021 09:24:52 -0400 Received: by smtp.corp.redhat.com (Postfix) id D2C506A8E4; Fri, 23 Apr 2021 13:24:52 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.195.9]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4F76563634 for ; Fri, 23 Apr 2021 13:24:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619184372; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=AW57pVB8Xt8dfWZ27kBtkZDMruX/xTOylTIe4MlNsyY=; b=Cdb913guvq79sSYnpAcBKxmzhx+joTNGrULwOEVDtHL9//1MFjVbR2vvxvICBqT5Wl1m1x 0Iin49b/TN7jA4YURX6abVLcjD8kaGy6pP7F/O3icsmt3xVBoCbNtn34ka6MCLu3/YCSpq qV21DDMieFNqOFF5VPw2zfetZ5SzIa8= X-MC-Unique: subOQJicNhmFVhrvteXyhg-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 08/14] qemu: Wire up MEMORY_DEVICE_SIZE_CHANGE event Date: Fri, 23 Apr 2021 15:24:30 +0200 Message-Id: <29e470c82aa85545a9a83e81debdff20b57fc814.1619184154.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" 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 --- docs/formatdomain.rst | 7 +++ docs/schemas/domaincommon.rng | 5 ++ examples/c/misc/event-test.c | 17 ++++++ include/libvirt/libvirt-domain.h | 23 ++++++++ src/conf/domain_conf.c | 26 ++++++++- src/conf/domain_conf.h | 8 +++ src/conf/domain_event.c | 84 +++++++++++++++++++++++++++++ src/conf/domain_event.h | 10 ++++ src/libvirt_private.syms | 3 ++ 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 +++++++ 21 files changed, 434 insertions(+), 3 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 44e478c88a..7ab5d25488 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -7731,6 +7731,7 @@ Example: usage of the memory devices 0 2048 1048576 + 524288 @@ -7846,6 +7847,12 @@ Example: usage of the memory devices The total size exposed to the guest. Must respect ``block`` granulari= ty and be smaller or equal to ``size``. =20 + ``actual`` + Active XML for ``virtio-mem`` model may contain ``actual`` element th= at + reflects the actual size of the corresponding virtio memory device. T= he + element is formatted into live XML and never parsed, i.e. it is + output-only element. + :anchor:`` =20 IOMMU devices diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index b75c2f3ead..0ab9e82c09 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -6619,6 +6619,11 @@ + + + + + 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, } =20 =20 +static int +myDomainEventMemoryDeviceSizeChangeCallback(virConnectPtr conn G_GNUC_UNUS= ED, + 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[] =3D { DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadat= aChangeCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockTh= resholdCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFa= ilureCallback), + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE, myDomainEv= entMemoryDeviceSizeChangeCallback), }; =20 struct storagePoolEventData { diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-dom= ain.h index e99bfb7654..171a2ae704 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4653,6 +4653,28 @@ typedef void (*virConnectDomainEventMemoryFailureCal= lback)(virConnectPtr conn, unsigned int fl= ags, void *opaque); =20 +/** + * 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 t= hen + * 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)(virCon= nectPtr conn, + virDom= ainPtr dom, + const = char *alias, + unsign= ed long long size, + void *= opaque); + =20 /** * VIR_DOMAIN_EVENT_CALLBACK: @@ -4697,6 +4719,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_METADATA_CHANGE =3D 23, /* virConnectDomainEventMe= tadataChangeCallback */ VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD =3D 24, /* virConnectDomainEventBl= ockThresholdCallback */ VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE =3D 25, /* virConnectDomainEventMe= moryFailureCallback */ + VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE =3D 26, /* virConnectDom= ainEventMemoryDeviceSizeChangeCallback */ =20 # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e75c5c9dcd..d578a95526 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -17420,6 +17420,23 @@ virDomainMemoryFindByDeviceInfo(virDomainDef *def, } =20 =20 +virDomainMemoryDef * +virDomainMemoryFindByDeviceAlias(virDomainDef *def, + const char *alias) +{ + size_t i; + + for (i =3D 0; i < def->nmems; i++) { + virDomainMemoryDef *tmp =3D def->mems[i]; + + if (STREQ_NULLABLE(tmp->info.alias, alias)) + return tmp; + } + + return NULL; +} + + /** * virDomainMemoryInsert: * @@ -26979,7 +26996,8 @@ virDomainMemorySourceDefFormat(virBuffer *buf, =20 static void virDomainMemoryTargetDefFormat(virBuffer *buf, - virDomainMemoryDef *def) + virDomainMemoryDef *def, + unsigned int flags) { g_auto(virBuffer) childBuf =3D VIR_BUFFER_INIT_CHILD(buf); =20 @@ -27001,6 +27019,10 @@ virDomainMemoryTargetDefFormat(virBuffer *buf, =20 virBufferAsprintf(&childBuf, "%llu\n", def->requestedsize); + if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) { + virBufferAsprintf(&childBuf, "%llu\n", + def->actualsize); + } } =20 virXMLFormatElement(buf, "target", NULL, &childBuf); @@ -27033,7 +27055,7 @@ virDomainMemoryDefFormat(virBuffer *buf, if (virDomainMemorySourceDefFormat(buf, def) < 0) return -1; =20 - virDomainMemoryTargetDefFormat(buf, def); + virDomainMemoryTargetDefFormat(buf, def, flags); =20 virDomainDeviceInfoFormat(buf, &def->info, flags); =20 diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4fc864b1eb..87b0d53a27 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2469,6 +2469,9 @@ struct _virDomainMemoryDef { unsigned long long labelsize; /* kibibytes; valid only for NVDIMM */ unsigned long long blocksize; /* kibibytes; valid only for VIRTIO_MEM = */ unsigned long long requestedsize; /* kibibytes; valid only for VIRTIO_= MEM */ + unsigned long long actualsize; /* kibibytes, valid for VIRTIO_MEM and + active domain only, only to report n= ever + parse */ bool readonly; /* valid only for NVDIMM */ =20 /* required for QEMU NVDIMM ppc64 support */ @@ -3762,6 +3765,11 @@ virDomainMemoryFindByDeviceInfo(virDomainDef *dev, virDomainDeviceInfo *info) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; =20 +virDomainMemoryDef * +virDomainMemoryFindByDeviceAlias(virDomainDef *def, + const char *alias) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; + int virDomainShmemDefInsert(virDomainDef *def, virDomainShmemDef *shmem) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; bool virDomainShmemDefEquals(virDomainShmemDef *src, virDomainShmemDef *ds= t) diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 15a3baedf7..196093884a 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; =20 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); =20 static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -277,6 +279,15 @@ struct _virDomainEventMemoryFailure { }; typedef struct _virDomainEventMemoryFailure virDomainEventMemoryFailure; =20 +struct _virDomainEventMemoryDeviceSizeChange { + virDomainEvent parent; + + char *alias; + unsigned long long size; +}; +typedef struct _virDomainEventMemoryDeviceSizeChange virDomainEventMemoryD= eviceSizeChange; +typedef virDomainEventMemoryDeviceSizeChange *virDomainEventMemoryDeviceSi= zeChangePtr; + 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, virDomainEven= tClass)) + return -1; return 0; } =20 @@ -540,6 +553,14 @@ virDomainEventMemoryFailureDispose(void *obj) VIR_DEBUG("obj=3D%p", event); } =20 +static void +virDomainEventMemoryDeviceSizeChangeDispose(void *obj) +{ + virDomainEventMemoryDeviceSizeChangePtr event =3D obj; + VIR_DEBUG("obj=3D%p", event); + + g_free(event->alias); +} =20 static void * virDomainEventNew(virClass *klass, @@ -1664,6 +1685,57 @@ virDomainEventMemoryFailureNewFromDom(virDomainPtr d= om, recipient, action, flags); } =20 + +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 =3D virDomainEventNew(virDomainEventMemoryDeviceSizeChangeCla= ss, + VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CH= ANGE, + id, name, uuid))) + return NULL; + + ev->alias =3D g_strdup(alias); + ev->size =3D 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; } =20 + case VIR_DOMAIN_EVENT_ID_MEMORY_DEVICE_SIZE_CHANGE: + { + virDomainEventMemoryDeviceSizeChangePtr memoryDeviceSizeChange= Event; + + memoryDeviceSizeChangeEvent =3D (virDomainEventMemoryDeviceSiz= eChangePtr)event; + ((virConnectDomainEventMemoryDeviceSizeChangeCallback)cb)(conn= , dom, + memo= ryDeviceSizeChangeEvent->alias, + memo= ryDeviceSizeChangeEvent->size, + cbop= aque); + 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); =20 +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 66af60a775..29efdaac6b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -502,6 +502,7 @@ virDomainMemballoonModelTypeFromString; virDomainMemballoonModelTypeToString; virDomainMemoryDefFree; virDomainMemoryFindByDef; +virDomainMemoryFindByDeviceAlias; virDomainMemoryFindByDeviceInfo; virDomainMemoryFindInactiveByDef; virDomainMemoryInsert; @@ -716,6 +717,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 c182b47f38..226e1d9b79 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -11053,6 +11053,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 2626f5dcaa..3302ced640 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -427,6 +427,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, =20 QEMU_PROCESS_EVENT_LAST } qemuProcessEventType; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9a241ad551..b495a261d1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4317,6 +4317,40 @@ processGuestCrashloadedEvent(virQEMUDriver *driver, } =20 =20 +static void +processMemoryDeviceSizeChange(virQEMUDriver *driver, + virDomainObj *vm, + qemuMonitorMemoryDeviceSizeChange *info) +{ + virDomainMemoryDef *mem =3D NULL; + virObjectEvent *event =3D NULL; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + return; + + if (!virDomainObjIsActive(vm)) { + VIR_DEBUG("Domain is not running"); + goto endjob; + } + + mem =3D virDomainMemoryFindByDeviceAlias(vm->def, info->devAlias); + if (!mem) { + VIR_DEBUG("Memory device '%s' not found", info->devAlias); + goto endjob; + } + + mem->actualsize =3D VIR_DIV_UP(info->size, 1024); + + event =3D virDomainEventMemoryDeviceSizeChangeNewFromObj(vm, + info->devAlias, + mem->actualsize= ); + + endjob: + qemuDomainObjEndJob(driver, vm); + virObjectEventStateQueue(driver->domainEventState, event); +} + + static void qemuProcessEventHandler(void *data, void *opaque) { struct qemuProcessEvent *processEvent =3D data; @@ -4366,6 +4400,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 c5793a8238..9292d63a7f 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1449,6 +1449,20 @@ qemuMonitorEmitSpiceMigrated(qemuMonitor *mon) } =20 =20 +int +qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon, + const char *devAlias, + unsigned long long size) +{ + int ret =3D -1; + VIR_DEBUG("mon=3D%p, devAlias=3D'%s', size=3D%llu", mon, devAlias, siz= e); + + QEMU_MONITOR_CALLBACK(mon, ret, domainMemoryDeviceSizeChange, mon->vm,= devAlias, size); + + return ret; +} + + int qemuMonitorEmitMemoryFailure(qemuMonitor *mon, qemuMonitorEventMemoryFailure *mfp) @@ -4431,6 +4445,16 @@ qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGid= Status *info) } =20 =20 +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 8d27a7e3fb..078310de61 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -101,6 +101,14 @@ struct _qemuMonitorRdmaGidStatus { }; =20 =20 +typedef struct _qemuMonitorMemoryDeviceSizeChange qemuMonitorMemoryDeviceS= izeChange; +typedef qemuMonitorMemoryDeviceSizeChange *qemuMonitorMemoryDeviceSizeChan= gePtr; +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 *i= nfo); void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfo *info); void qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGidStatus *info); +void qemuMonitorMemoryDeviceSizeChangeFree(qemuMonitorMemoryDeviceSizeChan= ge *info); =20 typedef void (*qemuMonitorDestroyCallback)(qemuMonitor *mon, virDomainObj *vm, @@ -364,6 +373,12 @@ typedef int (*qemuMonitorDomainMemoryFailureCallback)(= qemuMonitor *mon, qemuMonitorEventMemo= ryFailure *mfp, void *opaque); =20 +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 domainRdmaGidStatusChang= ed; qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded; qemuMonitorDomainMemoryFailureCallback domainMemoryFailure; + qemuMonitorDomainMemoryDeviceSizeChange domainMemoryDeviceSizeChange; }; =20 qemuMonitor *qemuMonitorOpen(virDomainObj *vm, @@ -496,6 +512,10 @@ int qemuMonitorEmitSerialChange(qemuMonitor *mon, bool connected); int qemuMonitorEmitSpiceMigrated(qemuMonitor *mon); =20 +int qemuMonitorEmitMemoryDeviceSizeChange(qemuMonitor *mon, + const char *devAlias, + unsigned long long size); + int qemuMonitorEmitMemoryFailure(qemuMonitor *mon, qemuMonitorEventMemoryFailure *mfp); =20 diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e2f68e838b..071c6a19be 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -113,6 +113,7 @@ static void qemuMonitorJSONHandleDumpCompleted(qemuMoni= tor *mon, virJSONValue *d static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon, = virJSONValue *data); static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon, vi= rJSONValue *data); static void qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon, virJSONVa= lue *data); +static void qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, = virJSONValue *data); =20 typedef struct { const char *type; @@ -133,6 +134,7 @@ static qemuEventHandler eventHandlers[] =3D { { "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, }, { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, }, { "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, }, + { "MEMORY_DEVICE_SIZE_CHANGE", qemuMonitorJSONHandleMemoryDeviceSizeCh= ange, }, { "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, }, { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, }, { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, }, @@ -1320,6 +1322,28 @@ qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon, } =20 =20 +static void +qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, + virJSONValue *data) +{ + const char *name; + unsigned long long size; + + if (!(name =3D 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 e= vent", 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 9c16e51917..47fa4068b0 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1919,6 +1919,47 @@ qemuProcessHandleMemoryFailure(qemuMonitor *mon G_GN= UC_UNUSED, } =20 =20 +static int +qemuProcessHandleMemoryDeviceSizeChange(qemuMonitor *mon G_GNUC_UNUSED, + virDomainObj *vm, + const char *devAlias, + unsigned long long size, + void *opaque) +{ + virQEMUDriver *driver =3D opaque; + struct qemuProcessEvent *processEvent =3D NULL; + qemuMonitorMemoryDeviceSizeChange *info =3D NULL; + int ret =3D -1; + + virObjectLock(vm); + + VIR_DEBUG("Memory device '%s' changed size to '%llu' in domain '%s'", + devAlias, size, vm->def->name); + + info =3D g_new0(qemuMonitorMemoryDeviceSizeChange, 1); + info->devAlias =3D g_strdup(devAlias); + info->size =3D size; + + processEvent =3D g_new0(struct qemuProcessEvent, 1); + processEvent->eventType =3D QEMU_PROCESS_EVENT_MEMORY_DEVICE_SIZE_CHAN= GE; + processEvent->vm =3D virObjectRef(vm); + processEvent->data =3D g_steal_pointer(&info); + + if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) { + qemuProcessEventFree(processEvent); + virObjectUnref(vm); + goto cleanup; + } + + processEvent =3D NULL; + ret =3D 0; + cleanup: + qemuProcessEventFree(processEvent); + virObjectUnlock(vm); + return ret; +} + + static qemuMonitorCallbacks monitorCallbacks =3D { .eofNotify =3D qemuProcessHandleMonitorEOF, .errorNotify =3D qemuProcessHandleMonitorError, @@ -1952,6 +1993,7 @@ static qemuMonitorCallbacks monitorCallbacks =3D { .domainRdmaGidStatusChanged =3D qemuProcessHandleRdmaGidStatusChanged, .domainGuestCrashloaded =3D qemuProcessHandleGuestCrashloaded, .domainMemoryFailure =3D qemuProcessHandleMemoryFailure, + .domainMemoryDeviceSizeChange =3D qemuProcessHandleMemoryDeviceSizeCha= nge, }; =20 static void diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon= _dispatch.c index 1b4f5256c3..285078f772 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1333,6 +1333,35 @@ remoteRelayDomainEventMemoryFailure(virConnectPtr co= nn, } =20 =20 +static int +remoteRelayDomainEventMemoryDeviceSizeChange(virConnectPtr conn, + virDomainPtr dom, + const char *alias, + unsigned long long size, + void *opaque) +{ + daemonClientEventCallback *callback =3D 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 =3D callback->callbackID; + data.alias =3D g_strdup(alias); + data.size =3D size; + make_nonnull_domain(&data.dom, dom); + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_S= IZE_CHANGE, + (xdrproc_t)xdr_remote_domain_event_memor= y_device_size_change_msg, + &data); + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -1360,6 +1389,7 @@ static virConnectDomainEventGenericCallback domainEve= ntCallbacks[] =3D { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryFailure), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMemoryDeviceSizeChange= ), }; =20 G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) =3D=3D VIR_DOMAIN_EVENT= _ID_LAST); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 0c72d69933..0e0b92d584 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -410,6 +410,10 @@ remoteDomainBuildEventMemoryFailure(virNetClientProgra= m *prog, void *evdata, void *opaque); =20 static void +remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog, + virNetClient *client, + void *evdata, void *opaque); +static void remoteConnectNotifyEventConnectionClosed(virNetClientProgram *prog G_GNUC_= UNUSED, virNetClient *client G_GNUC_UNUSE= D, void *evdata, void *opaque); @@ -624,6 +628,10 @@ static virNetClientProgramEvent remoteEvents[] =3D { 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 }, }; =20 static void @@ -5462,6 +5470,30 @@ remoteDomainBuildEventMemoryFailure(virNetClientProg= ram *prog G_GNUC_UNUSED, } =20 =20 +static void +remoteDomainBuildEventMemoryDeviceSizeChange(virNetClientProgram *prog G_G= NUC_UNUSED, + virNetClient *client G_GNUC_U= NUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn =3D opaque; + remote_domain_event_memory_device_size_change_msg *msg =3D evdata; + struct private_data *priv =3D conn->privateData; + virDomainPtr dom; + virObjectEvent *event =3D NULL; + + if (!(dom =3D get_nonnull_domain(conn, msg->dom))) + return; + + event =3D virDomainEventMemoryDeviceSizeChangeNewFromDom(dom, + msg->alias, + msg->size); + + virObjectUnref(dom); + + virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackI= D); +} + + 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 { }; =20 =20 +struct remote_domain_event_memory_device_size_change_msg { + int callbackID; + remote_nonnull_domain dom; + remote_nonnull_string alias; + unsigned hyper size; +}; + /*----- Protocol. -----*/ =20 /* 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 =3D 430 + REMOTE_PROC_NODE_DEVICE_CREATE =3D 430, =20 + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE =3D 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 =3D 1, REMOTE_PROC_CONNECT_CLOSE =3D 2, @@ -3623,4 +3629,5 @@ enum remote_procedure { REMOTE_PROC_NODE_DEVICE_DEFINE_XML =3D 428, REMOTE_PROC_NODE_DEVICE_UNDEFINE =3D 429, REMOTE_PROC_NODE_DEVICE_CREATE =3D 430, + REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE =3D 431, }; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 0825f82522..7384d2d68d 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13475,6 +13475,24 @@ virshEventMemoryFailurePrint(virConnectPtr conn G_= GNUC_UNUSED, } =20 =20 +static void +virshEventMemoryDeviceSizeChangePrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + const char *alias, + unsigned long long size, + void *opaque) +{ + g_auto(virBuffer) buf =3D 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[] =3D { { "lifecycle", VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), }, @@ -13526,6 +13544,8 @@ virshDomainEventCallback virshDomainEventCallbacks[= ] =3D { 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 =3D=3D G_N_ELEMENTS(virshDomainEv= entCallbacks)); =20 --=20 2.26.3