]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
btrfs: add support for read_iter, write_iter, and direct_IO_bvec
authorDave Kleikamp <dave.kleikamp@oracle.com>
Tue, 24 Jan 2012 16:59:04 +0000 (10:59 -0600)
committerDave Kleikamp <dave.kleikamp@oracle.com>
Tue, 24 Jan 2012 16:59:04 +0000 (10:59 -0600)
Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
fs/btrfs/file.c
fs/btrfs/inode.c

index 1c905395d140cfcfa78ff797f881c31bd0a04286..df7d21f7d92bda0c5d246af57f15f9adda37da0c 100644 (file)
@@ -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,
index c9f365b6649ed534a5584a2916390bd37ab1121d..48a3e791d4050547a6080f377b6e3550602f0ae0 100644 (file)
@@ -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,