]> git.neil.brown.name Git - LaFS.git/commitdiff
Move filesystem shutdown from put_super to lafs_release.
authorNeilBrown <neilb@suse.de>
Mon, 28 Jun 2010 02:44:18 +0000 (12:44 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 28 Jun 2010 02:44:18 +0000 (12:44 +1000)
It needs to happen before invalidate_inodes, else the cleaner
can corrupt the inode list.

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

diff --git a/README b/README
index c5cd5c053de761a4d13134e781d66a6a27cf13ed..3db11350251b16a5a5c5f4dcf8f45a6cf113881a 100644 (file)
--- a/README
+++ b/README
@@ -4842,7 +4842,7 @@ DONE 7c/ NULL pointer deref - 000001b4
      Could be cluster_flush finds inode dblock without inode.
      Have a BUG_ON of this now.
 
- 7d/ paging request at 6b6b6bfb. 
+DONE 7d/ paging request at 6b6b6bfb. 
     invalidate_inode_buffers called, so inode_has_buffers,
     so private_list is not empty.  So presumably use-after-free.
     But is on s_inodes list.
diff --git a/super.c b/super.c
index 0819f83920aee602b89e7240ac0cf25032409a0e..dc46b76ea81362dc1bc2a2617ec34357b9f54d9e 100644 (file)
--- a/super.c
+++ b/super.c
@@ -624,15 +624,48 @@ lafs_load(struct options *op, int newest)
        return fs;
 }
 
+static int show_orphans(struct fs *fs)
+{
+       struct datablock *db;
+       printk("Orphans:\n");
+       list_for_each_entry(db, &fs->pending_orphans,
+                           orphans) {
+               printk("orphan=%s\n", strblk(&db->b));
+               if (LAFSI(db->b.inode)->type == TypeInodeFile)
+                       lafs_print_tree(&LAFSI(db->my_inode)->iblock->b, 0);
+       }
+       printk("cleaner active: %d %d\n", fs->cleaner.active,
+              fs->scan.done);
+       return 1; /* meaningless, but makes it easy to add to wait_event below */
+}
+
 static void
 lafs_release(struct fs *fs)
 {
        /* Release the 'struct fs' */
        int i;
 
+       /* FIXME should I refcount this when there are multiple
+        * filesets? How does that work?
+        */
+
        /* Delay final destruction of the root inode */
        /* FIXME all the sbs... */
        set_bit(I_Deleting, &LAFSI(fs->ss[0].root)->iflags);
+
+       /* FIXME I'm not sure we should be waiting for the
+        * cleaner.  Maybe we should just release all tc->cleaning
+        * blocks instead.
+        */
+       set_bit(CleanerDisabled, &fs->fsstate);
+
+       wait_event(fs->async_complete,
+                  show_orphans(fs) &&
+                  !test_bit(OrphansRunning, &fs->fsstate) &&
+                  list_empty(&fs->pending_orphans) &&
+                  fs->scan.done == 1 &&
+                  fs->cleaner.active == 0);
+
        for (i = 0; i < fs->devices; i++) {
                struct fs_dev *dv = &fs->devs[i];
                kfree(dv->devblk);
@@ -678,21 +711,6 @@ lafs_release(struct fs *fs)
        kfree(fs);
 }
 
-static int show_orphans(struct fs *fs)
-{
-       struct datablock *db;
-       printk("Orphans:\n");
-       list_for_each_entry(db, &fs->pending_orphans,
-                           orphans) {
-               printk("orphan=%s\n", strblk(&db->b));
-               if (LAFSI(db->b.inode)->type == TypeInodeFile)
-                       lafs_print_tree(&LAFSI(db->my_inode)->iblock->b, 0);
-       }
-       printk("cleaner active: %d %d\n", fs->cleaner.active,
-              fs->scan.done);
-       return 1; /* meaningless, but makes it easy to add to wait_event below */
-}
-
 static void
 lafs_put_super(struct super_block *sb)
 {
@@ -703,21 +721,10 @@ lafs_put_super(struct super_block *sb)
        if (sb == fs->prime_sb) {
                int d;
                /* This is the main sb, not a snapshot or
-                * subordinate fs
-                */
-               /* FIXME I'm not sure we should be waiting for the
-                * cleaner.  Maybe we should just release all tc->cleaning
-                * blocks instead.
+                * subordinate fs.
+                * Now that all inodes have been invalidated we can do
+                * the final checkpoint.
                 */
-               set_bit(CleanerDisabled, &fs->fsstate);
-
-               /* FIXME maybe I want these tests in a spinlock ?? */
-               wait_event(fs->async_complete,
-                          show_orphans(fs) &&
-                          !test_bit(OrphansRunning, &fs->fsstate) &&
-                          list_empty(&fs->pending_orphans) &&
-                          fs->scan.done == 1 &&
-                          fs->cleaner.active == 0);
                lafs_checkpoint_lock(fs);
                /* Don't incorporate any more segusage/quota updates. */
                lafs_checkpoint_start(fs);