]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/xfs/linux-2.6/xfs_aops.c
Pull sem2mutex-ioc4 into release branch
[linux-2.6-omap-h63xx.git] / fs / xfs / linux-2.6 / xfs_aops.c
index d1db8c17a74e8eb7b5ccd0a0a971808d1960606f..74d8be87f983d4995c32bc87ebcc89ff33b577bb 100644 (file)
@@ -336,24 +336,47 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
 }
 
 /*
- * Submit all of the bios for all of the ioends we have saved up,
- * covering the initial writepage page and also any probed pages.
+ * Submit all of the bios for all of the ioends we have saved up, covering the
+ * initial writepage page and also any probed pages.
+ *
+ * Because we may have multiple ioends spanning a page, we need to start
+ * writeback on all the buffers before we submit them for I/O. If we mark the
+ * buffers as we got, then we can end up with a page that only has buffers
+ * marked async write and I/O complete on can occur before we mark the other
+ * buffers async write.
+ *
+ * The end result of this is that we trip a bug in end_page_writeback() because
+ * we call it twice for the one page as the code in end_buffer_async_write()
+ * assumes that all buffers on the page are started at the same time.
+ *
+ * The fix is two passes across the ioend list - one to start writeback on the
+ * bufferheads, and then the second one submit them for I/O.
  */
 STATIC void
 xfs_submit_ioend(
        xfs_ioend_t             *ioend)
 {
+       xfs_ioend_t             *head = ioend;
        xfs_ioend_t             *next;
        struct buffer_head      *bh;
        struct bio              *bio;
        sector_t                lastblock = 0;
 
+       /* Pass 1 - start writeback */
+       do {
+               next = ioend->io_list;
+               for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
+                       xfs_start_buffer_writeback(bh);
+               }
+       } while ((ioend = next) != NULL);
+
+       /* Pass 2 - submit I/O */
+       ioend = head;
        do {
                next = ioend->io_list;
                bio = NULL;
 
                for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
-                       xfs_start_buffer_writeback(bh);
 
                        if (!bio) {
  retry:
@@ -517,7 +540,7 @@ xfs_probe_cluster(
 
        /* First sum forwards in this page */
        do {
-               if (mapped != buffer_mapped(bh))
+               if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh)))
                        return total;
                total += bh->b_size;
        } while ((bh = bh->b_this_page) != head);
@@ -724,10 +747,11 @@ xfs_convert_page(
                        struct backing_dev_info *bdi;
 
                        bdi = inode->i_mapping->backing_dev_info;
+                       wbc->nr_to_write--;
                        if (bdi_write_congested(bdi)) {
                                wbc->encountered_congestion = 1;
                                done = 1;
-                       } else if (--wbc->nr_to_write <= 0) {
+                       } else if (wbc->nr_to_write <= 0) {
                                done = 1;
                        }
                }
@@ -1439,4 +1463,5 @@ struct address_space_operations linvfs_aops = {
        .commit_write           = generic_commit_write,
        .bmap                   = linvfs_bmap,
        .direct_IO              = linvfs_direct_IO,
+       .migratepage            = buffer_migrate_page,
 };