Whenever memory regions are accessed outside the BQL, they need to be preserved against hot-unplug. MemoryRegions actually do not have their own reference count; they piggyback on a QOM object, their "owner". Add two functions to retrieve and specify the owner.
The setter function will affect the owner recursively on a whole tree of contained regions, but without crossing (a) aliases (b) regions that are already owned by another device. This is so that a device can create a complex tree of regions and a single call to memory_region_set_owner (perhaps even within a bus-specific function, e.g. pci_register_bar) will affect the entire tree. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- include/exec/memory.h | 18 ++++++++++++++++++ memory.c | 21 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 0 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 06586f3..5c20bac 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -135,6 +135,7 @@ struct MemoryRegion { const MemoryRegionIOMMUOps *iommu_ops; void *opaque; MemoryRegion *parent; + struct Object *owner; Int128 size; hwaddr addr; void (*destructor)(MemoryRegion *mr); @@ -374,6 +375,23 @@ void memory_region_init_iommu(MemoryRegion *mr, void memory_region_destroy(MemoryRegion *mr); /** + * memory_region_owner: get a memory region's owner. + * + * @mr: the memory region being queried. + */ +struct Object *memory_region_owner(MemoryRegion *mr); + +/** + * memory_region_set_owner: set the owner for a memory region and all + * the unowned regions below it. + * + * @mr: the memory region being set. + * @owner: the object that acts as the owner + */ +void memory_region_set_owner(MemoryRegion *mr, + struct Object *owner); + +/** * memory_region_size: get a memory region's size. * * @mr: the memory region being queried. diff --git a/memory.c b/memory.c index 00e31c0..f7fddb1 100644 --- a/memory.c +++ b/memory.c @@ -789,6 +789,7 @@ void memory_region_init(MemoryRegion *mr, mr->ops = NULL; mr->iommu_ops = NULL; mr->parent = NULL; + mr->owner = NULL; mr->size = int128_make64(size); if (size == UINT64_MAX) { mr->size = int128_2_64(); @@ -1040,6 +1041,26 @@ void memory_region_destroy(MemoryRegion *mr) g_free(mr->ioeventfds); } +Object *memory_region_owner(MemoryRegion *mr) +{ + return mr->owner; +} + +void memory_region_set_owner(MemoryRegion *mr, + Object *owner) +{ + MemoryRegion *child; + + assert(mr->owner == NULL || mr->owner == owner); + mr->owner = owner; + + QTAILQ_FOREACH(child, &mr->subregions, subregions_link) { + if (child->owner == NULL || child->owner == owner) { + memory_region_set_owner(child, owner); + } + } +} + uint64_t memory_region_size(MemoryRegion *mr) { if (int128_eq(mr->size, int128_2_64())) { -- 1.7.1