]> git.neil.brown.name Git - LaFS.git/commitdiff
Avoid inadvertently flush blocks that are in middle of a transaction.
authorNeilBrown <neilb@suse.de>
Thu, 3 Sep 2009 05:28:15 +0000 (15:28 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 3 Sep 2009 05:28:15 +0000 (15:28 +1000)
If a directory block has PinPending, then a transaction is in progress
and flushing the block (e.g. pdflush) would be a bad idea, as we could
lose the credit before the final update.

file.c

diff --git a/file.c b/file.c
index 65e07f3ce9b13aa3c19f93a516fe9dfb21acb442..ac40b0ca2d7964461053dc8bbae55fbd30061a30 100644 (file)
--- a/file.c
+++ b/file.c
@@ -195,6 +195,7 @@ lafs_writepage(struct page *page, struct writeback_control *wbc)
        struct datablock *b0 = NULL;
        int blocks = PAGE_SIZE >> ino->i_blkbits;
        int i;
+       int rv = 0;
        dprintk("WRITEPAGE %lu\n", page->index);
        for (i = 0 ; i < blocks; i++) {
                struct datablock *b = lafs_get_block(ino, i, page, GFP_KERNEL,
@@ -204,37 +205,47 @@ lafs_writepage(struct page *page, struct writeback_control *wbc)
                if (i == 0)
                        b0 = getdref(b, MKREF(writepage0));
 
+               /* We need to check PinPending, otherwise we must be called
+                * to flush out a page that is currently part of a transaction.
+                */
                if (test_bit(B_Dirty, &b->b.flags)) {
-                       lafs_iolock_written(&b->b);
-                       lafs_cluster_allocate(&b->b, 0);
+                       if (test_bit(B_PinPending, &b->b.flags))
+                               rv = AOP_WRITEPAGE_ACTIVATE;
+                       else {
+                               lafs_iolock_written(&b->b);
+                               lafs_cluster_allocate(&b->b, 0);
+                       }
                }
                putdref(b, MKREF(writepage));
        }
-       if (b0) {
-               set_page_writeback(page);
-               set_bit(B_HaveWriteback, &b0->b.flags);
-               lafs_iocheck_writeback(b0, 0);
+       if (rv == 0) {
+               if (b0) {
+                       set_page_writeback(page);
+                       set_bit(B_HaveWriteback, &b0->b.flags);
+                       lafs_iocheck_writeback(b0, 0);
+               }
+               unlock_page(page);
        }
-       unlock_page(page); /* FIXME this must not happen before
-                             the writes complete! */
        if (!b0)
                return 0;
        putdref(b0, MKREF(writepage0));
-       if (wbc->for_writepages && LAFSI(ino)->depth == 0) {
+       if (rv == 0 && wbc->for_writepages && LAFSI(ino)->depth == 0) {
                /* We really want the data to be safe soon, not just
                 * the page to be clean.
                 * so write the inode.
                 */
                struct datablock *b = lafs_inode_dblock(ino, 0,
                                                        MKREF(writepageflush));
-               lafs_iolock_written(&b->b);
-               lafs_cluster_allocate(&b->b, 0);
+               if (test_bit(B_Dirty, &b->b.flags)) {
+                       lafs_iolock_written(&b->b);
+                       lafs_cluster_allocate(&b->b, 0);
+               }
                putdref(b, MKREF(writepageflush));
        }
 // FIXME need to make sure a cluster_flush happens some time!!!        if (wbc->sync_mode != WB_SYNC_NONE)
                lafs_cluster_flush(fs, 0);
        dprintk("WRITEPAGE flush\n");
-       return 0;
+       return rv;
 }
 
 static void lafs_sync_page(struct page *page)