Once address_space_translate will only be protected by RCU, the returned MemoryRegion might disappear as soon as the RCU read-side critical section ends. Avoid this by adding a reference to the region, and dropping it in the caller of address_space_translate.
This generalizes what was done for address_space_map to other callers of address_space_translate. It is necessary to call address_space_translate out of the BQL. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- exec.c | 19 +++++++++++++++---- include/exec/memory.h | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/exec.c b/exec.c index 3e1a576..e564014 100644 --- a/exec.c +++ b/exec.c @@ -302,6 +302,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, *plen = len; *xlat = addr; + memory_region_ref(mr); return mr; } @@ -1990,6 +1991,7 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, memcpy(buf, ptr, l); } } + memory_region_unref(mr); len -= l; buf += l; addr += l; @@ -2146,7 +2148,7 @@ void *address_space_map(AddressSpace *as, bounce.addr = addr; bounce.len = l; - memory_region_ref(mr); + /* Keep the reference to mr until address_space_unmap. */ bounce.mr = mr; if (!is_write) { address_space_read(as, addr, bounce.buffer, l); @@ -2169,12 +2171,13 @@ void *address_space_map(AddressSpace *as, l = len; this_mr = address_space_translate(as, addr, &xlat, &l, is_write); + memory_region_unref(this_mr); if (this_mr != mr || xlat != base + done) { break; } } - memory_region_ref(mr); + /* Keep the reference to mr until address_space_unmap. */ *plen = done; return qemu_ram_ptr_length(raddr + base, plen); } @@ -2272,6 +2275,7 @@ static inline uint32_t ldl_phys_internal(hwaddr addr, break; } } + memory_region_unref(mr); return val; } @@ -2331,6 +2335,7 @@ static inline uint64_t ldq_phys_internal(hwaddr addr, break; } } + memory_region_unref(mr); return val; } @@ -2398,6 +2403,7 @@ static inline uint32_t lduw_phys_internal(hwaddr addr, break; } } + memory_region_unref(mr); return val; } @@ -2445,6 +2451,7 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val) } } } + memory_region_unref(mr); } /* warning: addr must be aligned */ @@ -2486,6 +2493,7 @@ static inline void stl_phys_internal(hwaddr addr, uint32_t val, } invalidate_and_set_dirty(addr1, 4); } + memory_region_unref(mr); } void stl_phys(hwaddr addr, uint32_t val) @@ -2549,6 +2557,7 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val, } invalidate_and_set_dirty(addr1, 2); } + memory_region_unref(mr); } void stw_phys(hwaddr addr, uint32_t val) @@ -2638,11 +2647,13 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr) { MemoryRegion*mr; hwaddr l = 1; + bool res; mr = address_space_translate(&address_space_memory, phys_addr, &phys_addr, &l, false); - return !(memory_region_is_ram(mr) || - memory_region_is_romd(mr)); + res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr)); + memory_region_unref(mr); + return res; } #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index b21a460..66226b1 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -986,7 +986,8 @@ bool address_space_write(AddressSpace *as, hwaddr addr, bool address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len); /* address_space_translate: translate an address range into an address space - * into a MemoryRegion and an address range into that section + * into a MemoryRegion and an address range into that section. Add a reference + * to that region. * * @as: #AddressSpace to be accessed * @addr: address within that address space -- 1.8.1.4