From patchwork Wed Jul 17 19:33:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 11048185 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E7215746 for ; Wed, 17 Jul 2019 19:35:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D74EF204FB for ; Wed, 17 Jul 2019 19:35:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CA06E285D6; Wed, 17 Jul 2019 19:35:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 44BDF204FB for ; Wed, 17 Jul 2019 19:35:50 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hnpgf-0000Hl-9N; Wed, 17 Jul 2019 19:34:01 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hnpgd-0000HM-L8 for xen-devel@lists.xenproject.org; Wed, 17 Jul 2019 19:33:59 +0000 X-Inumbo-ID: d0f0b3d2-a8c9-11e9-8afc-8b45d339bfd7 Received: from mail-io1-f65.google.com (unknown [209.85.166.65]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id d0f0b3d2-a8c9-11e9-8afc-8b45d339bfd7; Wed, 17 Jul 2019 19:33:56 +0000 (UTC) Received: by mail-io1-f65.google.com with SMTP id j5so43432508ioj.8 for ; Wed, 17 Jul 2019 12:33:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cEs8uh0BztRP1QpWyft084vesYDg1M1kqUeeQXfN2QA=; b=ieA41QAFnlXUtVqAb+JM6NPJ4gWcqmHfiLDuuZ3iucw+LaWk7zKtSfmUw4iAoi3pBC jhGsaqYnfM+Kgn21fINAQd38j+mumJoF7CyWIehRF1F4tEgdVcghF2yYB8lvnxGkfVaT DnB7NoqS6doyPLU/QFpYrNbB8/ntQUUU0XwvcegkrYb2G37Cjg3LN6qPlLOxssv8Xf7l 5+qDz9MAiVI9yZfaiwAwZHAI9MOUaUeTVaZN9e0rpjcN+NGphbdibLHs5udUlnlfCoie kNG48U8xca1lS71GRtLYoF7K53YfnT6h9H+eeCNWdr6EkX7ROvdgXvchzPie5OYRY7aj KAEg== X-Gm-Message-State: APjAAAU6TJuvUIvZ08AtbumGIsLhe4CuGXk5KXYT2M7GoPGrtm4+CU4f qoci8nyeslbzRr6Dbt4aL9k7ImU/ X-Google-Smtp-Source: APXvYqw1wWU9j0YZB4Yq3mDafb2VrcuUm21sJeF1GN2DXWDhPfQoz1P2dGTt837ss9tBcNz4Ph5HSQ== X-Received: by 2002:a5e:de4d:: with SMTP id e13mr16737420ioq.272.1563392035325; Wed, 17 Jul 2019 12:33:55 -0700 (PDT) Received: from l1.lan (c-71-205-12-124.hsd1.co.comcast.net. [71.205.12.124]) by smtp.gmail.com with ESMTPSA id v13sm21743421ioq.13.2019.07.17.12.33.53 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Wed, 17 Jul 2019 12:33:54 -0700 (PDT) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Wed, 17 Jul 2019 13:33:32 -0600 Message-Id: <20190717193335.11991-3-tamas@tklengyel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190717193335.11991-1-tamas@tklengyel.com> References: <20190717193335.11991-1-tamas@tklengyel.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v6 2/5] x86/mem_sharing: copy a page_lock version to be internal to memshr X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Tamas K Lengyel , Wei Liu , George Dunlap , Andrew Cooper , Jan Beulich , Roger Pau Monne Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Patch cf4b30dca0a "Add debug code to detect illegal page_lock and put_page_type ordering" added extra sanity checking to page_lock/page_unlock for debug builds with the assumption that no hypervisor path ever locks two pages at once. This assumption doesn't hold during memory sharing so we copy a version of page_lock/unlock to be used exclusively in the memory sharing subsystem without the sanity checks. Signed-off-by: Tamas K Lengyel Acked-by: Jan Beulich Cc: George Dunlap Cc: Andrew Cooper Cc: Wei Liu Cc: Roger Pau Monne --- v6: adjust comment according to Jan's suggestion --- xen/arch/x86/mm/mem_sharing.c | 54 ++++++++++++++++++++++++++++++++--- xen/include/asm-x86/mm.h | 15 ++-------- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index 6c033d1488..a5fe89e339 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -112,13 +112,59 @@ static inline void page_sharing_dispose(struct page_info *page) #endif /* MEM_SHARING_AUDIT */ -static inline int mem_sharing_page_lock(struct page_info *pg) +/* + * Private implementations of page_lock/unlock to bypass PV-only + * sanity checks not applicable to mem-sharing. + * + * _page_lock is used in memory sharing to protect addition (share) and removal + * (unshare) of (gfn,domain) tupples to a list of gfn's that the shared page is + * currently backing. + * Nesting may happen when sharing (and locking) two pages. + * Deadlock is avoided by locking pages in increasing order. + * All memory sharing code paths take the p2m lock of the affected gfn before + * taking the lock for the underlying page. We enforce ordering between page_lock + * and p2m_lock using an mm-locks.h construct. + * + * TODO: Investigate if PGT_validated is necessary. + */ +static inline bool _page_lock(struct page_info *page) { - int rc; + unsigned long x, nx; + + do { + while ( (x = page->u.inuse.type_info) & PGT_locked ) + cpu_relax(); + nx = x + (1 | PGT_locked); + if ( !(x & PGT_validated) || + !(x & PGT_count_mask) || + !(nx & PGT_count_mask) ) + return false; + } while ( cmpxchg(&page->u.inuse.type_info, x, nx) != x ); + + return true; +} + +static inline void _page_unlock(struct page_info *page) +{ + unsigned long x, nx, y = page->u.inuse.type_info; + + do { + x = y; + ASSERT((x & PGT_count_mask) && (x & PGT_locked)); + + nx = x - (1 | PGT_locked); + /* We must not drop the last reference here. */ + ASSERT(nx & PGT_count_mask); + } while ( (y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x ); +} + +static inline bool mem_sharing_page_lock(struct page_info *pg) +{ + bool rc; pg_lock_data_t *pld = &(this_cpu(__pld)); page_sharing_mm_pre_lock(); - rc = page_lock(pg); + rc = _page_lock(pg); if ( rc ) { preempt_disable(); @@ -135,7 +181,7 @@ static inline void mem_sharing_page_unlock(struct page_info *pg) page_sharing_mm_unlock(pld->mm_unlock_level, &pld->recurse_count); preempt_enable(); - page_unlock(pg); + _page_unlock(pg); } static inline shr_handle_t get_next_handle(void) diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 6c14635270..087ad97351 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -356,24 +356,15 @@ struct platform_bad_page { const struct platform_bad_page *get_platform_badpages(unsigned int *array_size); /* Per page locks: - * page_lock() is used for two purposes: pte serialization, and memory sharing. + * page_lock() is used for pte serialization. * * All users of page lock for pte serialization live in mm.c, use it * to lock a page table page during pte updates, do not take other locks within * the critical section delimited by page_lock/unlock, and perform no * nesting. * - * All users of page lock for memory sharing live in mm/mem_sharing.c. Page_lock - * is used in memory sharing to protect addition (share) and removal (unshare) - * of (gfn,domain) tupples to a list of gfn's that the shared page is currently - * backing. Nesting may happen when sharing (and locking) two pages -- deadlock - * is avoided by locking pages in increasing order. - * All memory sharing code paths take the p2m lock of the affected gfn before - * taking the lock for the underlying page. We enforce ordering between page_lock - * and p2m_lock using an mm-locks.h construct. - * - * These two users (pte serialization and memory sharing) do not collide, since - * sharing is only supported for hvm guests, which do not perform pv pte updates. + * The use of PGT_locked in mem_sharing does not collide, since mem_sharing is + * only supported for hvm guests, which do not have PV PTEs updated. */ int page_lock(struct page_info *page); void page_unlock(struct page_info *page);