]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/xfs/linux-2.6/xfs_aops.c
writeback: remove pages_skipped accounting in __block_write_full_page()
[mirror_ubuntu-artful-kernel.git] / fs / xfs / linux-2.6 / xfs_aops.c
index 7361861e3aacde605a400771af549b77e9b457e5..52bd08c0a2780c0b12a582fe6a4031d716cf9926 100644 (file)
@@ -108,14 +108,19 @@ xfs_page_trace(
 
 /*
  * Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend.
+ * the final hold on this ioend. If we are asked to wait,
+ * flush the workqueue.
  */
 STATIC void
 xfs_finish_ioend(
-       xfs_ioend_t             *ioend)
+       xfs_ioend_t     *ioend,
+       int             wait)
 {
-       if (atomic_dec_and_test(&ioend->io_remaining))
+       if (atomic_dec_and_test(&ioend->io_remaining)) {
                queue_work(xfsdatad_workqueue, &ioend->io_work);
+               if (wait)
+                       flush_workqueue(xfsdatad_workqueue);
+       }
 }
 
 /*
@@ -156,6 +161,8 @@ xfs_setfilesize(
        xfs_fsize_t             bsize;
 
        ip = xfs_vtoi(ioend->io_vnode);
+       if (!ip)
+               return;
 
        ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
        ASSERT(ioend->io_type != IOMAP_READ);
@@ -174,6 +181,7 @@ xfs_setfilesize(
                ip->i_d.di_size = isize;
                ip->i_update_core = 1;
                ip->i_update_size = 1;
+               mark_inode_dirty_sync(vn_to_inode(ioend->io_vnode));
        }
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -315,17 +323,13 @@ xfs_iomap_valid(
 /*
  * BIO completion handler for buffered IO.
  */
-STATIC int
+STATIC void
 xfs_end_bio(
        struct bio              *bio,
-       unsigned int            bytes_done,
        int                     error)
 {
        xfs_ioend_t             *ioend = bio->bi_private;
 
-       if (bio->bi_size)
-               return 1;
-
        ASSERT(atomic_read(&bio->bi_cnt) >= 1);
        ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
 
@@ -334,8 +338,7 @@ xfs_end_bio(
        bio->bi_end_io = NULL;
        bio_put(bio);
 
-       xfs_finish_ioend(ioend);
-       return 0;
+       xfs_finish_ioend(ioend, 0);
 }
 
 STATIC void
@@ -399,10 +402,9 @@ xfs_start_page_writeback(
                clear_page_dirty_for_io(page);
        set_page_writeback(page);
        unlock_page(page);
-       if (!buffers) {
+       /* If no buffers on the page are to be written, finish it here */
+       if (!buffers)
                end_page_writeback(page);
-               wbc->pages_skipped++;   /* We didn't write this page */
-       }
 }
 
 static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
@@ -470,7 +472,7 @@ xfs_submit_ioend(
                }
                if (bio)
                        xfs_submit_ioend_bio(ioend, bio);
-               xfs_finish_ioend(ioend);
+               xfs_finish_ioend(ioend, 0);
        } while ((ioend = next) != NULL);
 }
 
