From nobody Sun Feb 8 18:44:51 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.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.129.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=1632232368; cv=none; d=zohomail.com; s=zohoarc; b=MS6GBsnt2lwUSrwcTeurgAcQMHgsjfcNxTJ3lrfzrZsd1BfOL5lb4eTNzJWeUgtq9ZS5GrVh6dSlO9mXKxE07babrFf/EKOZH1Zbw0yr2aVo9QcEO/Ef5ASWCy7FATbT9o7LJNVn7xIJFjEvSYKh/xy6uhxi1DhEtNirvIHnJxY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1632232368; h=Content-Type:Content-Transfer-Encoding:Cc: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=5ZE2fLL7wLCODq003UK2xSmsl4kNGgZ2pBoUVb/JVUA=; b=KzGsEQzmNxt/bBODGwFht3PPG0bbeuMF7IPoFvDG0ybe542FWVu3M4an4t2RjvMY1ymTN9AmB3+dWRafk6bp3MQaEFEjFYIVPlM5rHCrXMVB6MF1z7NPRM5eO7/irCP2o+CqdJLeR1HDWs8n1kiPVKMtnXkv3jr2vy6jdB84MHg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 163223236799444.106645776163646; Tue, 21 Sep 2021 06:52:47 -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-27-CLN4iXnPPyaS6xvDuD2sQA-1; Tue, 21 Sep 2021 09:52:45 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C475450766; Tue, 21 Sep 2021 13:52:39 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A888669FAE; Tue, 21 Sep 2021 13:52:39 +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 787014EA2F; Tue, 21 Sep 2021 13:52:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 18LDqb9k004386 for ; Tue, 21 Sep 2021 09:52:37 -0400 Received: by smtp.corp.redhat.com (Postfix) id 4EFE360938; Tue, 21 Sep 2021 13:52:37 +0000 (UTC) Received: from maggie.redhat.com (unknown [10.43.2.93]) by smtp.corp.redhat.com (Postfix) with ESMTP id 807D1608BA; Tue, 21 Sep 2021 13:52:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1632232366; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc: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=5ZE2fLL7wLCODq003UK2xSmsl4kNGgZ2pBoUVb/JVUA=; b=Nv/+AL4P13vWBKa0o1eIkqY9FlcYv5Po9rHZLlkiy7LRV0ydPg6e1T2aOtOZ9MGPSYm2NP +gdcEBW0POaTmBJlnRp9VqaSBph7R7TO65gC0rSrpJeQNgp/UuVcWLbNGgq16fklb++LsH 6R79G4ELTW2nU+7kWmlX68CJOaUbA4A= X-MC-Unique: CLN4iXnPPyaS6xvDuD2sQA-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v6 06/16] qemu: Wire up live update Date: Tue, 21 Sep 2021 15:51:22 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: libvir-list@redhat.com Cc: david@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.79 on 10.5.11.11 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) X-ZM-MESSAGEID: 1632232369450100002 Content-Type: text/plain; charset="utf-8" As advertised in one of previous commits, we want to be able to change 'requested-size' attribute of virtio-mem on the fly. This commit does exactly that. Changing anything else is checked for and forbidden. Once guest has changed the allocation, QEMU emits an event which we will use to track the allocation. In the next commit. Signed-off-by: Michal Privoznik --- src/conf/domain_conf.c | 47 +++++++++- src/conf/domain_conf.h | 5 + src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 174 ++++++++++++++++++++++++++++++++++- src/qemu/qemu_hotplug.c | 18 ++++ src/qemu/qemu_hotplug.h | 5 + src/qemu/qemu_monitor.c | 13 +++ src/qemu/qemu_monitor.h | 5 + src/qemu/qemu_monitor_json.c | 15 +++ src/qemu/qemu_monitor_json.h | 5 + 10 files changed, 286 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 82d4d124ad..c84158d0f1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16577,6 +16577,50 @@ virDomainMemoryFindInactiveByDef(virDomainDef *def, } =20 =20 +/** + * virDomainMemoryFindByDeviceInfo: + * @def: domain defintion + * @info: device info to match + * @pos: store position within array + * + * For given domain definition @def find device with + * matching address and matching device alias (if set in @info, + * otherwise ignored). + * + * If @pos is not NULL then the position of the matched device + * within the array is stored there. + * + * Returns: device if found, + * NULL otherwise. + */ +virDomainMemoryDef * +virDomainMemoryFindByDeviceInfo(virDomainDef *def, + virDomainDeviceInfo *info, + int *pos) +{ + size_t i; + + for (i =3D 0; i < def->nmems; i++) { + virDomainMemoryDef *tmp =3D def->mems[i]; + + if (!virDomainDeviceInfoAddressIsEqual(&tmp->info, info)) + continue; + + /* alias, if present */ + if (info->alias && + STRNEQ_NULLABLE(tmp->info.alias, info->alias)) + continue; + + if (pos) + *pos =3D i; + + return tmp; + } + + return NULL; +} + + /** * virDomainMemoryInsert: * @@ -28594,7 +28638,8 @@ virDomainDefCompatibleDevice(virDomainDef *def, return -1; } =20 - if ((virDomainDefGetMemoryTotal(def) + sz) > def->mem.max_memory) { + if (action =3D=3D VIR_DOMAIN_DEVICE_ACTION_ATTACH && + (virDomainDefGetMemoryTotal(def) + sz) > def->mem.max_memory) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Attaching memory device with size '%llu' wou= ld " "exceed domain's maxMemory config size '%llu'= "), diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8356d38dcb..9db15a87fb 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3807,6 +3807,11 @@ int virDomainMemoryFindByDef(virDomainDef *def, virD= omainMemoryDef *mem) int virDomainMemoryFindInactiveByDef(virDomainDef *def, virDomainMemoryDef *mem) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; +virDomainMemoryDef * +virDomainMemoryFindByDeviceInfo(virDomainDef *dev, + virDomainDeviceInfo *info, + int *pos) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; =20 int virDomainShmemDefInsert(virDomainDef *def, virDomainShmemDef *shmem) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index efb6648913..d77502922d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -508,6 +508,7 @@ virDomainMemballoonModelTypeFromString; virDomainMemballoonModelTypeToString; virDomainMemoryDefFree; virDomainMemoryFindByDef; +virDomainMemoryFindByDeviceInfo; virDomainMemoryFindInactiveByDef; virDomainMemoryInsert; virDomainMemoryModelTypeToString; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6ae678b165..1dee792dfd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7088,6 +7088,175 @@ qemuDomainChangeDiskLive(virDomainObj *vm, return 0; } =20 + +static bool +qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef, + const virDomainMemoryDef *newDef) +{ + /* The only thing that is allowed to change is 'requestedsize' for + * virtio-mem model. Check if user isn't trying to sneak in change for + * something else. */ + + switch (oldDef->model) { + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + break; + + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory of model '%s'"), + virDomainMemoryModelTypeToString(oldDef->model)); + return false; + break; + } + + if (oldDef->model !=3D newDef->model) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory model from '%s' to '%s'"), + virDomainMemoryModelTypeToString(oldDef->model), + virDomainMemoryModelTypeToString(newDef->model)); + return false; + } + + if (oldDef->access !=3D newDef->access) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory access from '%s' to '%s'"), + virDomainMemoryAccessTypeToString(oldDef->access), + virDomainMemoryAccessTypeToString(newDef->access)); + return false; + } + + if (oldDef->discard !=3D newDef->discard) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory discard from '%s' to '%s'"), + virTristateBoolTypeToString(oldDef->discard), + virTristateBoolTypeToString(newDef->discard)); + return false; + } + + if (!virBitmapEqual(oldDef->sourceNodes, + newDef->sourceNodes)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cannot modify memory source nodes")); + return false; + } + + if (oldDef->pagesize !=3D newDef->pagesize) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory pagesize from '%llu' to '%l= lu'"), + oldDef->pagesize, + newDef->pagesize); + return false; + } + + if (STRNEQ_NULLABLE(oldDef->nvdimmPath, newDef->nvdimmPath)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory path from '%s' to '%s'"), + NULLSTR(oldDef->nvdimmPath), + NULLSTR(newDef->nvdimmPath)); + return false; + } + + if (oldDef->alignsize !=3D newDef->alignsize) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory align size from '%llu' to '= %llu'"), + oldDef->alignsize, newDef->alignsize); + return false; + } + + if (oldDef->nvdimmPmem !=3D newDef->nvdimmPmem) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory pmem from '%d' to '%d'"), + oldDef->nvdimmPmem, newDef->nvdimmPmem); + return false; + } + + if (oldDef->targetNode !=3D newDef->targetNode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory targetNode from '%d' to '%d= '"), + oldDef->targetNode, newDef->targetNode); + return false; + } + + if (oldDef->size !=3D newDef->size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory size from '%llu' to '%llu'"= ), + oldDef->size, newDef->size); + return false; + } + + if (oldDef->labelsize !=3D newDef->labelsize) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory label size from '%llu' to '= %llu'"), + oldDef->labelsize, newDef->labelsize); + return false; + } + if (oldDef->blocksize !=3D newDef->blocksize) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("cannot modify memory block size from '%llu' to '= %llu'"), + oldDef->blocksize, newDef->blocksize); + return false; + } + + /* requestedsize can change */ + + if (oldDef->readonly !=3D newDef->readonly) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cannot modify memory pmem flag")); + return false; + } + + if ((oldDef->uuid || newDef->uuid) && + !(oldDef->uuid && newDef->uuid && + memcmp(oldDef->uuid, newDef->uuid, VIR_UUID_BUFLEN) =3D=3D 0)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cannot modify memory UUID")); + return false; + } + + return true; +} + + +static int +qemuDomainChangeMemoryLive(virQEMUDriver *driver G_GNUC_UNUSED, + virDomainObj *vm, + virDomainDeviceDef *dev) +{ + virDomainDeviceDef oldDev =3D { .type =3D VIR_DOMAIN_DEVICE_MEMORY }; + virDomainMemoryDef *newDef =3D dev->data.memory; + virDomainMemoryDef *oldDef =3D NULL; + + oldDef =3D virDomainMemoryFindByDeviceInfo(vm->def, &dev->data.memory-= >info, NULL); + if (!oldDef) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("memory '%s' not found"), dev->data.memory->info.= alias); + return -1; + } + + oldDev.data.memory =3D oldDef; + + if (virDomainDefCompatibleDevice(vm->def, dev, &oldDev, + VIR_DOMAIN_DEVICE_ACTION_UPDATE, + true) < 0) + return -1; + + if (!qemuDomainChangeMemoryLiveValidateChange(oldDef, newDef)) + return -1; + + if (qemuDomainChangeMemoryRequestedSize(driver, vm, + newDef->info.alias, + newDef->requestedsize) < 0) + return -1; + + oldDef->requestedsize =3D newDef->requestedsize; + return 0; +} + + static int qemuDomainUpdateDeviceLive(virDomainObj *vm, virDomainDeviceDef *dev, @@ -7129,6 +7298,10 @@ qemuDomainUpdateDeviceLive(virDomainObj *vm, ret =3D qemuDomainChangeNet(driver, vm, dev); break; =20 + case VIR_DOMAIN_DEVICE_MEMORY: + ret =3D qemuDomainChangeMemoryLive(driver, vm, dev); + break; + case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: @@ -7144,7 +7317,6 @@ qemuDomainUpdateDeviceLive(virDomainObj *vm, case VIR_DOMAIN_DEVICE_HOSTDEV: case VIR_DOMAIN_DEVICE_CONTROLLER: case VIR_DOMAIN_DEVICE_REDIRDEV: - case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_TPM: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 9c16ab4567..ccfd83cf66 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -6800,3 +6800,21 @@ qemuDomainSetVcpuInternal(virQEMUDriver *driver, virBitmapFree(livevcpus); return ret; } + + +int +qemuDomainChangeMemoryRequestedSize(virQEMUDriver *driver, + virDomainObj *vm, + const char *alias, + unsigned long long requestedsize) +{ + qemuDomainObjPrivate *priv =3D vm->privateData; + int rc; + + qemuDomainObjEnterMonitor(driver, vm); + rc =3D qemuMonitorChangeMemoryRequestedSize(priv->mon, alias, requeste= dsize); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + + return rc; +} diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index b5f7afb076..ae8feb459c 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -166,3 +166,8 @@ int qemuHotplugAttachDBusVMState(virQEMUDriver *driver, int qemuHotplugRemoveDBusVMState(virQEMUDriver *driver, virDomainObj *vm, qemuDomainAsyncJob asyncJob); + +int qemuDomainChangeMemoryRequestedSize(virQEMUDriver *driver, + virDomainObj *vm, + const char *alias, + unsigned long long requestedsize); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 42846349c4..24119ef66e 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4625,3 +4625,16 @@ qemuMonitorSetAction(qemuMonitor *mon, =20 return qemuMonitorJSONSetAction(mon, shutdown, reboot, watchdog, panic= ); } + + +int +qemuMonitorChangeMemoryRequestedSize(qemuMonitor *mon, + const char *alias, + unsigned long long requestedsize) +{ + VIR_DEBUG("alias=3D%s requestedsize=3D%llu", alias, requestedsize); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONChangeMemoryRequestedSize(mon, alias, requesteds= ize); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 2f08357c0c..0ebe73ac04 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1537,3 +1537,8 @@ qemuMonitorSetAction(qemuMonitor *mon, qemuMonitorActionReboot reboot, qemuMonitorActionWatchdog watchdog, qemuMonitorActionPanic panic); + +int +qemuMonitorChangeMemoryRequestedSize(qemuMonitor *mon, + const char *alias, + unsigned long long requestedsize); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 37e9c05d27..4ef8abb537 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -9398,3 +9398,18 @@ qemuMonitorJSONSetAction(qemuMonitor *mon, =20 return 0; } + + +int +qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitor *mon, + const char *alias, + unsigned long long requestedsize) +{ + g_autofree char *path =3D g_strdup_printf("/machine/peripheral/%s", al= ias); + qemuMonitorJSONObjectProperty prop =3D { + .type =3D QEMU_MONITOR_OBJECT_PROPERTY_ULONG, + .val.ul =3D requestedsize * 1024, /* monitor needs bytes */ + }; + + return qemuMonitorJSONSetObjectProperty(mon, path, "requested-size", &= prop); +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index c8cf734a1c..0289f8c3bf 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -710,3 +710,8 @@ qemuMonitorJSONSetAction(qemuMonitor *mon, qemuMonitorActionReboot reboot, qemuMonitorActionWatchdog watchdog, qemuMonitorActionPanic panic); + +int +qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitor *mon, + const char *alias, + unsigned long long requestedsize); --=20 2.32.0