From patchwork Fri May 8 12:49:01 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 470030 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8B6601401AB for ; Fri, 8 May 2015 22:54:59 +1000 (AEST) Received: from localhost ([::1]:55618 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Yqhnt-0004b6-Dl for incoming@patchwork.ozlabs.org; Fri, 08 May 2015 08:54:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58604) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqhiW-0003eZ-Lv for qemu-devel@nongnu.org; Fri, 08 May 2015 08:49:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YqhiR-0002C4-Pm for qemu-devel@nongnu.org; Fri, 08 May 2015 08:49:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33471) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqhiR-0002Bw-JY for qemu-devel@nongnu.org; Fri, 08 May 2015 08:49:19 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t48CnIU5015829 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 8 May 2015 08:49:19 -0400 Received: from donizetti.redhat.com (ovpn-112-64.ams2.redhat.com [10.36.112.64]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t48Cn5ZK029121 for ; Fri, 8 May 2015 08:49:17 -0400 From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 8 May 2015 14:49:01 +0200 Message-Id: <1431089344-20350-7-git-send-email-pbonzini@redhat.com> In-Reply-To: <1431089344-20350-1-git-send-email-pbonzini@redhat.com> References: <1431089344-20350-1-git-send-email-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 6/9] exec: move rcu_read_lock/unlock to address_space_translate callers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Message-Id: <1426684909-95030-3-git-send-email-pbonzini@redhat.com> --- exec.c | 33 +++++++++++++++++++++++++++++---- hw/vfio/common.c | 7 +++++-- include/exec/memory.h | 4 +++- translate-all.c | 3 +++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/exec.c b/exec.c index ae37b98..e19ab22 100644 --- a/exec.c +++ b/exec.c @@ -373,6 +373,7 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) return false; } +/* Called from RCU critical section */ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, hwaddr *xlat, hwaddr *plen, bool is_write) @@ -381,7 +382,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, MemoryRegionSection *section; MemoryRegion *mr; - rcu_read_lock(); for (;;) { AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); section = address_space_translate_internal(d, addr, &addr, plen, true); @@ -409,7 +409,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, } *xlat = addr; - rcu_read_unlock(); return mr; } @@ -2329,6 +2328,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, MemoryRegion *mr; MemTxResult result = MEMTX_OK; + rcu_read_lock(); while (len > 0) { l = len; 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; addr += l; } + rcu_read_unlock(); return result; } @@ -2452,6 +2453,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as, hwaddr addr1; MemoryRegion *mr; + rcu_read_lock(); while (len > 0) { l = len; 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; addr += l; } + rcu_read_unlock(); } /* 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; hwaddr l, xlat; + rcu_read_lock(); while (len > 0) { l = len; 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; addr += l; } + rcu_read_unlock(); return true; } @@ -2624,9 +2629,12 @@ void *address_space_map(AddressSpace *as, } l = len; + rcu_read_lock(); mr = address_space_translate(as, addr, &xlat, &l, is_write); + if (!memory_access_is_direct(mr, is_write)) { if (atomic_xchg(&bounce.in_use, true)) { + rcu_read_unlock(); return NULL; } /* Avoid unbounded allocations */ @@ -2642,6 +2650,7 @@ void *address_space_map(AddressSpace *as, bounce.buffer, l); } + rcu_read_unlock(); *plen = l; return bounce.buffer; } @@ -2665,6 +2674,7 @@ void *address_space_map(AddressSpace *as, } memory_region_ref(mr); + rcu_read_unlock(); *plen = done; 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; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, false); if (l < 4 || !memory_access_is_direct(mr, false)) { /* I/O case */ @@ -2762,6 +2773,7 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr, if (result) { *result = r; } + rcu_read_unlock(); return val; } @@ -2814,6 +2826,7 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr, hwaddr addr1; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, 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) { *result = r; } + rcu_read_unlock(); return val; } @@ -2921,6 +2935,7 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as, hwaddr addr1; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, 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) { *result = r; } + rcu_read_unlock(); return val; } @@ -3007,6 +3023,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, hwaddr addr1; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, 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) { *result = r; } + rcu_read_unlock(); } 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; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, 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) { *result = r; } + rcu_read_unlock(); } 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; MemTxResult r; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr1, &l, true); if (l < 2 || !memory_access_is_direct(mr, true)) { #if defined(TARGET_WORDS_BIGENDIAN) @@ -3185,6 +3206,7 @@ static inline void address_space_stw_internal(AddressSpace *as, if (result) { *result = r; } + rcu_read_unlock(); } 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; hwaddr l = 1; + bool res; + rcu_read_lock(); 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)); + rcu_read_unlock(); + return res; } void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b012620..b1045da 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -270,13 +270,14 @@ static void vfio_iommu_map_notify(Notifier *n, void *data) * this IOMMU to its immediate target. We need to translate * it the rest of the way through to memory. */ + rcu_read_lock(); mr = address_space_translate(&address_space_memory, iotlb->translated_addr, &xlat, &len, iotlb->perm & IOMMU_WO); if (!memory_region_is_ram(mr)) { error_report("iommu map to non memory area %"HWADDR_PRIx"", xlat); - return; + goto out; } /* * 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) { error_report("iommu has granularity incompatible with target AS"); - return; + goto out; } 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); } } +out: + rcu_read_unlock(); } static void vfio_listener_region_add(MemoryListener *listener, diff --git a/include/exec/memory.h b/include/exec/memory.h index 0ccfd3b..b61c84f 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1233,7 +1233,9 @@ void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val, #endif /* 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 * @addr: address within that address space diff --git a/translate-all.c b/translate-all.c index 65a76c5..536008f 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1416,14 +1416,17 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr) MemoryRegion *mr; hwaddr l = 1; + rcu_read_lock(); mr = address_space_translate(as, addr, &addr, &l, false); if (!(memory_region_is_ram(mr) || memory_region_is_romd(mr))) { + rcu_read_unlock(); return; } ram_addr = (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK) + addr; tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); + rcu_read_unlock(); } #endif /* !defined(CONFIG_USER_ONLY) */