]> git.neil.brown.name Git - LaFS.git/commitdiff
write_begin and sync_page fixes.
authorNeilBrown <neilb@suse.de>
Sun, 18 Jul 2010 15:03:33 +0000 (17:03 +0200)
committerNeilBrown <neilb@suse.de>
Sun, 25 Jul 2010 05:34:27 +0000 (15:34 +1000)
1/ write_begin needs to drop the page lock and failure,
  and generally clean up properly.
2/ sync_page does not need to 'get_block' as a pointer is
  readily available - so just use that with appropriate locking.

Signed-off-by: NeilBrown <neilb@suse.de>
file.c

diff --git a/file.c b/file.c
index 2442b4334da44640848209af0a245a050eae74c6..6275d962e525ee3e189e4666a2210ebf7b64b2a1 100644 (file)
--- a/file.c
+++ b/file.c
@@ -160,8 +160,10 @@ lafs_write_begin(struct file *file, struct address_space *mapping,
 
        fb = lafs_get_block(ino, first, page, GFP_KERNEL, MKREF(write));
        dprintk("PREPARE %p\n", fb);
-       if (!fb)
-               return -ENOMEM;
+       if (!fb) {
+               err = -ENOMEM;
+               goto fail;
+       }
        /* Further lafs_get_block calls cannot fail as both the page
         * and the block structures exist
         */
@@ -208,14 +210,18 @@ retry:
                goto retry;
        }
        if (err < 0)
-               goto fail;
+               goto fail_unlock;
        *fsdata = fb;
        return 0;
 
-fail:
+fail_unlock:
        lafs_checkpoint_unlock(fs);
-       while (--i >= first)
-               putdref(&fb[i-first], MKREF(write));
+fail:
+       if (fb)
+               for (i = first; i <= last ; i++)
+                       putdref(&fb[i-first], MKREF(write));
+       unlock_page(page);
+       page_cache_release(page);
        return err;
 }
 
@@ -372,6 +378,13 @@ static void lafs_sync_page(struct page *page)
        struct fs *fs;
        int bits;
        int i;
+       int want_flush = 0;
+
+       if (!PageWriteback(page))
+               /* Presumably page is locked - nothing
+                * we can do
+                */
+               return;
 
        mapping = page->mapping;
        if (!mapping)
@@ -380,21 +393,23 @@ static void lafs_sync_page(struct page *page)
        fs = fs_from_inode(ino);
        bits = PAGE_SHIFT - ino->i_blkbits;
 
-       for (i = 0; i < (1<<bits); i++) {
-               struct datablock *b = lafs_get_block(ino, i, page,
-                                                    GFP_KERNEL, MKREF(sync_page));
-               if (!b)
-                       continue;
-               /* If this block is still dirty though the page is in
-                * writeback, the block must be in the current cluster
-                */
-               if (test_bit(B_Dirty, &b->b.flags)) {
-                       putdref(b, MKREF(sync_page));
-                       lafs_cluster_flush(fs, 0);
-                       break;
+       spin_lock(&mapping->private_lock);
+       if (PagePrivate(page)) {
+               struct datablock *bl = (struct datablock *)page->private;
+
+               for (i = 0; i < (1<<bits); i++) {
+                       /* If this block is still dirty though the page is in
+                        * writeback, the block must be in the current cluster
+                        */
+                       if (test_bit(B_Dirty, &bl[i].b.flags)) {
+                               want_flush = 1;
+                               break;
+                       }
                }
-               putdref(b, MKREF(sync_page));
        }
+       spin_unlock(&mapping->private_lock);
+       if (want_flush)
+               lafs_cluster_flush(fs, 0);
 }
 
 static int