On 4/6/26 15:43, Marc-André Lureau wrote:
Refactor the RamDiscardManager interface into two distinct components:
- RamDiscardSource: An interface that state providers (virtio-mem,
   RamBlockAttributes) implement to provide discard state information
   (granularity, populated/discarded ranges, replay callbacks).
- RamDiscardManager: A concrete QOM object that wraps a source, owns
   the listener list, and handles listener registration/unregistration
   and notifications.

This separation moves the listener management logic from individual
source implementations into the central RamDiscardManager, reducing
code duplication between virtio-mem and RamBlockAttributes.

The change prepares for future work where a RamDiscardManager could
aggregate multiple sources.

Note, the original virtio-mem code had conditions before discard:
   if (vmem->size) {
       rdl->notify_discard(rdl, rdl->section);
   }
however, the new code calls discard unconditionally. This is considered
safe, since the populate/discard of sections are already asymmetrical
(unplug & unregister all listener section unconditionally).

Reviewed-by: Peter Xu <[email protected]>
Acked-by: David Hildenbrand <[email protected]>
Signed-off-by: Marc-André Lureau <[email protected]>
---
  include/hw/virtio/virtio-mem.h |   3 -
  include/system/memory.h        | 197 +++++++++++++++++++++----------------
  include/system/ramblock.h      |   2 -
  hw/virtio/virtio-mem.c         | 163 ++++++------------------------
  system/memory.c                | 218 ++++++++++++++++++++++++++++++++++++-----
  system/ram-block-attributes.c  | 171 ++++++++++----------------------
  6 files changed, 385 insertions(+), 369 deletions(-)


+int ram_discard_manager_notify_populate(RamDiscardManager *rdm,
+                                        uint64_t offset, uint64_t size)
+{
+    RamDiscardListener *rdl, *rdl2;
+    int ret = 0;
+
+    QLIST_FOREACH(rdl, &rdm->rdl_list, next) {
+        MemoryRegionSection tmp = *rdl->section;
+
+        if (!memory_region_section_intersect_range(&tmp, offset, size)) {
+            continue;
+        }
+        ret = rdl->notify_populate(rdl, &tmp);
+        if (ret) {
+            break;
+        }
+    }
+
+    if (ret) {

(Pre-existing, reduce scope?)

           RamDiscardListener *rdl2;

+        /* Notify all already-notified listeners about discard. */
+        QLIST_FOREACH(rdl2, &rdm->rdl_list, next) {
+            MemoryRegionSection tmp = *rdl2->section;
+
+            if (rdl2 == rdl) {
+                break;
+            }
+            if (!memory_region_section_intersect_range(&tmp, offset, size)) {
+                continue;
+            }
+            rdl2->notify_discard(rdl2, &tmp);
+        }
+    }
+    return ret;
+}


  void ram_discard_manager_register_listener(RamDiscardManager *rdm,
                                             RamDiscardListener *rdl,
                                             MemoryRegionSection *section)
  {
-    RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+    int ret;
+
+    g_assert(section->mr == rdm->mr);
+
+    rdl->section = memory_region_section_new_copy(section);
+    QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next);
- g_assert(rdmc->register_listener);
-    rdmc->register_listener(rdm, rdl, section);
+    ret = ram_discard_source_replay_populated(rdm->rds, rdl->section,
+                                              rdm_populate_cb, rdl);
+    if (ret) {
+        error_report("%s: Replaying populated ranges failed: %s", __func__,
+                     strerror(-ret));

Pre-existing, should ram_discard_manager_register_listener propagate
Error*? For example the current caller provides an errp
(vfio_ram_discard_register_listener). Can be improved on top of course.

Reviewed-by: Philippe Mathieu-Daudé <[email protected]>

+    }
  }



Reply via email to