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