Dave Kleikamp
2012-Feb-27 21:19 UTC
[RFC PATCH 21/22] btrfs: add support for read_iter, write_iter, and direct_IO_bvec
Some helpers were broken out of btrfs_direct_IO() in order to avoid code duplication in new bio_vec-based function. Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com> Cc: Zach Brown <zab@zabbo.net> Cc: Chris Mason <chris.mason@oracle.com> Cc: linux-btrfs@vger.kernel.org --- fs/btrfs/file.c | 2 + fs/btrfs/inode.c | 116 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 859ba2d..7a2fbc0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1880,6 +1880,8 @@ const struct file_operations btrfs_file_operations = { .aio_read = generic_file_aio_read, .splice_read = generic_file_splice_read, .aio_write = btrfs_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .mmap = btrfs_file_mmap, .open = generic_file_open, .release = btrfs_release_file, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 32214fe..52199e7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6151,24 +6151,14 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io out: return retval; } -static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, - unsigned long nr_segs) + +static ssize_t btrfs_pre_direct_IO(int writing, loff_t offset, size_t count, + struct inode *inode, int *write_bits) { - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; struct btrfs_ordered_extent *ordered; struct extent_state *cached_state = NULL; u64 lockstart, lockend; ssize_t ret; - int writing = rw & WRITE; - int write_bits = 0; - size_t count = iov_length(iov, nr_segs); - - if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov, - offset, nr_segs)) { - return 0; - } lockstart = offset; lockend = offset + count - 1; @@ -6176,7 +6166,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, if (writing) { ret = btrfs_delalloc_reserve_space(inode, count); if (ret) - goto out; + return ret; } while (1) { @@ -6191,8 +6181,8 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, lockend - lockstart + 1); if (!ordered) break; - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); + unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, + lockend, &cached_state, GFP_NOFS); btrfs_start_ordered_extent(inode, ordered, 1); btrfs_put_ordered_extent(ordered); cond_resched(); @@ -6203,46 +6193,99 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, * the dirty or uptodate bits */ if (writing) { - write_bits = EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING; - ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, - EXTENT_DELALLOC, 0, NULL, &cached_state, - GFP_NOFS); - if (ret) { + *write_bits = EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING; + ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, + lockend, EXTENT_DELALLOC, 0, NULL, + &cached_state, GFP_NOFS); + if (ret) clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, - lockend, EXTENT_LOCKED | write_bits, + lockend, EXTENT_LOCKED | *write_bits, 1, 0, &cached_state, GFP_NOFS); - goto out; - } } - free_extent_state(cached_state); - cached_state = NULL; - ret = __blockdev_direct_IO(rw, iocb, inode, - BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, - iov, offset, nr_segs, btrfs_get_blocks_direct, NULL, - btrfs_submit_direct, 0); + return ret; +} + +static ssize_t btrfs_post_direct_IO(ssize_t ret, loff_t offset, size_t count, + struct inode *inode, int *write_bits) +{ + struct extent_state *cached_state = NULL; if (ret < 0 && ret != -EIOCBQUEUED) { clear_extent_bit(&BTRFS_I(inode)->io_tree, offset, - offset + iov_length(iov, nr_segs) - 1, - EXTENT_LOCKED | write_bits, 1, 0, + offset + count - 1, + EXTENT_LOCKED | *write_bits, 1, 0, &cached_state, GFP_NOFS); - } else if (ret >= 0 && ret < iov_length(iov, nr_segs)) { + } else if (ret >= 0 && ret < count) { /* * We''re falling back to buffered, unlock the section we didn''t * do IO on. */ clear_extent_bit(&BTRFS_I(inode)->io_tree, offset + ret, - offset + iov_length(iov, nr_segs) - 1, - EXTENT_LOCKED | write_bits, 1, 0, + offset + count - 1, + EXTENT_LOCKED | *write_bits, 1, 0, &cached_state, GFP_NOFS); } -out: free_extent_state(cached_state); return ret; } +static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + ssize_t ret; + int writing = rw & WRITE; + int write_bits = 0; + size_t count = iov_length(iov, nr_segs); + + if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov, + offset, nr_segs)) { + return 0; + } + + ret = btrfs_pre_direct_IO(writing, offset, count, inode, &write_bits); + if (ret) + return ret; + + ret = __blockdev_direct_IO(rw, iocb, inode, + BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, + iov, offset, nr_segs, btrfs_get_blocks_direct, NULL, + btrfs_submit_direct, 0); + + ret = btrfs_post_direct_IO(ret, offset, iov_length(iov, nr_segs), + inode, &write_bits); + return ret; +} + +static ssize_t btrfs_direct_IO_bvec(int rw, struct kiocb *iocb, + struct bio_vec *bvec, loff_t offset, + unsigned long bvec_len) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + ssize_t ret; + int writing = rw & WRITE; + int write_bits = 0; + size_t count = bvec_length(bvec, bvec_len); + + ret = btrfs_pre_direct_IO(writing, offset, count, inode, &write_bits); + if (ret) + return ret; + + ret = __blockdev_direct_IO_bvec(rw, iocb, inode, + BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, + bvec, offset, bvec_len, btrfs_get_blocks_direct, NULL, + btrfs_submit_direct, 0); + + ret = btrfs_post_direct_IO(ret, offset, bvec_length(bvec, bvec_len), + inode, &write_bits); + return ret; +} + static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { @@ -7433,6 +7476,7 @@ static const struct address_space_operations btrfs_aops = { .writepages = btrfs_writepages, .readpages = btrfs_readpages, .direct_IO = btrfs_direct_IO, + .direct_IO_bvec = btrfs_direct_IO_bvec, .invalidatepage = btrfs_invalidatepage, .releasepage = btrfs_releasepage, .set_page_dirty = btrfs_set_page_dirty, -- 1.7.9.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html