From patchwork Thu Dec 2 08:48:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shiyang Ruan X-Patchwork-Id: 12652001 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3311EC433EF for ; Thu, 2 Dec 2021 08:49:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356359AbhLBIwo (ORCPT ); Thu, 2 Dec 2021 03:52:44 -0500 Received: from mail.cn.fujitsu.com ([183.91.158.132]:24741 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1356286AbhLBIwg (ORCPT ); Thu, 2 Dec 2021 03:52:36 -0500 IronPort-Data: A9a23:DMSxzqgAISvYiPuBoV5uNtAdX161CxEKZh0ujC45NGQNrF6WrkVVzmUfCm+Pb/aJNzH0eohzPo7j9x5Q65SHx9BkQQFsrnw8FHgiRejtX4rAdhiqV8+xwmwvdGo+toNGLICowPkcFhcwnT/wdOi+xZVA/fvQHOOlUraeYnkZqTJME0/NtzoywobVvaY42bBVMyvV0T/Di5W31G2NglaYAUpIg063ky6Didyp0N8uUvPSUtgQ1LPWvyF94JvyvshdJVOgKmVfNrbSq+ouUNiEEm3lExcFUrtJk57wdAsEX7zTIROTzHFRXsBOgDAb/mprjPl9b6FaNC+7iB3Q9zx14M9QvJqrWEEnOLbQsOoAURhECDw4NqpDkFPCCSHm4ZfKnhSfKBMAxN0rVinaJ7Yw9u9pAG1m++YfLTcXZBGfwemxxdqTSuJsrsUlItPiMI4Wtjdn1z6xJfovR9bBBbrL4dtZ1TIrrsFIAfvaIcEebFJHYBbfZBtAElQaEpQzmKGvnHaXWzlZrk+F4K8yy2vNxQdylr/3P7L9fMKGRMBQtkKZvX7duWD4BAwKctCS11Kt8Huqi6nEnT7TX5gbH7m1sPVthTW7wm0VFQ1TW0C3rOe0jmagVN9FbU8Z4Cwjqe417kPDZt38WQCo5X2JpBgRX/JOHOAgrgKA0KzZ50CeHGdsZjpAbsE28d84XhQ02VKT2dDkHzpitPuSU331y1s+hVteIgBMdSlbO3BCFlBDvrHeTEgIpkqnZr5e/GSd07UZwQ3N/g0= IronPort-HdrOrdr: A9a23:mvDwraliwFmD3YWrHaVEx1vVq9HpDfIQ3DAbv31ZSRFFG/Fw9vre+MjzsCWYtN9/Yh8dcK+7UpVoLUm8yXcX2/h1AV7BZniEhILAFugLgrcKqAeQeREWmNQ86Y5QN4B6CPDVSWNxlNvG5mCDeOoI8Z2q97+JiI7lo0tQcQ== X-IronPort-AV: E=Sophos;i="5.87,281,1631548800"; d="scan'208";a="118319113" Received: from unknown (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 02 Dec 2021 16:49:10 +0800 Received: from G08CNEXMBPEKD04.g08.fujitsu.local (unknown [10.167.33.201]) by cn.fujitsu.com (Postfix) with ESMTP id B5D1D4D13A1E; Thu, 2 Dec 2021 16:49:06 +0800 (CST) Received: from G08CNEXCHPEKD09.g08.fujitsu.local (10.167.33.85) by G08CNEXMBPEKD04.g08.fujitsu.local (10.167.33.201) with Microsoft SMTP Server (TLS) id 15.0.1497.23; Thu, 2 Dec 2021 16:49:07 +0800 Received: from irides.mr.mr.mr (10.167.225.141) by G08CNEXCHPEKD09.g08.fujitsu.local (10.167.33.209) with Microsoft SMTP Server id 15.0.1497.23 via Frontend Transport; Thu, 2 Dec 2021 16:49:04 +0800 From: Shiyang Ruan To: , , , , CC: , , , , Subject: [PATCH v8 9/9] fsdax: set a CoW flag when associate reflink mappings Date: Thu, 2 Dec 2021 16:48:56 +0800 Message-ID: <20211202084856.1285285-10-ruansy.fnst@fujitsu.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211202084856.1285285-1-ruansy.fnst@fujitsu.com> References: <20211202084856.1285285-1-ruansy.fnst@fujitsu.com> MIME-Version: 1.0 X-yoursite-MailScanner-ID: B5D1D4D13A1E.A2178 X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: ruansy.fnst@fujitsu.com Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Introduce a FS_DAX_MAPPING_COW flag to support association with CoW file mappings. In this case, the dax-RMAP already takes the responsibility to look up for shared files by given dax page. The page->mapping is no longer to used for rmap but for marking that this dax page is shared. And to make sure disassociation works fine, we use page->index as refcount, and clear page->mapping to the initial state when page->index is decreased to 0. With the help of this new flag, it is able to distinguish normal case and CoW case, and keep the warning in normal case. Signed-off-by: Shiyang Ruan --- fs/dax.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index 66366ba83ffc..18823f2c2385 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -335,12 +335,46 @@ static unsigned long dax_end_pfn(void *entry) pfn < dax_end_pfn(entry); pfn++) /* - * TODO: for reflink+dax we need a way to associate a single page with - * multiple address_space instances at different linear_page_index() - * offsets. + * Set FS_DAX_MAPPING_COW flag on the last bit of page->mapping to indicate that + * this is a reflink case. In this case, we associate this page->mapping with + * file mapping at the first time and only once. + */ +#define FS_DAX_MAPPING_COW 1UL + +#define MAPPING_SET_COW(m) (m = (struct address_space *)FS_DAX_MAPPING_COW) +#define MAPPING_TEST_COW(m) (((unsigned long)m & FS_DAX_MAPPING_COW) == \ + FS_DAX_MAPPING_COW) + +/* + * Set or Update the page->mapping with FS_DAX_MAPPING_COW flag. + * Return true if it is an Update. + */ +static inline bool dax_mapping_set_cow(struct page *page) +{ + if (page->mapping) { + /* flag already set */ + if (MAPPING_TEST_COW(page->mapping)) + return false; + + /* + * This page has been mapped even before it is shared, just + * need to set this FS_DAX_MAPPING_COW flag. + */ + MAPPING_SET_COW(page->mapping); + return true; + } + /* Newly associate CoW mapping */ + MAPPING_SET_COW(page->mapping); + return false; +} + +/* + * When it is called in dax_insert_entry(), the cow flag will indicate that + * whether this entry is shared by multiple files. If so, set the page->mapping + * to be FS_DAX_MAPPING_COW, and use page->index as refcount. */ static void dax_associate_entry(void *entry, struct address_space *mapping, - struct vm_area_struct *vma, unsigned long address) + struct vm_area_struct *vma, unsigned long address, bool cow) { unsigned long size = dax_entry_size(entry), pfn, index; int i = 0; @@ -352,9 +386,17 @@ static void dax_associate_entry(void *entry, struct address_space *mapping, for_each_mapped_pfn(entry, pfn) { struct page *page = pfn_to_page(pfn); - WARN_ON_ONCE(page->mapping); - page->mapping = mapping; - page->index = index + i++; + if (cow) { + if (dax_mapping_set_cow(page)) { + /* Was normal, now updated to CoW */ + page->index = 2; + } else + page->index++; + } else { + WARN_ON_ONCE(page->mapping); + page->mapping = mapping; + page->index = index + i++; + } } } @@ -370,7 +412,12 @@ static void dax_disassociate_entry(void *entry, struct address_space *mapping, struct page *page = pfn_to_page(pfn); WARN_ON_ONCE(trunc && page_ref_count(page) > 1); - WARN_ON_ONCE(page->mapping && page->mapping != mapping); + if (!MAPPING_TEST_COW(page->mapping)) { + /* keep the CoW flag if this page is still shared */ + if (page->index-- > 0) + continue; + } else + WARN_ON_ONCE(page->mapping && page->mapping != mapping); page->mapping = NULL; page->index = 0; } @@ -829,7 +876,8 @@ static void *dax_insert_entry(struct xa_state *xas, void *old; dax_disassociate_entry(entry, mapping, false); - dax_associate_entry(new_entry, mapping, vmf->vma, vmf->address); + dax_associate_entry(new_entry, mapping, vmf->vma, vmf->address, + false); /* * Only swap our new entry into the page cache if the current * entry is a zero page or an empty entry. If a normal PTE or