]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - fs/direct-io.c
fuse: postpone end_page_writeback() in fuse_writepage_locked()
[linux-3.10.git] / fs / direct-io.c
index 0c85fae37666db4b18fb2bf9ebf692ae04bcbf40..7ab90f5081eebc4ab8b0de88bef8d0b6310ed113 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/uio.h>
 #include <linux/atomic.h>
 #include <linux/prefetch.h>
+#include <linux/aio.h>
 
 /*
  * How many user pages to map in one call to get_user_pages().  This determines
@@ -261,9 +262,9 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is
                dio->end_io(dio->iocb, offset, transferred,
                            dio->private, ret, is_async);
        } else {
+               inode_dio_done(dio->inode);
                if (is_async)
                        aio_complete(dio->iocb, ret, 0);
-               inode_dio_done(dio->inode);
        }
 
        return ret;
@@ -441,8 +442,8 @@ static struct bio *dio_await_one(struct dio *dio)
 static int dio_bio_complete(struct dio *dio, struct bio *bio)
 {
        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec;
-       int page_no;
+       struct bio_vec *bvec;
+       unsigned i;
 
        if (!uptodate)
                dio->io_error = -EIO;
@@ -450,8 +451,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
        if (dio->is_async && dio->rw == READ) {
                bio_check_pages_dirty(bio);     /* transfers ownership */
        } else {
-               for (page_no = 0; page_no < bio->bi_vcnt; page_no++) {
-                       struct page *page = bvec[page_no].bv_page;
+               bio_for_each_segment_all(bvec, bio, i) {
+                       struct page *page = bvec->bv_page;
 
                        if (dio->rw == READ && !PageCompound(page))
                                set_page_dirty_lock(page);
@@ -540,6 +541,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
        sector_t fs_endblk;     /* Into file, in filesystem-sized blocks */
        unsigned long fs_count; /* Number of filesystem-sized blocks */
        int create;
+       unsigned int i_blkbits = sdio->blkbits + sdio->blkfactor;
 
        /*
         * If there was a memory error and we've overwritten all the
@@ -554,7 +556,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
                fs_count = fs_endblk - fs_startblk + 1;
 
                map_bh->b_state = 0;
-               map_bh->b_size = fs_count << dio->inode->i_blkbits;
+               map_bh->b_size = fs_count << i_blkbits;
 
                /*
                 * For writes inside i_size on a DIO_SKIP_HOLES filesystem we
@@ -671,12 +673,6 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio,
                if (sdio->final_block_in_bio != sdio->cur_page_block ||
                    cur_offset != bio_next_offset)
                        dio_bio_submit(dio, sdio);
-               /*
-                * Submit now if the underlying fs is about to perform a
-                * metadata read
-                */
-               else if (sdio->boundary)
-                       dio_bio_submit(dio, sdio);
        }
 
        if (sdio->bio == NULL) {
@@ -736,16 +732,6 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
            sdio->cur_page_block +
            (sdio->cur_page_len >> sdio->blkbits) == blocknr) {
                sdio->cur_page_len += len;
-
-               /*
-                * If sdio->boundary then we want to schedule the IO now to
-                * avoid metadata seeks.
-                */
-               if (sdio->boundary) {
-                       ret = dio_send_cur_page(dio, sdio, map_bh);
-                       page_cache_release(sdio->cur_page);
-                       sdio->cur_page = NULL;
-               }
                goto out;
        }
 
@@ -757,7 +743,7 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
                page_cache_release(sdio->cur_page);
                sdio->cur_page = NULL;
                if (ret)
-                       goto out;
+                       return ret;
        }
 
        page_cache_get(page);           /* It is in dio */
@@ -767,6 +753,16 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
        sdio->cur_page_block = blocknr;
        sdio->cur_page_fs_offset = sdio->block_in_file << sdio->blkbits;
 out:
+       /*
+        * If sdio->boundary then we want to schedule the IO now to
+        * avoid metadata seeks.
+        */
+       if (sdio->boundary) {
+               ret = dio_send_cur_page(dio, sdio, map_bh);
+               dio_bio_submit(dio, sdio);
+               page_cache_release(sdio->cur_page);
+               sdio->cur_page = NULL;
+       }
        return ret;
 }
 
@@ -968,7 +964,8 @@ do_holes:
                        this_chunk_bytes = this_chunk_blocks << blkbits;
                        BUG_ON(this_chunk_bytes == 0);
 
-                       sdio->boundary = buffer_boundary(map_bh);
+                       if (this_chunk_blocks == sdio->blocks_available)
+                               sdio->boundary = buffer_boundary(map_bh);
                        ret = submit_page_section(dio, sdio, page,
                                                  offset_in_page,
                                                  this_chunk_bytes,
@@ -1053,7 +1050,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        int seg;
        size_t size;
        unsigned long addr;
-       unsigned blkbits = inode->i_blkbits;
+       unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
+       unsigned blkbits = i_blkbits;
        unsigned blocksize_mask = (1 << blkbits) - 1;
        ssize_t retval = -EINVAL;
        loff_t end = offset;
@@ -1062,6 +1060,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        unsigned long user_addr;
        size_t bytes;
        struct buffer_head map_bh = { 0, };
+       struct blk_plug plug;
 
        if (rw & WRITE)
                rw = WRITE_ODIRECT;
@@ -1148,7 +1147,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        dio->inode = inode;
        dio->rw = rw;
        sdio.blkbits = blkbits;
-       sdio.blkfactor = inode->i_blkbits - blkbits;
+       sdio.blkfactor = i_blkbits - blkbits;
        sdio.block_in_file = offset >> blkbits;
 
        sdio.get_block = get_block;
@@ -1177,6 +1176,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                                PAGE_SIZE - user_addr / PAGE_SIZE);
        }
 
+       blk_start_plug(&plug);
+
        for (seg = 0; seg < nr_segs; seg++) {
                user_addr = (unsigned long)iov[seg].iov_base;
                sdio.size += bytes = iov[seg].iov_len;
@@ -1235,6 +1236,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (sdio.bio)
                dio_bio_submit(dio, &sdio);
 
+       blk_finish_plug(&plug);
+
        /*
         * It is possible that, we return short IO due to end of file.
         * In that case, we need to release all the pages we got hold on.
@@ -1258,7 +1261,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
         */
        BUG_ON(retval == -EIOCBQUEUED);
        if (dio->is_async && retval == 0 && dio->result &&
-           ((rw & READ) || (dio->result == sdio.size)))
+           ((rw == READ) || (dio->result == sdio.size)))
                retval = -EIOCBQUEUED;
 
        if (retval != -EIOCBQUEUED)