From: Goldwyn Rodrigues <rgoldwyn@xxxxxxxx> Set iomap->flags to IOMAP_F_COW and fill up the source map in case the I/O is not page aligned. Signed-off-by: Goldwyn Rodrigues <rgoldwyn@xxxxxxxx> --- fs/btrfs/iomap.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/iomap.c b/fs/btrfs/iomap.c index 025ccbf471bf..f8fa34105838 100644 --- a/fs/btrfs/iomap.c +++ b/fs/btrfs/iomap.c @@ -165,6 +165,35 @@ static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode, return 0; } +/* + * get_iomap: Get the block map and fill the iomap structure + * @pos: file position + * @length: I/O length + * @iomap: The iomap structure to fill + */ + +static int get_iomap(struct inode *inode, loff_t pos, loff_t length, + struct iomap *iomap) +{ + struct extent_map *em; + iomap->addr = IOMAP_NULL_ADDR; + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, pos, length, 0); + if (IS_ERR(em)) + return PTR_ERR(em); + /* XXX Do we need to check for em->flags here? */ + if (em->block_start == EXTENT_MAP_HOLE) { + iomap->type = IOMAP_HOLE; + } else { + iomap->addr = em->block_start; + iomap->type = IOMAP_MAPPED; + } + iomap->offset = em->start; + iomap->bdev = em->bdev; + iomap->length = em->len; + free_extent_map(em); + return 0; +} + static void btrfs_buffered_page_done(struct inode *inode, loff_t pos, unsigned copied, struct page *page, struct iomap *iomap) @@ -190,6 +219,7 @@ static int btrfs_buffered_iomap_begin(struct inode *inode, loff_t pos, int ret; size_t write_bytes = length; struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + size_t end; size_t sector_offset = pos & (fs_info->sectorsize - 1); struct btrfs_iomap *bi; @@ -257,8 +287,18 @@ static int btrfs_buffered_iomap_begin(struct inode *inode, loff_t pos, iomap->private = bi; iomap->length = round_up(write_bytes, fs_info->sectorsize); iomap->offset = round_down(pos, fs_info->sectorsize); + end = pos + write_bytes; + /* Set IOMAP_F_COW if start/end is not page aligned */ + if (((pos & (PAGE_SIZE - 1)) || (end & (PAGE_SIZE - 1)))) { + iomap->flags = IOMAP_F_COW; + ret = get_iomap(inode, pos, length, srcmap); + if (ret < 0) + goto release; + } else { + iomap->type = IOMAP_DELALLOC; + } + iomap->addr = IOMAP_NULL_ADDR; - iomap->type = IOMAP_DELALLOC; iomap->bdev = fs_info->fs_devices->latest_bdev; iomap->page_ops = &btrfs_buffered_page_ops; return 0; -- 2.16.4