From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60791) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UsdOT-0006L5-60 for qemu-devel@nongnu.org; Fri, 28 Jun 2013 14:27:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UsdOP-0000SS-Ni for qemu-devel@nongnu.org; Fri, 28 Jun 2013 14:27:36 -0400 Received: from mail-ea0-x230.google.com ([2a00:1450:4013:c01::230]:62507) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UsdOP-0000S4-CV for qemu-devel@nongnu.org; Fri, 28 Jun 2013 14:27:33 -0400 Received: by mail-ea0-f176.google.com with SMTP id z15so1201110ead.35 for ; Fri, 28 Jun 2013 11:27:32 -0700 (PDT) Received: from playground.lan (net-37-116-217-184.cust.dsl.vodafone.it. [37.116.217.184]) by mx.google.com with ESMTPSA id o5sm12035344eef.5.2013.06.28.11.27.30 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 28 Jun 2013 11:27:31 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Fri, 28 Jun 2013 20:26:37 +0200 Message-Id: <1372444009-11544-19-git-send-email-pbonzini@redhat.com> In-Reply-To: <1372444009-11544-1-git-send-email-pbonzini@redhat.com> References: <1372444009-11544-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PATCH 18/30] memory: protect current_map by RCU List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 5 +++++ memory.c | 50 +++++++++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 9c33bba..aa7a922 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -24,6 +24,7 @@ #include "qemu/queue.h" #include "qemu/int128.h" #include "qemu/notify.h" +#include "qemu/rcu.h" #define MAX_PHYS_ADDR_SPACE_BITS 62 #define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1) @@ -168,9 +169,13 @@ struct MemoryRegion { */ struct AddressSpace { /* All fields are private. */ + struct rcu_head rcu; char *name; MemoryRegion *root; + + /* Accessed via RCU. */ struct FlatView *current_map; + int ioeventfd_nb; struct MemoryRegionIoeventfd *ioeventfds; struct AddressSpaceDispatch *dispatch; diff --git a/memory.c b/memory.c index bb92e17..7a4fe37 100644 --- a/memory.c +++ b/memory.c @@ -29,26 +29,12 @@ static unsigned memory_region_transaction_depth; static bool memory_region_update_pending; static bool global_dirty_log = false; -/* flat_view_mutex is taken around reading as->current_map; the critical - * section is extremely short, so I'm using a single mutex for every AS. - * We could also RCU for the read-side. - * - * The BQL is taken around transaction commits, hence both locks are taken - * while writing to as->current_map (with the BQL taken outside). - */ -static QemuMutex flat_view_mutex; - static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners = QTAILQ_HEAD_INITIALIZER(memory_listeners); static QTAILQ_HEAD(, AddressSpace) address_spaces = QTAILQ_HEAD_INITIALIZER(address_spaces); -static void memory_init(void) -{ - qemu_mutex_init(&flat_view_mutex); -} - typedef struct AddrRange AddrRange; /* @@ -239,6 +225,7 @@ struct FlatRange { * order. */ struct FlatView { + struct rcu_head rcu; unsigned ref; FlatRange *ranges; unsigned nr; @@ -610,10 +597,10 @@ static FlatView *address_space_get_flatview(AddressSpace *as) { FlatView *view; - qemu_mutex_lock(&flat_view_mutex); - view = as->current_map; + rcu_read_lock(); + view = rcu_dereference(&as->current_map); flatview_ref(view); - qemu_mutex_unlock(&flat_view_mutex); + rcu_read_unlock(); return view; } @@ -722,10 +709,9 @@ static void address_space_update_topology(AddressSpace *as) address_space_update_topology_pass(as, old_view, new_view, false); address_space_update_topology_pass(as, old_view, new_view, true); - qemu_mutex_lock(&flat_view_mutex); - flatview_unref(as->current_map); - as->current_map = new_view; - qemu_mutex_unlock(&flat_view_mutex); + /* Writes are protected by the BQL. */ + rcu_assign_pointer(as->current_map, new_view); + call_rcu(old_view, flatview_unref, rcu); /* Note that all the old MemoryRegions are still alive up to this * point. This relieves most MemoryListeners from the need to @@ -1687,10 +1673,6 @@ void memory_listener_unregister(MemoryListener *listener) void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) { - if (QTAILQ_EMPTY(&address_spaces)) { - memory_init(); - } - memory_region_transaction_begin(); as->root = root; as->current_map = g_new(FlatView, 1); @@ -1704,6 +1686,14 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) memory_region_transaction_commit(); } +static void do_address_space_destroy(AddressSpace *as) +{ + address_space_destroy_dispatch(as); + flatview_unref(as->current_map); + g_free(as->name); + g_free(as->ioeventfds); +} + void address_space_destroy(AddressSpace *as) { /* Flush out anything from MemoryListeners listening in on this */ @@ -1711,10 +1701,12 @@ void address_space_destroy(AddressSpace *as) as->root = NULL; memory_region_transaction_commit(); QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); - address_space_destroy_dispatch(as); - flatview_unref(as->current_map); - g_free(as->name); - g_free(as->ioeventfds); + + /* At this point, as->dispatch and as->current_map are dummy + * entries that the guest should never use. Wait for the old + * values to expire before freeing the data. + */ + call_rcu(as, do_address_space_destroy, rcu); } bool io_mem_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, unsigned size) -- 1.8.1.4