exec: move rcu_read_lock/unlock to address_space_translate callers
Once address_space_translate will be called outside the BQL, the returned MemoryRegion might disappear as soon as the RCU read-side critical section ends. Avoid this by moving the critical section to the callers. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <1426684909-95030-3-git-send-email-pbonzini@redhat.com>
This commit is contained in:
parent
4c66375252
commit
41063e1e7a
33
exec.c
33
exec.c
@ -373,6 +373,7 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called from RCU critical section */
|
||||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||||
hwaddr *xlat, hwaddr *plen,
|
hwaddr *xlat, hwaddr *plen,
|
||||||
bool is_write)
|
bool is_write)
|
||||||
@ -381,7 +382,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
|||||||
MemoryRegionSection *section;
|
MemoryRegionSection *section;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
||||||
section = address_space_translate_internal(d, addr, &addr, plen, true);
|
section = address_space_translate_internal(d, addr, &addr, plen, true);
|
||||||
@ -409,7 +409,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*xlat = addr;
|
*xlat = addr;
|
||||||
rcu_read_unlock();
|
|
||||||
return mr;
|
return mr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2329,6 +2328,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
MemTxResult result = MEMTX_OK;
|
MemTxResult result = MEMTX_OK;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = len;
|
l = len;
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, is_write);
|
mr = address_space_translate(as, addr, &addr1, &l, is_write);
|
||||||
@ -2415,6 +2415,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
buf += l;
|
buf += l;
|
||||||
addr += l;
|
addr += l;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2452,6 +2453,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = len;
|
l = len;
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||||
@ -2477,6 +2479,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
|||||||
buf += l;
|
buf += l;
|
||||||
addr += l;
|
addr += l;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* used for ROM loading : can write in RAM and ROM */
|
/* used for ROM loading : can write in RAM and ROM */
|
||||||
@ -2585,6 +2588,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
|||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
hwaddr l, xlat;
|
hwaddr l, xlat;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = len;
|
l = len;
|
||||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||||
@ -2598,6 +2602,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
|||||||
len -= l;
|
len -= l;
|
||||||
addr += l;
|
addr += l;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2624,9 +2629,12 @@ void *address_space_map(AddressSpace *as,
|
|||||||
}
|
}
|
||||||
|
|
||||||
l = len;
|
l = len;
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||||
|
|
||||||
if (!memory_access_is_direct(mr, is_write)) {
|
if (!memory_access_is_direct(mr, is_write)) {
|
||||||
if (atomic_xchg(&bounce.in_use, true)) {
|
if (atomic_xchg(&bounce.in_use, true)) {
|
||||||
|
rcu_read_unlock();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Avoid unbounded allocations */
|
/* Avoid unbounded allocations */
|
||||||
@ -2642,6 +2650,7 @@ void *address_space_map(AddressSpace *as,
|
|||||||
bounce.buffer, l);
|
bounce.buffer, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
*plen = l;
|
*plen = l;
|
||||||
return bounce.buffer;
|
return bounce.buffer;
|
||||||
}
|
}
|
||||||
@ -2665,6 +2674,7 @@ void *address_space_map(AddressSpace *as,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memory_region_ref(mr);
|
memory_region_ref(mr);
|
||||||
|
rcu_read_unlock();
|
||||||
*plen = done;
|
*plen = done;
|
||||||
return qemu_ram_ptr_length(raddr + base, plen);
|
return qemu_ram_ptr_length(raddr + base, plen);
|
||||||
}
|
}
|
||||||
@ -2728,6 +2738,7 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
if (l < 4 || !memory_access_is_direct(mr, false)) {
|
||||||
/* I/O case */
|
/* I/O case */
|
||||||
@ -2762,6 +2773,7 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2814,6 +2826,7 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
if (l < 8 || !memory_access_is_direct(mr, false)) {
|
||||||
@ -2849,6 +2862,7 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2921,6 +2935,7 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
false);
|
false);
|
||||||
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
if (l < 2 || !memory_access_is_direct(mr, false)) {
|
||||||
@ -2956,6 +2971,7 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3007,6 +3023,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
@ -3029,6 +3046,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
|
||||||
@ -3049,6 +3067,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
true);
|
true);
|
||||||
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
if (l < 4 || !memory_access_is_direct(mr, true)) {
|
||||||
@ -3083,6 +3102,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
|
void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||||
@ -3152,6 +3172,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
|||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||||
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
if (l < 2 || !memory_access_is_direct(mr, true)) {
|
||||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
@ -3185,6 +3206,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
|||||||
if (result) {
|
if (result) {
|
||||||
*result = r;
|
*result = r;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val,
|
void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||||
@ -3322,12 +3344,15 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr)
|
|||||||
{
|
{
|
||||||
MemoryRegion*mr;
|
MemoryRegion*mr;
|
||||||
hwaddr l = 1;
|
hwaddr l = 1;
|
||||||
|
bool res;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(&address_space_memory,
|
mr = address_space_translate(&address_space_memory,
|
||||||
phys_addr, &phys_addr, &l, false);
|
phys_addr, &phys_addr, &l, false);
|
||||||
|
|
||||||
return !(memory_region_is_ram(mr) ||
|
res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
|
||||||
memory_region_is_romd(mr));
|
rcu_read_unlock();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
|
void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
|
||||||
|
@ -270,13 +270,14 @@ static void vfio_iommu_map_notify(Notifier *n, void *data)
|
|||||||
* this IOMMU to its immediate target. We need to translate
|
* this IOMMU to its immediate target. We need to translate
|
||||||
* it the rest of the way through to memory.
|
* it the rest of the way through to memory.
|
||||||
*/
|
*/
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(&address_space_memory,
|
mr = address_space_translate(&address_space_memory,
|
||||||
iotlb->translated_addr,
|
iotlb->translated_addr,
|
||||||
&xlat, &len, iotlb->perm & IOMMU_WO);
|
&xlat, &len, iotlb->perm & IOMMU_WO);
|
||||||
if (!memory_region_is_ram(mr)) {
|
if (!memory_region_is_ram(mr)) {
|
||||||
error_report("iommu map to non memory area %"HWADDR_PRIx"",
|
error_report("iommu map to non memory area %"HWADDR_PRIx"",
|
||||||
xlat);
|
xlat);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Translation truncates length to the IOMMU page size,
|
* Translation truncates length to the IOMMU page size,
|
||||||
@ -284,7 +285,7 @@ static void vfio_iommu_map_notify(Notifier *n, void *data)
|
|||||||
*/
|
*/
|
||||||
if (len & iotlb->addr_mask) {
|
if (len & iotlb->addr_mask) {
|
||||||
error_report("iommu has granularity incompatible with target AS");
|
error_report("iommu has granularity incompatible with target AS");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
|
if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) {
|
||||||
@ -307,6 +308,8 @@ static void vfio_iommu_map_notify(Notifier *n, void *data)
|
|||||||
iotlb->addr_mask + 1, ret);
|
iotlb->addr_mask + 1, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_listener_region_add(MemoryListener *listener,
|
static void vfio_listener_region_add(MemoryListener *listener,
|
||||||
|
@ -1233,7 +1233,9 @@ void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* address_space_translate: translate an address range into an address space
|
/* 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. Should be
|
||||||
|
* called from an RCU critical section, to avoid that the last reference
|
||||||
|
* to the returned region disappears after address_space_translate returns.
|
||||||
*
|
*
|
||||||
* @as: #AddressSpace to be accessed
|
* @as: #AddressSpace to be accessed
|
||||||
* @addr: address within that address space
|
* @addr: address within that address space
|
||||||
|
@ -1416,14 +1416,17 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
|
|||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
hwaddr l = 1;
|
hwaddr l = 1;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr, &l, false);
|
mr = address_space_translate(as, addr, &addr, &l, false);
|
||||||
if (!(memory_region_is_ram(mr)
|
if (!(memory_region_is_ram(mr)
|
||||||
|| memory_region_is_romd(mr))) {
|
|| memory_region_is_romd(mr))) {
|
||||||
|
rcu_read_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ram_addr = (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK)
|
ram_addr = (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK)
|
||||||
+ addr;
|
+ addr;
|
||||||
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
|
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user