From 5af7425bc56b4763d152de5b38a9a2feb965a60f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 28 Jun 2010 12:44:18 +1000 Subject: [PATCH] Move filesystem shutdown from put_super to lafs_release. It needs to happen before invalidate_inodes, else the cleaner can corrupt the inode list. Signed-off-by: NeilBrown --- README | 2 +- super.c | 65 ++++++++++++++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/README b/README index c5cd5c0..3db1135 100644 --- 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 0819f83..dc46b76 100644 --- 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); -- 2.39.5