From: "Denis V. Lunev" <den@openvz.org>
To: svt-core@virtuozzo.com
Cc: andrey.drobyshev@virtuozzo.com, "Denis V. Lunev" <den@openvz.org>
Subject: [PATCH hci-8.0/hci-7.4 1/1] hostmem: fix live update crash of VMs with bound guest memory #VSTOR-147016
Date: Wed, 23 Sep 2026 18:20:55 +0200 [thread overview]
Message-ID: <20260923162056.3488196-1-den@openvz.org> (raw)
From: Denis V. Lunev <den@openvz.org>
A live QEMU update kills a VM whose memory backend has host-nodes when
the emulator cgroup no longer allows those nodes. The old QEMU saves its
state, the new one exits during startup with
qemu-kvm: cannot bind memory to host NUMA nodes: Invalid argument
and the guest is lost.
Guest RAM survives cpr-exec as the same anonymous mapping, carrying its
pages and its memory policy. host_memory_backend_memory_complete() does
not know that and treats it as fresh memory: it calls mbind() with
MPOL_MF_STRICT | MPOL_MF_MOVE and preallocates again. The exec keeps the
PID and the cgroup, so if cpuset.mems has been changed to nodes outside
host-nodes since the VM started, mbind() returns EINVAL and QEMU exits.
Where it succeeds, it only walks or migrates pages that are already in
place, while the guest is stopped.
Record in ram_block_add() that a block was reused on cpr-exec and skip
the NUMA binding and preallocation for such blocks. This is a property
of the block rather than of the incoming mode: file backends get a new
mapping after the exec and still need mbind(), and memory added later
keeps the full path.
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
backends/hostmem.c | 4 ++++
include/exec/cpu-common.h | 1 +
include/system/ramblock.h | 2 ++
system/physmem.c | 6 ++++++
4 files changed, 13 insertions(+)
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 35734d6f4d1..acb1bc8dfcb 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -363,6 +363,10 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
if (!backend->dump) {
qemu_madvise(ptr, sz, QEMU_MADV_DONTDUMP);
}
+ /* Inherited memory keeps the policy and the pages it had before exec */
+ if (qemu_ram_is_cpr_reused(backend->mr.ram_block)) {
+ return;
+ }
#ifdef CONFIG_NUMA
unsigned long lastbit = find_last_bit(backend->host_nodes, MAX_NODES);
/* lastbit == MAX_NODES means maxnode = 0 */
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 9b658a3f48f..155270b96a7 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -96,6 +96,7 @@ bool qemu_ram_is_migratable(RAMBlock *rb);
void qemu_ram_set_migratable(RAMBlock *rb);
void qemu_ram_unset_migratable(RAMBlock *rb);
bool qemu_ram_is_named_file(RAMBlock *rb);
+bool qemu_ram_is_cpr_reused(RAMBlock *rb);
int qemu_ram_get_fd(RAMBlock *rb);
size_t qemu_ram_pagesize(RAMBlock *block);
diff --git a/include/system/ramblock.h b/include/system/ramblock.h
index 87e847e184a..beaa6b23dcb 100644
--- a/include/system/ramblock.h
+++ b/include/system/ramblock.h
@@ -43,6 +43,8 @@ struct RAMBlock {
QLIST_ENTRY(RAMBlock) next;
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
Error *cpr_blocker;
+ /* Memory was inherited over cpr-exec rather than allocated */
+ bool cpr_reused;
int fd;
uint64_t fd_offset;
int guest_memfd;
diff --git a/system/physmem.c b/system/physmem.c
index 6f89232d257..4d649bc57e2 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -1668,6 +1668,11 @@ bool qemu_ram_is_named_file(RAMBlock *rb)
return rb->flags & RAM_NAMED_FILE;
}
+bool qemu_ram_is_cpr_reused(RAMBlock *rb)
+{
+ return rb->cpr_reused;
+}
+
int qemu_ram_get_fd(RAMBlock *rb)
{
return rb->fd;
@@ -1942,6 +1947,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
/* RAM block is being reused on CPR exec */
assert(ram.length == new_block->max_length);
new_block->mr->align = QEMU_VMALLOC_ALIGN;
+ new_block->cpr_reused = true;
} else {
if (ram.addr || ram.length) {
error_report("CPR mode=exec wasn't requested, but ram "
--
2.53.0
next reply other threads:[~2026-09-23 16:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 16:20 Denis V. Lunev [this message]
2026-09-23 16:42 ` Andrey Drobyshev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260923162056.3488196-1-den@openvz.org \
--to=den@openvz.org \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=svt-core@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox