From: Dave Kleikamp Date: Tue, 24 Jan 2012 16:59:04 +0000 (-0600) Subject: btrfs: add support for read_iter, write_iter, and direct_IO_bvec X-Git-Tag: v2.6.39-400.9.0~594^2~2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=05079afe38feb7b0f9b9946b04314ecc9578b8eb;p=users%2Fjedix%2Flinux-maple.git btrfs: add support for read_iter, write_iter, and direct_IO_bvec Signed-off-by: Dave Kleikamp --- diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 1c905395d140..df7d21f7d92b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1714,6 +1714,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 c9f365b6649e..48a3e791d405 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6106,24 +6106,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; @@ -6131,7 +6121,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) { @@ -6146,8 +6136,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(); @@ -6158,46 +6148,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) { @@ -7382,6 +7425,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,