diff options
| author | Richard Henderson <richard.henderson@linaro.org> | 2025-09-16 10:09:59 -0700 |
|---|---|---|
| committer | Richard Henderson <richard.henderson@linaro.org> | 2025-09-16 10:09:59 -0700 |
| commit | 5bf071485af9340fb7f387d071da0494f80e20d1 (patch) | |
| tree | 3ba82bbd326dd9669987559376ebfdc7cc07f234 | |
| parent | 190d5d7fd725ff754f94e8e0cbfb69f279c82b5d (diff) | |
| parent | ac7a892fd37ce4427d390ca8556203c9a2eb9d38 (diff) | |
| download | focaccia-qemu-5bf071485af9340fb7f387d071da0494f80e20d1.tar.gz focaccia-qemu-5bf071485af9340fb7f387d071da0494f80e20d1.zip | |
Merge tag 'mem-staging-pull-request' of https://gitlab.com/peterx/qemu into staging
Memory pull for 10.2 - Peter's fix on flatview_access_allowed() - Peter's fix on MR circular ref # -----BEGIN PGP SIGNATURE----- # # iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCaMg4oxIccGV0ZXJ4QHJl # ZGhhdC5jb20ACgkQO1/MzfOr1wYeLAD+LQ44LdRTjbdlAbDjSNnCorfEBFUmNysK # St4ut4Z9ZzAA+gK8DO12zc41Oi51NaBdD+X0s94DCV4UFl4Cz1D8HoIF # =hAUJ # -----END PGP SIGNATURE----- # gpg: Signature made Mon 15 Sep 2025 09:02:43 AM PDT # gpg: using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706 # gpg: issuer "peterx@redhat.com" # gpg: Good signature from "Peter Xu <xzpeter@gmail.com>" [unknown] # gpg: aka "Peter Xu <peterx@redhat.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D D1A9 3B5F CCCD F3AB D706 * tag 'mem-staging-pull-request' of https://gitlab.com/peterx/qemu: memory: Fix leaks due to owner-shared MRs circular references memory: Fix addr/len for flatview_access_allowed() Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
| -rw-r--r-- | docs/devel/memory.rst | 7 | ||||
| -rw-r--r-- | system/memory.c | 46 | ||||
| -rw-r--r-- | system/physmem.c | 4 |
3 files changed, 44 insertions, 13 deletions
diff --git a/docs/devel/memory.rst b/docs/devel/memory.rst index 57fb2aec76..42d3ca29c4 100644 --- a/docs/devel/memory.rst +++ b/docs/devel/memory.rst @@ -158,8 +158,11 @@ ioeventfd) can be changed during the region lifecycle. They take effect as soon as the region is made visible. This can be immediately, later, or never. -Destruction of a memory region happens automatically when the owner -object dies. +Destruction of a memory region happens automatically when the owner object +dies. When there are multiple memory regions under the same owner object, +the memory API will guarantee all memory regions will be properly detached +and finalized one by one. The order in which memory regions will be +finalized is not guaranteed. If however the memory region is part of a dynamically allocated data structure, you should call object_unparent() to destroy the memory region diff --git a/system/memory.c b/system/memory.c index 44701c465c..cf8cad6961 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1796,16 +1796,37 @@ static void memory_region_finalize(Object *obj) { MemoryRegion *mr = MEMORY_REGION(obj); - assert(!mr->container); - - /* We know the region is not visible in any address space (it - * does not have a container and cannot be a root either because - * it has no references, so we can blindly clear mr->enabled. - * memory_region_set_enabled instead could trigger a transaction - * and cause an infinite loop. + /* + * Each memory region (that can be freed) must have an owner, and it + * always has the same lifecycle of its owner. It means when reaching + * here, the memory region's owner's refcount is zero. + * + * Here it is possible that the MR has: + * + * (1) mr->container set, which means this MR is a subregion of a + * container MR. In this case they must share the same owner as the + * container (otherwise the container should have kept a refcount + * of this MR's owner). + * + * (2) mr->subregions non-empty, which means this MR is a container of + * one or more other MRs (which might have the the owner as this + * MR, or a different owner). + * + * We know the MR, or any MR that is attached to this one as either + * container or children, is not visible in any address space, because + * otherwise the address space should have taken at least one refcount + * of this MR's owner. So we can blindly clear mr->enabled. + * + * memory_region_set_enabled instead could trigger a transaction and + * cause an infinite loop. */ mr->enabled = false; memory_region_transaction_begin(); + if (mr->container) { + /* Must share the owner; see above comments */ + assert(mr->container->owner == mr->owner); + memory_region_del_subregion(mr->container, mr); + } while (!QTAILQ_EMPTY(&mr->subregions)) { MemoryRegion *subregion = QTAILQ_FIRST(&mr->subregions); memory_region_del_subregion(mr, subregion); @@ -2640,7 +2661,10 @@ static void memory_region_update_container_subregions(MemoryRegion *subregion) memory_region_transaction_begin(); - memory_region_ref(subregion); + if (mr->owner != subregion->owner) { + memory_region_ref(subregion); + } + QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { if (subregion->priority >= other->priority) { QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); @@ -2698,7 +2722,11 @@ void memory_region_del_subregion(MemoryRegion *mr, assert(alias->mapped_via_alias >= 0); } QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link); - memory_region_unref(subregion); + + if (mr->owner != subregion->owner) { + memory_region_unref(subregion); + } + memory_region_update_pending |= mr->enabled && subregion->enabled; memory_region_transaction_commit(); } diff --git a/system/physmem.c b/system/physmem.c index 311011156c..ddd58e9eb8 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3027,7 +3027,7 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, l = len; mr = flatview_translate(fv, addr, &mr_addr, &l, true, attrs); - if (!flatview_access_allowed(mr, attrs, addr, len)) { + if (!flatview_access_allowed(mr, attrs, mr_addr, l)) { return MEMTX_ACCESS_ERROR; } return flatview_write_continue(fv, addr, attrs, buf, len, @@ -3118,7 +3118,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr, l = len; mr = flatview_translate(fv, addr, &mr_addr, &l, false, attrs); - if (!flatview_access_allowed(mr, attrs, addr, len)) { + if (!flatview_access_allowed(mr, attrs, mr_addr, l)) { return MEMTX_ACCESS_ERROR; } return flatview_read_continue(fv, addr, attrs, buf, len, |