From patchwork Fri Jan 30 15:19:52 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 434939 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 9CE431400B6 for ; Sat, 31 Jan 2015 02:21:27 +1100 (AEDT) Received: from localhost ([::1]:37289 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YHDNt-0008AQ-MK for incoming@patchwork.ozlabs.org; Fri, 30 Jan 2015 10:21:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59361) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YHDMm-0006Xc-06 for qemu-devel@nongnu.org; Fri, 30 Jan 2015 10:20:17 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YHDMk-0005D9-N2 for qemu-devel@nongnu.org; Fri, 30 Jan 2015 10:20:15 -0500 Received: from mail-wi0-x231.google.com ([2a00:1450:400c:c05::231]:46269) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YHDMk-0005D1-E4 for qemu-devel@nongnu.org; Fri, 30 Jan 2015 10:20:14 -0500 Received: by mail-wi0-f177.google.com with SMTP id r20so3305832wiv.4 for ; Fri, 30 Jan 2015 07:20:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=ZV4isYaqgwcRpXA1B0PU7AtcQJQTBE2ymoQy1MKiXwc=; b=nWowZ52WtRqE8T7f2CgTvIDpMj46Z5SGpL2YQEOeKOM5yioUJCURkBkDm5Ou7tQURa heRTDlLGVqZpgOvhLzpRoXJjW9jbRjyKcj0Q5zrqp6Hshpa3aTE3mNlk1WdZ8ZMervgP SATC5HOMRKXxCmMB0e4DDcO4fmaBC9Glx4VJt/9nB98QsimPu/SxRI17etyKNEnZyVlk fm+coU/+xkDniCIh6XWYLfqTCQlKCMbumXrwppJYaYztaHWIJQazkrX4RZDcqIsqJtof jfsyPWrzGlKAc9vR0HKtzEIAmg47mIrstgf4rYrPJHyLMTiPysHy/jzMaYy88OVYCMQT rJUQ== X-Received: by 10.194.81.104 with SMTP id z8mr12828291wjx.45.1422631213846; Fri, 30 Jan 2015 07:20:13 -0800 (PST) Received: from playground.station (net-93-66-105-136.cust.vodafonedsl.it. [93.66.105.136]) by mx.google.com with ESMTPSA id n6sm15341184wjy.8.2015.01.30.07.20.12 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Jan 2015 07:20:12 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 30 Jan 2015 16:19:52 +0100 Message-Id: <1422631197-26063-7-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1422631197-26063-1-git-send-email-pbonzini@redhat.com> References: <1422631197-26063-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::231 Subject: [Qemu-devel] [PULL 06/11] memory: protect current_map by RCU 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 Replace the flat_view_mutex with RCU, avoiding futex contention for dataplane on large systems and many iothreads. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 5 +++++ memory.c | 54 ++++++++++++++++++++++----------------------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 0cd96b1..06ffa1d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -33,6 +33,7 @@ #include "qemu/notify.h" #include "qapi/error.h" #include "qom/object.h" +#include "qemu/rcu.h" #define MAX_PHYS_ADDR_SPACE_BITS 62 #define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1) @@ -207,9 +208,13 @@ struct MemoryListener { */ 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 8c3d8c0..a844ced 100644 --- a/memory.c +++ b/memory.c @@ -33,26 +33,12 @@ static bool memory_region_update_pending; static bool ioeventfd_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; /* @@ -242,6 +228,7 @@ struct FlatRange { * order. */ struct FlatView { + struct rcu_head rcu; unsigned ref; FlatRange *ranges; unsigned nr; @@ -654,10 +641,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 = atomic_rcu_read(&as->current_map); flatview_ref(view); - qemu_mutex_unlock(&flat_view_mutex); + rcu_read_unlock(); return view; } @@ -766,10 +753,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. */ + atomic_rcu_set(&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 @@ -1957,10 +1943,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); @@ -1974,15 +1956,10 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) memory_region_transaction_commit(); } -void address_space_destroy(AddressSpace *as) +static void do_address_space_destroy(AddressSpace *as) { MemoryListener *listener; - /* Flush out anything from MemoryListeners listening in on this */ - memory_region_transaction_begin(); - as->root = NULL; - memory_region_transaction_commit(); - QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); address_space_destroy_dispatch(as); QTAILQ_FOREACH(listener, &memory_listeners, link) { @@ -1994,6 +1971,21 @@ void address_space_destroy(AddressSpace *as) g_free(as->ioeventfds); } +void address_space_destroy(AddressSpace *as) +{ + /* Flush out anything from MemoryListeners listening in on this */ + memory_region_transaction_begin(); + as->root = NULL; + memory_region_transaction_commit(); + QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); + + /* 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) { return memory_region_dispatch_read(mr, addr, pval, size);