From a947cf84c5ae1663569a2df09ebafe3210ad3474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 4 Jun 2026 17:43:55 +0400 Subject: [PATCH] system/memory: add RamDiscardManager reference counting and cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Listeners now hold a reference to the RamDiscardManager, ensuring it stays alive while listeners are registered. The RDM is eagerly freed when the last source and listener are removed, and also unreffed during MemoryRegion finalization as a safety net. This completes the TODO left in the previous commit and prevents both use-after-free and memory leaks of the RamDiscardManager. Reviewed-by: Peter Xu Signed-off-by: Marc-André Lureau Link: https://lore.kernel.org/r/20260604-rdm5-v5-9-5768e6a0943d@redhat.com Signed-off-by: Peter Xu --- system/memory.c | 14 +++++++++++--- system/ram-discard-manager.c | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/system/memory.c b/system/memory.c index 119fee0d34..5fc36708ec 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1771,6 +1771,7 @@ static void memory_region_finalize(Object *obj) memory_region_clear_coalescing(mr); g_free((char *)mr->name); g_free(mr->ioeventfds); + object_unref(mr->rdm); } Object *memory_region_owner(const MemoryRegion *mr) @@ -2084,11 +2085,18 @@ int memory_region_add_ram_discard_source(MemoryRegion *mr, int memory_region_del_ram_discard_source(MemoryRegion *mr, RamDiscardSource *source) { + int ret; g_assert(mr->rdm); - return ram_discard_manager_del_source(mr->rdm, source); - - /* if there is no source and no listener left, we could free rdm */ + ret = ram_discard_manager_del_source(mr->rdm, source); + if (ret != 0) { + return ret; + } + if (QLIST_EMPTY(&mr->rdm->source_list) && QLIST_EMPTY(&mr->rdm->rdl_list)) { + object_unref(mr->rdm); + mr->rdm = NULL; + } + return 0; } /* Called with rcu_read_lock held. */ diff --git a/system/ram-discard-manager.c b/system/ram-discard-manager.c index 7da91bf648..4e8816e5a2 100644 --- a/system/ram-discard-manager.c +++ b/system/ram-discard-manager.c @@ -549,6 +549,7 @@ void ram_discard_manager_register_listener(RamDiscardManager *rdm, g_assert(section->mr == rdm->mr); + object_ref(rdm); rdl->section = memory_region_section_new_copy(section); QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next); @@ -570,6 +571,7 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, memory_region_section_free_copy(rdl->section); rdl->section = NULL; QLIST_REMOVE(rdl, next); + object_unref(rdm); } int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *rdm)