[snip] > --- > include/exec/ramblock.h | 24 +++ > system/meson.build | 1 + > system/ram-block-attribute.c | 282 +++++++++++++++++++++++++++++++++++ > 3 files changed, 307 insertions(+) > create mode 100644 system/ram-block-attribute.c
checkpatch.pl complains a lot about code line length: total: 5 errors, 34 warnings, 324 lines checked > diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h > index 0babd105c0..b8b5469db9 100644 > --- a/include/exec/ramblock.h > +++ b/include/exec/ramblock.h > @@ -23,6 +23,10 @@ > #include "cpu-common.h" > #include "qemu/rcu.h" > #include "exec/ramlist.h" > +#include "system/hostmem.h" > + > +#define TYPE_RAM_BLOCK_ATTRIBUTE "ram-block-attribute" > +OBJECT_DECLARE_TYPE(RamBlockAttribute, RamBlockAttributeClass, > RAM_BLOCK_ATTRIBUTE) Could we use "OBJECT_DECLARE_SIMPLE_TYPE" here? Since I find class doesn't have any virtual method. > struct RAMBlock { > struct rcu_head rcu; > @@ -90,5 +94,25 @@ struct RAMBlock { > */ > ram_addr_t postcopy_length; > }; > + > +struct RamBlockAttribute { > + Object parent; > + > + MemoryRegion *mr; > + > + /* 1-setting of the bit represents the memory is populated (shared) */ > + unsigned shared_bitmap_size; > + unsigned long *shared_bitmap; > + > + QLIST_HEAD(, PrivateSharedListener) psl_list; > +}; > + > +struct RamBlockAttributeClass { > + ObjectClass parent_class; > +}; With OBJECT_DECLARE_SIMPLE_TYPE, this class definition is not needed. > +int ram_block_attribute_realize(RamBlockAttribute *attr, MemoryRegion *mr); > +void ram_block_attribute_unrealize(RamBlockAttribute *attr); > + > #endif > #endif > diff --git a/system/meson.build b/system/meson.build > index 4952f4b2c7..50a5a64f1c 100644 > --- a/system/meson.build > +++ b/system/meson.build > @@ -15,6 +15,7 @@ system_ss.add(files( > 'dirtylimit.c', > 'dma-helpers.c', > 'globals.c', > + 'ram-block-attribute.c', This new file is missing a MAINTAINERS entry. > 'memory_mapping.c', > 'qdev-monitor.c', > 'qtest.c', [snip] > +static size_t ram_block_attribute_get_block_size(const RamBlockAttribute > *attr) > +{ > + /* > + * Because page conversion could be manipulated in the size of at least > 4K or 4K aligned, > + * Use the host page size as the granularity to track the memory > attribute. > + */ > + g_assert(attr && attr->mr && attr->mr->ram_block); > + g_assert(attr->mr->ram_block->page_size == qemu_real_host_page_size()); > + return attr->mr->ram_block->page_size; What about using qemu_ram_pagesize() instead of accessing ram_block->page_size directly? Additionally, maybe we can add a simple helper to get page size from RamBlockAttribute. > +} > + [snip] > +static void ram_block_attribute_psm_register_listener(GenericStateManager > *gsm, > + StateChangeListener > *scl, > + MemoryRegionSection > *section) > +{ > + RamBlockAttribute *attr = RAM_BLOCK_ATTRIBUTE(gsm); > + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, > scl); > + int ret; > + > + g_assert(section->mr == attr->mr); > + scl->section = memory_region_section_new_copy(section); > + > + QLIST_INSERT_HEAD(&attr->psl_list, psl, next); > + > + ret = ram_block_attribute_for_each_shared_section(attr, section, scl, > + > ram_block_attribute_notify_shared_cb); > + if (ret) { > + error_report("%s: Failed to register RAM discard listener: %s", > __func__, > + strerror(-ret)); There will be 2 error messages: one is the above, and another is from ram_block_attribute_for_each_shared_section(). Could we just exit to handle this error? > + } > +} > + > +static void ram_block_attribute_psm_unregister_listener(GenericStateManager > *gsm, > + StateChangeListener > *scl) > +{ > + RamBlockAttribute *attr = RAM_BLOCK_ATTRIBUTE(gsm); > + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, > scl); > + int ret; > + > + g_assert(scl->section); > + g_assert(scl->section->mr == attr->mr); > + > + ret = ram_block_attribute_for_each_shared_section(attr, scl->section, > scl, > + > ram_block_attribute_notify_private_cb); > + if (ret) { > + error_report("%s: Failed to unregister RAM discard listener: %s", > __func__, > + strerror(-ret)); Ditto. > + } > + > + memory_region_section_free_copy(scl->section); > + scl->section = NULL; > + QLIST_REMOVE(psl, next); > +} > +