From patchwork Thu Jan 21 14:56:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 8082111 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 80F6CBEEE5 for ; Thu, 21 Jan 2016 15:03:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BF9FC2050E for ; Thu, 21 Jan 2016 15:03:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C3D3220515 for ; Thu, 21 Jan 2016 15:03:53 +0000 (UTC) Received: from localhost ([::1]:48102 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aMGm9-00083S-7U for patchwork-qemu-devel@patchwork.kernel.org; Thu, 21 Jan 2016 10:03:53 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45572) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aMGfF-0002Vv-5a for qemu-devel@nongnu.org; Thu, 21 Jan 2016 09:56:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aMGfD-0002mC-V6 for qemu-devel@nongnu.org; Thu, 21 Jan 2016 09:56:45 -0500 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:59496) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aMGfD-0002g6-O8 for qemu-devel@nongnu.org; Thu, 21 Jan 2016 09:56:43 -0500 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1aMGez-0003Qn-OV for qemu-devel@nongnu.org; Thu, 21 Jan 2016 14:56:29 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Thu, 21 Jan 2016 14:56:11 +0000 Message-Id: <1453388189-13092-19-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1453388189-13092-1-git-send-email-peter.maydell@linaro.org> References: <1453388189-13092-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 2001:8b0:1d0::1 Subject: [Qemu-devel] [PULL 18/36] memory: Add address_space_init_shareable() 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Peter Crosthwaite This will either create a new AS or return a pointer to an already existing equivalent one, if we have already created an AS for the specified root memory region. The motivation is to reuse address spaces as much as possible. It's going to be quite common that bus masters out in device land have pointers to the same memory region for their mastering yet each will need to create its own address space. Let the memory API implement sharing for them. Aside from the perf optimisations, this should reduce the amount of redundant output on info mtree as well. Thee returned value will be malloced, but the malloc will be automatically freed when the AS runs out of refs. Signed-off-by: Peter Crosthwaite [PMM: dropped check for NULL root as unused; added doc-comment; squashed Peter C's reference-counting patch into this one; don't compare name string when deciding if we can share ASes; read as->malloced before the unref of as->root to avoid possible read-after-free if as->root was the owner of as] Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- include/exec/memory.h | 18 ++++++++++++++++++ memory.c | 27 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/exec/memory.h b/include/exec/memory.h index 01f1004..c92734a 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -241,6 +241,8 @@ struct AddressSpace { struct rcu_head rcu; char *name; MemoryRegion *root; + int ref_count; + bool malloced; /* Accessed via RCU. */ struct FlatView *current_map; @@ -1189,6 +1191,22 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr, */ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name); +/** + * address_space_init_shareable: return an address space for a memory region, + * creating it if it does not already exist + * + * @root: a #MemoryRegion that routes addresses for the address space + * @name: an address space name. The name is only used for debugging + * output. + * + * This function will return a pointer to an existing AddressSpace + * which was initialized with the specified MemoryRegion, or it will + * create and initialize one if it does not already exist. The ASes + * are reference-counted, so the memory will be freed automatically + * when the AddressSpace is destroyed via address_space_destroy. + */ +AddressSpace *address_space_init_shareable(MemoryRegion *root, + const char *name); /** * address_space_destroy: destroy an address space diff --git a/memory.c b/memory.c index 93bd8ed..d2d0a92 100644 --- a/memory.c +++ b/memory.c @@ -2124,7 +2124,9 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) { memory_region_ref(root); memory_region_transaction_begin(); + as->ref_count = 1; as->root = root; + as->malloced = false; as->current_map = g_new(FlatView, 1); flatview_init(as->current_map); as->ioeventfd_nb = 0; @@ -2139,6 +2141,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) static void do_address_space_destroy(AddressSpace *as) { MemoryListener *listener; + bool do_free = as->malloced; address_space_destroy_dispatch(as); @@ -2150,12 +2153,36 @@ static void do_address_space_destroy(AddressSpace *as) g_free(as->name); g_free(as->ioeventfds); memory_region_unref(as->root); + if (do_free) { + g_free(as); + } +} + +AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name) +{ + AddressSpace *as; + + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (root == as->root && as->malloced) { + as->ref_count++; + return as; + } + } + + as = g_malloc0(sizeof *as); + address_space_init(as, root, name); + as->malloced = true; + return as; } void address_space_destroy(AddressSpace *as) { MemoryRegion *root = as->root; + as->ref_count--; + if (as->ref_count) { + return; + } /* Flush out anything from MemoryListeners listening in on this */ memory_region_transaction_begin(); as->root = NULL;