Re: [PATCH v12 7/7] fsdax: set a CoW flag when associate reflink mappings

2022-04-11 Thread Christoph Hellwig
> + * 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 (dax_mapping_is_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.
> +  */
> + dax_mapping_set_cow_flag(>mapping);
> + return true;
> + }
> + /* Newly associate CoW mapping */
> + dax_mapping_set_cow_flag(>mapping);
> + return false;

Given that this is the only place calling dax_mapping_set_cow I wonder
if we should just open code it here, and also lift the page->index logic
from the caller into this helper.

static inline void dax_mapping_set_cow(struct page *page)
{
if ((uintptr_t)page->mapping != PAGE_MAPPING_DAX_COW) {
/*
 * Reset the index if the page was already mapped
 * regularly before.
 */
if (page->mapping)
page->index = 1;
page->mapping = (void *)PAGE_MAPPING_DAX_COW;
}
page->index++;
}

> + if (!dax_mapping_is_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);

Isnt the dax_mapping_is_cow check above inverted?



[PATCH v12 7/7] fsdax: set a CoW flag when associate reflink mappings

2022-04-10 Thread Shiyang Ruan
Introduce a PAGE_MAPPING_DAX_COW flag to support association with CoW file
mappings.  In this case, since the dax-rmap has already took 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.

==
PS: The @cow added for dax_associate_entry(), is used to let it know
whether the entry is to be shared during iomap operation.  It is decided
by iomap,srcmap's flag, and will be used in another patchset(
fsdax,xfs: Add reflink support for fsdax[1]).

In this patch, we set @cow always false for now.

[1] 
https://lore.kernel.org/linux-xfs/20210928062311.4012070-1-ruansy.f...@fujitsu.com/
==

Signed-off-by: Shiyang Ruan 
---
 fs/dax.c   | 65 --
 include/linux/page-flags.h |  6 
 2 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/fs/dax.c b/fs/dax.c
index 57efd3f73655..2c2958425b95 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -334,13 +334,46 @@ static unsigned long dax_end_pfn(void *entry)
for (pfn = dax_to_pfn(entry); \
pfn < dax_end_pfn(entry); pfn++)
 
+static inline void dax_mapping_set_cow_flag(struct address_space **mapping)
+{
+   *mapping = (struct address_space *)PAGE_MAPPING_DAX_COW;
+}
+
+static inline bool dax_mapping_is_cow(struct address_space *mapping)
+{
+   return (unsigned long)mapping == PAGE_MAPPING_DAX_COW;
+}
+
 /*
- * 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 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 (dax_mapping_is_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.
+*/
+   dax_mapping_set_cow_flag(>mapping);
+   return true;
+   }
+   /* Newly associate CoW mapping */
+   dax_mapping_set_cow_flag(>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 +385,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 +411,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 (!dax_mapping_is_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 +875,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,
+