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>
This commit is contained in:
Marc-André Lureau
2026-06-04 17:43:55 +04:00
committed by Peter Xu
parent a6f1bc9846
commit a947cf84c5
2 changed files with 13 additions and 3 deletions

View File

@@ -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. */

View File

@@ -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)