Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@math.psu.edu>2002-02-24 20:07:38 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-02-24 20:07:38 -0800
commitad9e3359dfcadb92560c16c76771c8243219e11b (patch)
treec2c2a8c7c98a3f215718a93f96e0cbffb3710f54
parentdbd56307a5fbd69fbb0b59b16b8963bca9e07c09 (diff)
[PATCH] (1/3) fs/super.c cleanups
* missing yield() added to grab_super() (on failure exit). Without that we have a nasty race - if get_sb_bdev() happens just before we grab ->s_umount in kill_super(), we are going to have get_sb_bdev() spinning indefinitely long without yielding CPU, so that kill_super() could make progress (and break the loop). * in kill_super() code that does actual superblock shutdown is wrapped in if (sb->s_root) {}. That condition is true for all old callers of kill_super(), so we don't change existing behaviour. * instances of deactivate_super()/remove_super() (after failed call of foo_fill_super()) are replaced with up_write(&s->s_umount); kill_super(s); - now it becomes legitimate (kill_super() works on such guys and does exactly what we want).
-rw-r--r--fs/super.c64
1 files changed, 34 insertions, 30 deletions
diff --git a/fs/super.c b/fs/super.c
index 2b4162e4b283..5295c6a5d336 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -355,6 +355,7 @@ static int grab_super(struct super_block *s)
}
up_write(&s->s_umount);
put_super(s);
+ yield();
return 0;
}
@@ -724,8 +725,8 @@ restart:
return s;
failed:
- deactivate_super(s);
- remove_super(s);
+ up_write(&s->s_umount);
+ kill_super(s);
goto out;
out1:
blkdev_put(bdev, BDEV_FS);
@@ -748,8 +749,8 @@ struct super_block *get_sb_nodev(struct file_system_type *fs_type,
error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
if (error) {
- deactivate_super(s);
- remove_super(s);
+ up_write(&s->s_umount);
+ kill_super(s);
return ERR_PTR(error);
}
s->s_flags |= MS_ACTIVE;
@@ -774,8 +775,8 @@ struct super_block *get_sb_single(struct file_system_type *fs_type,
s->s_flags = flags;
error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
if (error) {
- deactivate_super(s);
- remove_super(s);
+ up_write(&s->s_umount);
+ kill_super(s);
return ERR_PTR(error);
}
s->s_flags |= MS_ACTIVE;
@@ -826,32 +827,35 @@ void kill_super(struct super_block *sb)
return;
down_write(&sb->s_umount);
- sb->s_root = NULL;
- /* Need to clean after the sucker */
- if (fs->fs_flags & FS_LITTER)
- d_genocide(root);
- shrink_dcache_parent(root);
- dput(root);
- fsync_super(sb);
- lock_super(sb);
- lock_kernel();
- sb->s_flags &= ~MS_ACTIVE;
- invalidate_inodes(sb); /* bad name - it should be evict_inodes() */
- if (sop) {
- if (sop->write_super && sb->s_dirt)
- sop->write_super(sb);
- if (sop->put_super)
- sop->put_super(sb);
- }
+ if (sb->s_root) {
+ sb->s_root = NULL;
+ /* Need to clean after the sucker */
+ if (fs->fs_flags & FS_LITTER)
+ d_genocide(root);
+ shrink_dcache_parent(root);
+ dput(root);
+ fsync_super(sb);
+ lock_super(sb);
+ lock_kernel();
+ sb->s_flags &= ~MS_ACTIVE;
+ /* bad name - it should be evict_inodes() */
+ invalidate_inodes(sb);
+ if (sop) {
+ if (sop->write_super && sb->s_dirt)
+ sop->write_super(sb);
+ if (sop->put_super)
+ sop->put_super(sb);
+ }
- /* Forget any remaining inodes */
- if (invalidate_inodes(sb)) {
- printk("VFS: Busy inodes after unmount. "
- "Self-destruct in 5 seconds. Have a nice day...\n");
- }
+ /* Forget any remaining inodes */
+ if (invalidate_inodes(sb)) {
+ printk("VFS: Busy inodes after unmount. "
+ "Self-destruct in 5 seconds. Have a nice day...\n");
+ }
- unlock_kernel();
- unlock_super(sb);
+ unlock_kernel();
+ unlock_super(sb);
+ }
remove_super(sb);
}