@samitouri / QOSamiQemu / commits / a947cf84c5

system/memory: add RamDiscardManager reference counting and cleanup

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 <peterx@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Link: https://lore.kernel.org/r/20260604-rdm5-v5-9-5768e6a0943d@redhat.com Signed-off-by: Peter Xu <peterx@redhat.com>

Marc-André Lureau committed Jun 4, 2026 at 17:43 UTC a947cf84c5ae1663569a2df09ebafe3210ad3474
2 files changed +13 -3
system/memory.c
+11 -3
@@ -1771,6 +1771,7 @@ static void memory_region_finalize(Object *obj)
1771 memory_region_clear_coalescing(mr);
1772 g_free((char *)mr->name);
1773 g_free(mr->ioeventfds);
1774 + object_unref(mr->rdm);
1775 }
1776
1777 Object *memory_region_owner(const MemoryRegion *mr)
@@ -2084,11 +2085,18 @@ int memory_region_add_ram_discard_source(MemoryRegion *mr,
2085 int memory_region_del_ram_discard_source(MemoryRegion *mr,
2086 RamDiscardSource *source)
2087 {
2088 + int ret;
2089 g_assert(mr->rdm);
2090
2089 - return ram_discard_manager_del_source(mr->rdm, source);
2090 -
2091 - /* if there is no source and no listener left, we could free rdm */
2091 + ret = ram_discard_manager_del_source(mr->rdm, source);
2092 + if (ret != 0) {
2093 + return ret;
2094 + }
2095 + if (QLIST_EMPTY(&mr->rdm->source_list) && QLIST_EMPTY(&mr->rdm->rdl_list)) {
2096 + object_unref(mr->rdm);
2097 + mr->rdm = NULL;
2098 + }
2099 + return 0;
2100 }
2101
2102 /* Called with rcu_read_lock held. */
system/ram-discard-manager.c
+2
@@ -549,6 +549,7 @@ void ram_discard_manager_register_listener(RamDiscardManager *rdm,
549
550 g_assert(section->mr == rdm->mr);
551
552 + object_ref(rdm);
553 rdl->section = memory_region_section_new_copy(section);
554 QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next);
555
@@ -570,6 +571,7 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm,
571 memory_region_section_free_copy(rdl->section);
572 rdl->section = NULL;
573 QLIST_REMOVE(rdl, next);
574 + object_unref(rdm);
575 }
576
577 int ram_discard_manager_replay_populated_to_listeners(RamDiscardManager *rdm)