From: Goldwyn Rodrigues <[email protected]>

The IOMAP_DAX_COW is a iomap type which performs copy of
edges of data while performing a write if start/end are
not page aligned. The source address is expected in
iomap->inline_data.

dax_copy_edges() is a helper functions performs a copy from
one part of the device to another for data not page aligned.
If iomap->inline_data is NULL, it memset's the area to zero.

Signed-off-by: Goldwyn Rodrigues <[email protected]>
---
 fs/dax.c              | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/iomap.h |  1 +
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/fs/dax.c b/fs/dax.c
index e5e54da1715f..610bfa861a28 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1084,6 +1084,42 @@ int __dax_zero_page_range(struct block_device *bdev,
 }
 EXPORT_SYMBOL_GPL(__dax_zero_page_range);
 
+/*
+ * dax_copy_edges - Copies the part of the pages not included in
+ *                 the write, but required for CoW because
+ *                 offset/offset+length are not page aligned.
+ */
+static int dax_copy_edges(struct inode *inode, loff_t pos, loff_t length,
+                          struct iomap *iomap, void *daddr)
+{
+       unsigned offset = pos & (PAGE_SIZE - 1);
+       loff_t end = pos + length;
+       loff_t pg_end = round_up(end, PAGE_SIZE);
+       void *saddr = iomap->inline_data;
+       int ret = 0;
+       /*
+        * Copy the first part of the page
+        * Note: we pass offset as length
+        */
+       if (offset) {
+               if (saddr)
+                       ret = memcpy_mcsafe(daddr, saddr, offset);
+               else
+                       memset(daddr, 0, offset);
+       }
+
+       /* Copy the last part of the range */
+       if (end < pg_end) {
+               if (saddr)
+                       ret = memcpy_mcsafe(daddr + offset + length,
+                              saddr + offset + length, pg_end - end);
+               else
+                       memset(daddr + offset + length, 0,
+                                       pg_end - end);
+       }
+       return ret;
+}
+
 static loff_t
 dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
                struct iomap *iomap)
@@ -1105,9 +1141,11 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t 
length, void *data,
                        return iov_iter_zero(min(length, end - pos), iter);
        }
 
-       if (WARN_ON_ONCE(iomap->type != IOMAP_MAPPED))
+       if (WARN_ON_ONCE(iomap->type != IOMAP_MAPPED
+                        && iomap->type != IOMAP_DAX_COW))
                return -EIO;
 
+
        /*
         * Write can allocate block for an area which has a hole page mapped
         * into page tables. We have to tear down these mappings so that data
@@ -1144,6 +1182,12 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t 
length, void *data,
                        break;
                }
 
+               if (iomap->type == IOMAP_DAX_COW) {
+                       ret = dax_copy_edges(inode, pos, length, iomap, kaddr);
+                       if (ret)
+                               break;
+               }
+
                map_len = PFN_PHYS(map_len);
                kaddr += offset;
                map_len -= offset;
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 0fefb5455bda..6e885c5a38a3 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -25,6 +25,7 @@ struct vm_fault;
 #define IOMAP_MAPPED   0x03    /* blocks allocated at @addr */
 #define IOMAP_UNWRITTEN        0x04    /* blocks allocated at @addr in 
unwritten state */
 #define IOMAP_INLINE   0x05    /* data inline in the inode */
+#define IOMAP_DAX_COW  0x06    /* Copy data pointed by inline_data before 
write*/
 
 /*
  * Flags for all iomap mappings:
-- 
2.16.4

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to