@@ -645,7 +647,7 @@ xfs_probe_cluster(
 
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
-                       size_t pg_offset, len = 0;
+                       size_t pg_offset, pg_len = 0;
 
                        if (tindex == tlast) {
                                pg_offset =
@@ -658,16 +660,16 @@ xfs_probe_cluster(
                                pg_offset = PAGE_CACHE_SIZE;
 
                        if (page->index == tindex && !TestSetPageLocked(page)) {
-                               len = xfs_probe_page(page, pg_offset, mapped);
+                               pg_len = xfs_probe_page(page, pg_offset, mapped);
                                unlock_page(page);
                        }
 
-                       if (!len) {
+                       if (!pg_len) {
                                done = 1;
                                break;
                        }
 
-                       total += len;
+                       total += pg_len;
                        tindex++;
                }
 
@@ -1003,6 +1005,8 @@ xfs_page_state_convert(
                if (buffer_unwritten(bh) || buffer_delay(bh) ||
                    ((buffer_uptodate(bh) || PageUptodate(page)) &&
                     !buffer_mapped(bh) && (unmapped || startio))) {
+                       int new_ioend = 0;
+
                        /*
                         * Make sure we don't use a read-only iomap
                         */
@@ -1021,6 +1025,15 @@ xfs_page_state_convert(
                        }
 
                        if (!iomap_valid) {
+                               /*
+                                * if we didn't have a valid mapping then we
+                                * need to ensure that we put the new mapping
+                                * in a new ioend structure. This needs to be
+                                * done to ensure that the ioends correctly
+                                * reflect the block mappings at io completion
+                                * for unwritten extent conversion.
+                                */
+                               new_ioend = 1;
                                if (type == IOMAP_NEW) {
                                        size = xfs_probe_cluster(inode,
                                                        page, bh, head, 0);
@@ -1040,7 +1053,7 @@ xfs_page_state_convert(
                                if (startio) {
                                        xfs_add_to_ioend(inode, bh, offset,
                                                        type, &ioend,
-                                                       !iomap_valid);
+                                                       new_ioend);
                                } else {
                                        set_buffer_dirty(bh);
                                        unlock_buffer(bh);
@@ -1416,6 +1429,13 @@ xfs_end_io_direct(
         * This is not necessary for synchronous direct I/O, but we do
         * it anyway to keep the code uniform and simpler.
         *
+        * Well, if only it were that simple. Because synchronous direct I/O
+        * requires extent conversion to occur *before* we return to userspace,
+        * we have to wait for extent conversion to complete. Look at the
+        * iocb that has been passed to us to determine if this is AIO or
+        * not. If it is synchronous, tell xfs_finish_ioend() to kick the
+        * workqueue and wait for it to complete.
+        *
         * The core direct I/O code might be changed to always call the
         * completion handler in the future, in which case all this can
         * go away.
@@ -1423,9 +1443,9 @@ xfs_end_io_direct(
        ioend->io_offset = offset;
        ioend->io_size = size;
        if (ioend->io_type == IOMAP_READ) {
-               xfs_finish_ioend(ioend);
+               xfs_finish_ioend(ioend, 0);
        } else if (private && size > 0) {
-               xfs_finish_ioend(ioend);
+               xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
        } else {
                /*
                 * A direct I/O write ioend starts it's life in unwritten
@@ -1434,7 +1454,7 @@ xfs_end_io_direct(
                 * handler.
                 */
                INIT_WORK(&ioend->io_work, xfs_end_bio_written);
-               xfs_finish_ioend(ioend);
+               xfs_finish_ioend(ioend, 0);
        }
 
        /*
@@ -1487,13 +1507,18 @@ xfs_vm_direct_IO(
 }
 
 STATIC int
-xfs_vm_prepare_write(
+xfs_vm_write_begin(
        struct file             *file,
-       struct page             *page,
-       unsigned int            from,
-       unsigned int            to)
+       struct address_space    *mapping,
+       loff_t                  pos,
+       unsigned                len,
+       unsigned                flags,
+       struct page             **pagep,
+       void                    **fsdata)
 {
-       return block_prepare_write(page, from, to, xfs_get_blocks);
+       *pagep = NULL;
+       return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+                                                               xfs_get_blocks);
 }
 
 STATIC sector_t
@@ -1547,8 +1572,8 @@ const struct address_space_operations xfs_address_space_operations = {
        .sync_page              = block_sync_page,
        .releasepage            = xfs_vm_releasepage,
        .invalidatepage         = xfs_vm_invalidatepage,
-       .prepare_write          = xfs_vm_prepare_write,
-       .commit_write           = generic_commit_write,
+       .write_begin            = xfs_vm_write_begin,
+       .write_end              = generic_write_end,
        .bmap                   = xfs_vm_bmap,
        .direct_IO              = xfs_vm_direct_IO,
        .migratepage            = buffer_migrate_page,