From: Goldwyn Rodrigues <rgold...@suse.com>

Create a page size extent and copy the contents of the original
extent into the new one, and present to user space as the page
to write.

Signed-off-by: Goldwyn Rodrigues <rgold...@suse.com>
---
 fs/btrfs/dax.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/fs/btrfs/dax.c b/fs/btrfs/dax.c
index 6d68d39cc5da..4634917877f3 100644
--- a/fs/btrfs/dax.c
+++ b/fs/btrfs/dax.c
@@ -231,6 +231,45 @@ vm_fault_t btrfs_dax_fault(struct vm_fault *vmf)
                sector >>= 9;
                ret = copy_user_dax(em->bdev, dax_dev, sector, PAGE_SIZE, 
vmf->cow_page, vaddr);
                goto out;
+       } else if (vmf->flags & FAULT_FLAG_WRITE) {
+               pfn_t pfn;
+               struct extent_map *orig = em;
+               void *daddr;
+               sector_t dstart;
+               size_t maplen;
+               struct extent_changeset *data_reserved = NULL;
+               struct extent_state *cached_state = NULL;
+
+               ret = btrfs_delalloc_reserve_space(inode, &data_reserved, pos, 
PAGE_SIZE);
+               if (ret < 0)
+                       return ret;
+               refcount_inc(&orig->refs);
+               lock_extent_bits(&BTRFS_I(inode)->io_tree, pos, pos + 
PAGE_SIZE, &cached_state);
+               /* Create an extent of page size */
+               ret = btrfs_get_extent_map_write(&em, NULL, inode, pos,
+                               PAGE_SIZE);
+               if (ret < 0) {
+                       free_extent_map(orig);
+                       btrfs_delalloc_release_space(inode, data_reserved, pos,
+                                       PAGE_SIZE, true);
+                       goto out;
+               }
+
+               dax_dev = fs_dax_get_by_bdev(em->bdev);
+               /* Calculate start address of destination extent */
+               dstart = (get_start_sect(em->bdev) << 9) + em->block_start;
+               maplen = dax_direct_access(dax_dev, PHYS_PFN(dstart),
+                               1, &daddr, &pfn);
+
+               /* Copy the original contents into new destination */
+               copy_extent_page(orig, daddr, pos);
+               btrfs_update_ordered_extent(inode, pos, PAGE_SIZE, true);
+               dax_insert_entry(&xas, mapping, vmf, entry, pfn, 0, false);
+               ret = vmf_insert_mixed(vmf->vma, vaddr, pfn);
+               free_extent_map(orig);
+               unlock_extent_cached(&BTRFS_I(inode)->io_tree, pos, pos + 
PAGE_SIZE, &cached_state);
+               extent_changeset_free(data_reserved);
+               btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, 
false);
        } else {
                sector_t sector;
                if (em->block_start == EXTENT_MAP_HOLE) {
-- 
2.16.4

Reply via email to