From nobody Sat Jun 13 08:00:16 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178115984797121.049163141950544; Wed, 10 Jun 2026 23:37:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wXZ26-0002jk-76; Thu, 11 Jun 2026 02:36:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1t-0002aC-JN; Thu, 11 Jun 2026 02:36:42 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1o-0002au-PW; Thu, 11 Jun 2026 02:36:41 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 65B6ZnFL023462 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Thu, 11 Jun 2026 15:35:59 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=TsNSJDVyOcGYU6m4gSDD8QifEGATGyEn9yHwhIoM3Hk=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1781159759; v=1; b=mF2vfbvGeOO/Ykbrjt1i3R4vcxbVYSbV0OnIQec8zJBWWjX7wWOJxkYruRlhNCG0 lw6OmyX5Ayo1RUwCRQSuACw1cXXACSbFubMa4TaKqBRmG3mMmN/aEpFZ6qX+ejOE eOb/EXHg0wT4yqayC8hhse98zv8qOScKsqNOXi4VWauHC4TnO08ac1JSCb4D+CxP MR81AmIuB/32sZUoKIVGmA29c3qdASb5xnQe13z/iYkWVPU0rPBpJZTm5e6VGw5h DBmzkoFRiKUX35T2YH7m8lJ2j8bb9U2jwp6YRHUUSoRX4+HQRQpHwszYmXG/l7Ff B2yy2FOKg40UYobq7dRCIQ== From: Akihiko Odaki Date: Thu, 11 Jun 2026 15:35:48 +0900 Subject: [PATCH 1/3] system/physmem: Pass RAMBlock to RAMBlockNotifier callbacks MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-ram-v1-1-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> References: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: Kevin Wolf , Hanna Reitz , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Zhao Liu , Stefano Stabellini , Anthony PERARD , "Edgar E. Iglesias" , Peter Xu , Fabiano Rosas , Paolo Bonzini , Reinoud Zandijk , Marcelo Tosatti , Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-block@nongnu.org, xen-devel@lists.xenproject.org, kvm@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-16047 X-Developer-Signature: v=1; a=openpgp-sha256; l=13441; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=YVHHTk5SH8/bAsYfALAONdD+LB4KNIwybgtMz9gwSg8=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ5ZWuNeVUL9NX+q1F+zoZ2y5s1H5cTHztqcn5D8cfvOht 6/E+kBORykLgxgXg6yYIktK0W5ujejaT4UJ8S0wc1iZQIYwcHEKwERmqDMybHxkdNTdY5/Eaf1D z99sk8/If/9KXT5aQub1AoOeRYf0xBn+hwVIW62cGdpYeeC41ONE1elH869M/hIm9mD6pv83Wrb +YgUA X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1781159849982158500 The RAM save/restore code needs the RAMBlock in RAMBlockNotifier callbacks to decide whether migration must be aborted and to update RAMBlock state for postcopy. Looking up the RAMBlock inside callbacks is hazardous: with Xen mapcache it can deadlock, and it also leaves the callback contract unclear. Pass the RAMBlock explicitly to RAMBlockNotifier callbacks. The ram_block_resized callback takes a non-const RAMBlock because it may modify the RAMBlock, while the other callbacks take const RAMBlock. Xen mapcache passes NULL because mapcache entries do not have a one-to-one relationship with RAMBlocks. ram_block_resized() is never called from Xen mapcache, so its RAMBlock argument is always non-NULL. Drop redundant parameters from ram_block_resized() because they can be derived from the RAMBlock. Keep them for the other callbacks because their RAMBlock argument may be NULL. Signed-off-by: Akihiko Odaki --- include/system/ramlist.h | 18 ++++++++++-------- block/block-ram-registrar.c | 8 ++++---- hw/core/numa.c | 18 ++++++++++-------- hw/xen/xen-mapcache.c | 6 +++--- migration/ram.c | 12 +++--------- system/physmem.c | 7 +++---- target/i386/nvmm/nvmm-all.c | 4 ++-- target/i386/sev.c | 8 ++++---- util/vfio-helpers.c | 7 ++++--- 9 files changed, 43 insertions(+), 45 deletions(-) diff --git a/include/system/ramlist.h b/include/system/ramlist.h index c7f388f487d7..32157cc84305 100644 --- a/include/system/ramlist.h +++ b/include/system/ramlist.h @@ -62,11 +62,11 @@ void qemu_mutex_lock_ramlist(void); void qemu_mutex_unlock_ramlist(void); =20 struct RAMBlockNotifier { - void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size); - void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size); - void (*ram_block_resized)(RAMBlockNotifier *n, void *host, size_t old_= size, + void (*ram_block_added)(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size); + void (*ram_block_removed)(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size); + void (*ram_block_resized)(RAMBlockNotifier *n, RAMBlock *rb, size_t new_size); QLIST_ENTRY(RAMBlockNotifier) next; }; @@ -77,9 +77,11 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, void *= opaque); =20 void ram_block_notifier_add(RAMBlockNotifier *n); void ram_block_notifier_remove(RAMBlockNotifier *n); -void ram_block_notify_add(void *host, size_t size, size_t max_size); -void ram_block_notify_remove(void *host, size_t size, size_t max_size); -void ram_block_notify_resize(void *host, size_t old_size, size_t new_size); +void ram_block_notify_add(const RAMBlock *rb, + void *host, size_t size, size_t max_size); +void ram_block_notify_remove(const RAMBlock *rb, + void *host, size_t size, size_t max_size); +void ram_block_notify_resize(RAMBlock *rb, size_t new_size); =20 GString *ram_block_format(void); =20 diff --git a/block/block-ram-registrar.c b/block/block-ram-registrar.c index fcda2b86afb2..5b938de22587 100644 --- a/block/block-ram-registrar.c +++ b/block/block-ram-registrar.c @@ -9,8 +9,8 @@ #include "system/block-ram-registrar.h" #include "qapi/error.h" =20 -static void ram_block_added(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size) +static void ram_block_added(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size) { BlockRAMRegistrar *r =3D container_of(n, BlockRAMRegistrar, notifier); Error *err =3D NULL; @@ -26,8 +26,8 @@ static void ram_block_added(RAMBlockNotifier *n, void *ho= st, size_t size, } } =20 -static void ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size) +static void ram_block_removed(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size) { BlockRAMRegistrar *r =3D container_of(n, BlockRAMRegistrar, notifier); blk_unregister_buf(r->blk, host, max_size); diff --git a/hw/core/numa.c b/hw/core/numa.c index f462883c87cf..40acb98bdd0b 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -824,7 +824,7 @@ static int ram_block_notify_add_single(RAMBlock *rb, vo= id *opaque) RAMBlockNotifier *notifier =3D opaque; =20 if (host) { - notifier->ram_block_added(notifier, host, size, max_size); + notifier->ram_block_added(notifier, rb, host, size, max_size); } return 0; } @@ -837,7 +837,7 @@ static int ram_block_notify_remove_single(RAMBlock *rb,= void *opaque) RAMBlockNotifier *notifier =3D opaque; =20 if (host) { - notifier->ram_block_removed(notifier, host, size, max_size); + notifier->ram_block_removed(notifier, rb, host, size, max_size); } return 0; } @@ -861,38 +861,40 @@ void ram_block_notifier_remove(RAMBlockNotifier *n) } } =20 -void ram_block_notify_add(void *host, size_t size, size_t max_size) +void ram_block_notify_add(const RAMBlock *rb, + void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; RAMBlockNotifier *next; =20 QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { if (notifier->ram_block_added) { - notifier->ram_block_added(notifier, host, size, max_size); + notifier->ram_block_added(notifier, rb, host, size, max_size); } } } =20 -void ram_block_notify_remove(void *host, size_t size, size_t max_size) +void ram_block_notify_remove(const RAMBlock *rb, + void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; RAMBlockNotifier *next; =20 QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { if (notifier->ram_block_removed) { - notifier->ram_block_removed(notifier, host, size, max_size); + notifier->ram_block_removed(notifier, rb, host, size, max_size= ); } } } =20 -void ram_block_notify_resize(void *host, size_t old_size, size_t new_size) +void ram_block_notify_resize(RAMBlock *rb, size_t new_size) { RAMBlockNotifier *notifier; RAMBlockNotifier *next; =20 QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { if (notifier->ram_block_resized) { - notifier->ram_block_resized(notifier, host, old_size, new_size= ); + notifier->ram_block_resized(notifier, rb, new_size); } } } diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c index 85cf0cf359ca..f321c65b630e 100644 --- a/hw/xen/xen-mapcache.c +++ b/hw/xen/xen-mapcache.c @@ -222,7 +222,7 @@ static void xen_remap_bucket(MapCache *mc, =20 if (entry->vaddr_base !=3D NULL) { if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_remove(entry->vaddr_base, entry->size, + ram_block_notify_remove(NULL, entry->vaddr_base, entry->size, entry->size); } =20 @@ -308,7 +308,7 @@ static void xen_remap_bucket(MapCache *mc, } =20 if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_add(vaddr_base, size, size); + ram_block_notify_add(NULL, vaddr_base, size, size); } =20 entry->vaddr_base =3D vaddr_base; @@ -601,7 +601,7 @@ static void xen_invalidate_map_cache_entry_unlocked(Map= Cache *mc, return; } =20 - ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size); + ram_block_notify_remove(NULL, entry->vaddr_base, entry->size, entry->s= ize); if (entry->flags & XEN_MAPCACHE_ENTRY_GRANT) { rc =3D xengnttab_unmap(xen_region_gnttabdev, entry->vaddr_base, entry->size >> mc->bucket_shift); diff --git a/migration/ram.c b/migration/ram.c index fc38ffbf8af1..6bc7f705d31a 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4699,18 +4699,12 @@ static SaveVMHandlers savevm_ram_handlers =3D { .save_postcopy_prepare =3D ram_save_postcopy_prepare, }; =20 -static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, - size_t old_size, size_t new_size) +static void ram_mig_ram_block_resized(RAMBlockNotifier *n, RAMBlock *rb, + size_t new_size) { PostcopyState ps =3D postcopy_state_get(); - ram_addr_t offset; - RAMBlock *rb =3D qemu_ram_block_from_host(host, false, &offset); Error *err =3D NULL; - - if (!rb) { - error_report("RAM block not found"); - return; - } + ram_addr_t old_size =3D qemu_ram_get_used_length(rb); =20 if (migrate_ram_is_ignored(rb)) { return; diff --git a/system/physmem.c b/system/physmem.c index 7bcbf8757361..6d00e99270c7 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -2019,7 +2019,6 @@ static int memory_try_enable_merging(void *addr, size= _t len) */ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp) { - const ram_addr_t oldsize =3D block->used_length; const ram_addr_t unaligned_size =3D newsize; =20 newsize =3D TARGET_PAGE_ALIGN(newsize); @@ -2057,7 +2056,7 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsi= ze, Error **errp) =20 /* Notify before modifying the ram block and touching the bitmaps. */ if (block->host) { - ram_block_notify_resize(block->host, oldsize, newsize); + ram_block_notify_resize(block, newsize); } =20 physical_memory_clear_dirty_range(block->offset, block->used_length); @@ -2283,7 +2282,7 @@ static void ram_block_add(RAMBlock *new_block, Error = **errp) qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); } - ram_block_notify_add(new_block->host, new_block->used_length, + ram_block_notify_add(new_block, new_block->host, new_block->used_l= ength, new_block->max_length); } return; @@ -2600,7 +2599,7 @@ void qemu_ram_free(RAMBlock *block) } =20 if (block->host) { - ram_block_notify_remove(block->host, block->used_length, + ram_block_notify_remove(block, block->host, block->used_length, block->max_length); } =20 diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 8a1af35ed32b..f29b9c504ea8 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -1134,8 +1134,8 @@ static MemoryListener nvmm_memory_listener =3D { }; =20 static void -nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size) +nvmm_ram_block_added(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size) { struct nvmm_machine *mach =3D get_nvmm_mach(); uintptr_t hva =3D (uintptr_t)host; diff --git a/target/i386/sev.c b/target/i386/sev.c index b44b5a1c2b94..63d8d36b6d41 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -329,8 +329,8 @@ sev_set_guest_state(SevCommonState *sev_common, SevStat= e new_state) } =20 static void -sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size) +sev_ram_block_added(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size) { int r; struct kvm_enc_region range; @@ -359,8 +359,8 @@ sev_ram_block_added(RAMBlockNotifier *n, void *host, si= ze_t size, } =20 static void -sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, - size_t max_size) +sev_ram_block_removed(RAMBlockNotifier *n, const RAMBlock *rb, + void *host, size_t size, size_t max_size) { int r; struct kvm_enc_region range; diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index aab0bf9d485d..5059ed44b8af 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -465,8 +465,8 @@ fail_container: return ret; } =20 -static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, void *host, - size_t size, size_t max_size) +static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, const RAMBlock = *rb, + void *host, size_t size, size_t max_= size) { QEMUVFIOState *s =3D container_of(n, QEMUVFIOState, ram_notifier); Error *local_err =3D NULL; @@ -481,7 +481,8 @@ static void qemu_vfio_ram_block_added(RAMBlockNotifier = *n, void *host, } } =20 -static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, void *host, +static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, const RAMBloc= k *rb, + void *host, size_t size, size_t max_size) { QEMUVFIOState *s =3D container_of(n, QEMUVFIOState, ram_notifier); --=20 2.54.0 From nobody Sat Jun 13 08:00:16 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178115985570278.62916112185258; Wed, 10 Jun 2026 23:37:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wXZ25-0002h4-F3; Thu, 11 Jun 2026 02:36:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1t-0002a3-0C; Thu, 11 Jun 2026 02:36:41 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1o-0002av-OF; Thu, 11 Jun 2026 02:36:40 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 65B6ZnFM023462 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Thu, 11 Jun 2026 15:35:59 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=aXY+9PaZ9XaHKvBSIeH+b5AgPj/NnaHzLDwsmvH8hlQ=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1781159759; v=1; b=abu4GAEI/P1NSGdIuUf+LkZxJ9arCs1yM0WmvQC22lVukFMsafVQiyBskXulpTEa QFlcZDFxcxcLBuXmNOqo2ulBDLK9Zop1QUDuKIm+ZDQ3+cpnTBKOtwLi6RLg7PFO 46vO1YoXM9DePYwhUsZdMFmUB87WBxv3fblz9fiJstitAdb5lr6LBpTGtgpwzk9e FnD1lKU9Zd4bRui5tRKhB6km+2fFNZGaiEgTIrl7bvZQ2/FMgziCYDvr9cS5xuxz msA2DGW9Si7chAeX3eKHvXpIjzKbJ46q/YigcI2DjnOKOZ5AOAHtjkSFRQagRJ51 +GeF8IppeFQtrtMu6KA62g== From: Akihiko Odaki Date: Thu, 11 Jun 2026 15:35:49 +0900 Subject: [PATCH 2/3] system/physmem: Notify RAMBlock migratable and idstr changes MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-ram-v1-2-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> References: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: Kevin Wolf , Hanna Reitz , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Zhao Liu , Stefano Stabellini , Anthony PERARD , "Edgar E. Iglesias" , Peter Xu , Fabiano Rosas , Paolo Bonzini , Reinoud Zandijk , Marcelo Tosatti , Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-block@nongnu.org, xen-devel@lists.xenproject.org, kvm@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-16047 X-Developer-Signature: v=1; a=openpgp-sha256; l=4261; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=QBBxWW4P2EOIbBSc38NXTlVjZmTEVPegIdLf55t33Pg=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ5ZWuE/SPP21AppC647OfWojwvszKfyx32yd33uyFScEF XTz6j7qKGVhEONikBVTZEkp2s2tEV37qTAhvgVmDisTyBAGLk4BmEjYa4b/iXJikZXL8vYxWvQ9 73hUPLtWf8ISdZ6ZnA38Df0NWlGrGBm2SB7ytVy0e8HWD4+/PitSz5ZfwHeh+UPomqS/1vtm12z hAwA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1781159858507158500 The RAM migration code assumes that the set of migratable RAMBlocks and their idstr values do not change while migration is running. Add RAMBlockNotifier callbacks for RAM_MIGRATABLE flag and idstr changes so migration can detect attempts to make such changes at runtime and abort with a clear error. Signed-off-by: Akihiko Odaki --- include/system/ramlist.h | 6 ++++++ hw/core/numa.c | 36 ++++++++++++++++++++++++++++++++++++ system/physmem.c | 9 +++++++++ 3 files changed, 51 insertions(+) diff --git a/include/system/ramlist.h b/include/system/ramlist.h index 32157cc84305..e96de5573eed 100644 --- a/include/system/ramlist.h +++ b/include/system/ramlist.h @@ -66,6 +66,9 @@ struct RAMBlockNotifier { void *host, size_t size, size_t max_size); void (*ram_block_removed)(RAMBlockNotifier *n, const RAMBlock *rb, void *host, size_t size, size_t max_size); + void (*ram_block_set_migratable)(RAMBlockNotifier *n, const RAMBlock *= rb); + void (*ram_block_unset_migratable)(RAMBlockNotifier *n, const RAMBlock= *rb); + void (*ram_block_set_idstr)(RAMBlockNotifier *n, const RAMBlock *rb); void (*ram_block_resized)(RAMBlockNotifier *n, RAMBlock *rb, size_t new_size); QLIST_ENTRY(RAMBlockNotifier) next; @@ -81,6 +84,9 @@ void ram_block_notify_add(const RAMBlock *rb, void *host, size_t size, size_t max_size); void ram_block_notify_remove(const RAMBlock *rb, void *host, size_t size, size_t max_size); +void ram_block_notify_set_migratable(const RAMBlock *rb); +void ram_block_notify_unset_migratable(const RAMBlock *rb); +void ram_block_notify_set_idstr(const RAMBlock *rb); void ram_block_notify_resize(RAMBlock *rb, size_t new_size); =20 GString *ram_block_format(void); diff --git a/hw/core/numa.c b/hw/core/numa.c index 40acb98bdd0b..0685cd1c6ccc 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -887,6 +887,42 @@ void ram_block_notify_remove(const RAMBlock *rb, } } =20 +void ram_block_notify_set_migratable(const RAMBlock *rb) +{ + RAMBlockNotifier *notifier; + RAMBlockNotifier *next; + + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { + if (notifier->ram_block_set_migratable) { + notifier->ram_block_set_migratable(notifier, rb); + } + } +} + +void ram_block_notify_unset_migratable(const RAMBlock *rb) +{ + RAMBlockNotifier *notifier; + RAMBlockNotifier *next; + + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { + if (notifier->ram_block_unset_migratable) { + notifier->ram_block_unset_migratable(notifier, rb); + } + } +} + +void ram_block_notify_set_idstr(const RAMBlock *rb) +{ + RAMBlockNotifier *notifier; + RAMBlockNotifier *next; + + QLIST_FOREACH_SAFE(notifier, &ram_list.ramblock_notifiers, next, next)= { + if (notifier->ram_block_set_idstr) { + notifier->ram_block_set_idstr(notifier, rb); + } + } +} + void ram_block_notify_resize(RAMBlock *rb, size_t new_size) { RAMBlockNotifier *notifier; diff --git a/system/physmem.c b/system/physmem.c index 6d00e99270c7..83c9243236a5 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -1911,11 +1911,17 @@ bool qemu_ram_is_migratable(const RAMBlock *rb) =20 void qemu_ram_set_migratable(RAMBlock *rb) { + /* Notify before modifying the ram block. */ + ram_block_notify_set_migratable(rb); + rb->flags |=3D RAM_MIGRATABLE; } =20 void qemu_ram_unset_migratable(RAMBlock *rb) { + /* Notify before modifying the ram block. */ + ram_block_notify_unset_migratable(rb); + rb->flags &=3D ~RAM_MIGRATABLE; } =20 @@ -1937,6 +1943,9 @@ void qemu_ram_set_idstr(RAMBlock *new_block, const ch= ar *name, DeviceState *dev) assert(new_block); assert(!new_block->idstr[0]); =20 + /* Notify before modifying the ram block. */ + ram_block_notify_set_idstr(new_block); + if (dev) { char *id =3D qdev_get_dev_path(dev); if (id) { --=20 2.54.0 From nobody Sat Jun 13 08:00:16 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1781159848689167.04669646076752; Wed, 10 Jun 2026 23:37:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wXZ25-0002hC-Fw; Thu, 11 Jun 2026 02:36:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1s-0002Zq-5Z; Thu, 11 Jun 2026 02:36:40 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXZ1o-0002at-PF; Thu, 11 Jun 2026 02:36:39 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 65B6ZnFN023462 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Thu, 11 Jun 2026 15:35:59 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=3u8QwhLa+X7Oh5rryZcKTj0YlBRGjYHqyTP8c2+QAnA=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1781159760; v=1; b=l3MckvaR+jjB+gxr4qMCvp0L4HDZC7yXAakbX0+Hf6h+bX1npV2VIT3hGCaWQnec 6azY+OdaWeTxSM/bLJzfaCtkpnZeYFzPTyJqf8p1/JnaHwWarTCqRZE4TfPWyHXk 67xYNTe6V9EnbW3t2qdDswyGtIHXaG6kVISnymqUEjg6L68EyshP7OT+iXTNpw0k jzquwB9O4VIryFX5y8y3Ibf/tiiRrURCUMMrgt5XJ9j2ui0BDIuaZmm7TdUHrsqx LlWIqVgf3waBxgJ6tjpBKdWH8dRM96gsiTf6iBq9Zp/9gimanF3XL4Sd14AtMI6L yBa84PPAiDNLNwMxwuZkxg== From: Akihiko Odaki Date: Thu, 11 Jun 2026 15:35:50 +0900 Subject: [PATCH 3/3] migration/ram: Abort on unsupported migratable RAM changes MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-ram-v1-3-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> References: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260611-ram-v1-0-a2dacf699718@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: Kevin Wolf , Hanna Reitz , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Zhao Liu , Stefano Stabellini , Anthony PERARD , "Edgar E. Iglesias" , Peter Xu , Fabiano Rosas , Paolo Bonzini , Reinoud Zandijk , Marcelo Tosatti , Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-block@nongnu.org, xen-devel@lists.xenproject.org, kvm@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-16047 X-Developer-Signature: v=1; a=openpgp-sha256; l=9885; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=+TuMv/ELGdVJRpszAAUj/bwg+XvQHvHbSPOG4nbU0t8=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ5ZWuO+MtKV+dtUsMla1ZbMW7amT33K7Nbh7Xc+UJLsI7 8y1tns7SlkYxLgYZMUUWVKKdnNrRNd+KkyIb4GZw8oEMoSBi1MAJlKzmuF/vTTnxG7WhVrMVW5K mS/XOeT++JzFNUV3cq5fv++dRo4SRoZeo7n35FndvdiffJJJu/PEJbFaW7vTeUnkS4N37zWlZ/E CAA== X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1781159849947158500 ram_mig_ram_block_resized() already aborts migration when migratable RAM is resized. Extend the same handling to other unsupported changes to the migratable RAMBlock set, such as removing a migratable RAMBlock, changing a RAMBlock's migratable state, or setting a RAMBlock's idstr. Signed-off-by: Akihiko Odaki --- include/migration/misc.h | 2 +- migration/ram.c | 117 ++++++++++++++++++++++++++++++++++++++++---= ---- 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/include/migration/misc.h b/include/migration/misc.h index 3159a5e53c3c..91015524a83d 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -40,7 +40,7 @@ void precopy_remove_notifier(NotifierWithReturn *n); int precopy_notify(PrecopyNotifyReason reason, Error **errp); =20 void qemu_guest_free_page_hint(void *addr, size_t len); -bool migrate_ram_is_ignored(RAMBlock *block); +bool migrate_ram_is_ignored(const RAMBlock *block); =20 /* migration/block.c */ =20 diff --git a/migration/ram.c b/migration/ram.c index 6bc7f705d31a..eb761644520f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -224,7 +224,7 @@ static bool postcopy_preempt_active(void) return migrate_postcopy_preempt() && migration_in_postcopy(); } =20 -bool migrate_ram_is_ignored(RAMBlock *block) +bool migrate_ram_is_ignored(const RAMBlock *block) { MigMode mode =3D migrate_mode(); return !qemu_ram_is_migratable(block) || @@ -364,6 +364,12 @@ struct RAMSrcPageRequest { QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req; }; =20 +typedef enum RAMStateStage { + RAM_STATE_STAGE_ITERATING, + RAM_STATE_STAGE_COMPLETING, + RAM_STATE_STAGE_COMPLETED, +} RAMStateStage; + /* State of RAM for migration */ struct RAMState { /* @@ -398,8 +404,8 @@ struct RAMState { uint64_t xbzrle_bytes_prev; /* Are we really using XBZRLE (e.g., after the first round). */ bool xbzrle_started; - /* Are we on the last stage of migration */ - bool last_stage; + /* Migration stage */ + RAMStateStage stage; =20 /* total handled target pages at the beginning of period */ uint64_t target_page_count_prev; @@ -635,7 +641,7 @@ static int save_xbzrle_page(RAMState *rs, PageSearchSta= tus *pss, =20 if (!cache_is_cached(XBZRLE.cache, current_addr, generation)) { xbzrle_counters.cache_miss++; - if (!rs->last_stage) { + if (rs->stage =3D=3D RAM_STATE_STAGE_ITERATING) { if (cache_insert(XBZRLE.cache, current_addr, *current_data, generation) =3D=3D -1) { return -1; @@ -674,7 +680,7 @@ static int save_xbzrle_page(RAMState *rs, PageSearchSta= tus *pss, * Update the cache contents, so that it corresponds to the data * sent, in all cases except where we skip the page. */ - if (!rs->last_stage && encoded_len !=3D 0) { + if (rs->stage =3D=3D RAM_STATE_STAGE_ITERATING && encoded_len !=3D 0) { memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE); /* * In the case where we couldn't compress, ensure that the caller @@ -840,7 +846,8 @@ static inline bool migration_bitmap_clear_dirty(RAMStat= e *rs, * * Do the same for postcopy due to the same reason. */ - if (!rs->last_stage && !migration_in_postcopy()) { + if (rs->stage =3D=3D RAM_STATE_STAGE_ITERATING && + !migration_in_postcopy()) { /* * Clear dirty bitmap if needed. This _must_ be called before we * send any of the page in the chunk because we need to make sure @@ -1316,7 +1323,7 @@ static int ram_save_page(RAMState *rs, PageSearchStat= us *pss) if (rs->xbzrle_started && !migration_in_postcopy()) { pages =3D save_xbzrle_page(rs, pss, &p, current_addr, block, offset); - if (!rs->last_stage) { + if (rs->stage =3D=3D RAM_STATE_STAGE_ITERATING) { /* Can't send this cached data async, since the cache page * might get updated before it gets to the wire */ @@ -2920,6 +2927,8 @@ static void ram_state_resume_prepare(RAMState *rs, QE= MUFile *out) RAMBlock *block; uint64_t pages =3D 0; =20 + rs->stage =3D RAM_STATE_STAGE_ITERATING; + /* * Postcopy is not using xbzrle/compression, so no need for that. * Also, since source are already halted, we don't need to care @@ -3373,7 +3382,9 @@ static int ram_save_complete(QEMUFile *f, void *opaqu= e) =20 trace_ram_save_complete(rs->migration_dirty_pages, 0); =20 - rs->last_stage =3D !migration_in_colo_state(); + if (!migration_in_colo_state()) { + rs->stage =3D RAM_STATE_STAGE_COMPLETING; + } =20 WITH_RCU_READ_LOCK_GUARD() { if (!migration_in_postcopy()) { @@ -3383,7 +3394,7 @@ static int ram_save_complete(QEMUFile *f, void *opaqu= e) ret =3D rdma_registration_start(f, RAM_CONTROL_FINISH); if (ret < 0) { qemu_file_set_error(f, ret); - return ret; + goto err; } =20 /* try transferring iterative blocks of memory */ @@ -3400,7 +3411,8 @@ static int ram_save_complete(QEMUFile *f, void *opaqu= e) } if (pages < 0) { qemu_mutex_unlock(&rs->bitmap_mutex); - return pages; + ret =3D pages; + goto err; } } qemu_mutex_unlock(&rs->bitmap_mutex); @@ -3408,7 +3420,7 @@ static int ram_save_complete(QEMUFile *f, void *opaqu= e) ret =3D rdma_registration_stop(f, RAM_CONTROL_FINISH); if (ret < 0) { qemu_file_set_error(f, ret); - return ret; + goto err; } } =20 @@ -3419,7 +3431,7 @@ static int ram_save_complete(QEMUFile *f, void *opaqu= e) */ ret =3D multifd_ram_flush_and_sync(f); if (ret < 0) { - return ret; + goto err; } } =20 @@ -3428,10 +3440,10 @@ static int ram_save_complete(QEMUFile *f, void *opa= que) =20 if (qemu_file_get_error(f)) { Error *local_err =3D NULL; - int err =3D qemu_file_get_error_obj(f, &local_err); + ret =3D -qemu_file_get_error_obj(f, &local_err); =20 error_reportf_err(local_err, "Failed to write bitmap to file: = "); - return -err; + goto err; } } =20 @@ -3439,7 +3451,14 @@ static int ram_save_complete(QEMUFile *f, void *opaq= ue) =20 trace_ram_save_complete(rs->migration_dirty_pages, 1); =20 - return qemu_fflush(f); + ret =3D qemu_fflush(f); + +err: + if (!migration_in_colo_state()) { + rs->stage =3D RAM_STATE_STAGE_COMPLETED; + } + + return ret; } =20 static void ram_state_pending(void *opaque, MigPendingData *pending, @@ -4699,6 +4718,68 @@ static SaveVMHandlers savevm_ram_handlers =3D { .save_postcopy_prepare =3D ram_save_postcopy_prepare, }; =20 +static bool ram_migration_is_running(void) +{ + return ram_state && ram_state->stage !=3D RAM_STATE_STAGE_COMPLETED; +} + +static void ram_mig_ram_block_set_migratable(RAMBlockNotifier *n, + const RAMBlock *rb) +{ + Error *err =3D NULL; + + if (!ram_migration_is_running()) { + return; + } + + error_setg(&err, "RAM block '%s' set migratable during precopy.", + rb->idstr); + migrate_error_propagate(migrate_get_current(), err); + migration_cancel(); +} + +static void ram_mig_ram_block_unset_migratable(RAMBlockNotifier *n, + const RAMBlock *rb) +{ + Error *err =3D NULL; + + if (!ram_migration_is_running()) { + return; + } + + error_setg(&err, "RAM block '%s' unset migratable during precopy.", + rb->idstr); + migrate_error_propagate(migrate_get_current(), err); + migration_cancel(); +} + +static void ram_mig_ram_block_set_idstr(RAMBlockNotifier *n, const RAMBloc= k *rb) +{ + Error *err =3D NULL; + + if (!ram_migration_is_running() || migrate_ram_is_ignored(rb)) { + return; + } + + error_setg(&err, "RAM block idstr set during precopy."); + migrate_error_propagate(migrate_get_current(), err); + migration_cancel(); +} + +static void ram_mig_ram_block_removed(RAMBlockNotifier *n, const RAMBlock = *rb, + void *host, size_t size, size_t max_= size) +{ + Error *err =3D NULL; + + if (!rb || !ram_migration_is_running() || migrate_ram_is_ignored(rb)) { + return; + } + + error_setg(&err, "RAM block '%s' removed during precopy.", rb->idstr); + migrate_error_propagate(migrate_get_current(), err); + migration_cancel(); +} + static void ram_mig_ram_block_resized(RAMBlockNotifier *n, RAMBlock *rb, size_t new_size) { @@ -4710,7 +4791,7 @@ static void ram_mig_ram_block_resized(RAMBlockNotifie= r *n, RAMBlock *rb, return; } =20 - if (migration_is_running()) { + if (ram_migration_is_running()) { /* * Precopy code on the source cannot deal with the size of RAM blo= cks * changing at random points in time - especially after sending the @@ -4754,6 +4835,10 @@ static void ram_mig_ram_block_resized(RAMBlockNotifi= er *n, RAMBlock *rb, } =20 static RAMBlockNotifier ram_mig_ram_notifier =3D { + .ram_block_removed =3D ram_mig_ram_block_removed, + .ram_block_set_migratable =3D ram_mig_ram_block_set_migratable, + .ram_block_unset_migratable =3D ram_mig_ram_block_unset_migratable, + .ram_block_set_idstr =3D ram_mig_ram_block_set_idstr, .ram_block_resized =3D ram_mig_ram_block_resized, }; =20 --=20 2.54.0