diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-22 20:11:53 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-21 18:31:15 -0400 |
commit | e7fe0585ca8793e2d43c57e77d4ca79042806acf (patch) | |
tree | a68234ce86f5ff221f3f6260374f3a6437d77ce3 | |
parent | 6754af64641e8224c281ee5714e012e3ed41f701 (diff) |
fix do_emergency_remount()/umount() races
need list_for_each_entry_safe() here. Original didn't even
have restart logics, so if you race with umount() it blew up.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/super.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/super.c b/fs/super.c index ccb2b5fa89bd..4df8233dfb61 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -602,10 +602,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
602 | 602 | ||
603 | static void do_emergency_remount(struct work_struct *work) | 603 | static void do_emergency_remount(struct work_struct *work) |
604 | { | 604 | { |
605 | struct super_block *sb; | 605 | struct super_block *sb, *n; |
606 | 606 | ||
607 | spin_lock(&sb_lock); | 607 | spin_lock(&sb_lock); |
608 | list_for_each_entry(sb, &super_blocks, s_list) { | 608 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { |
609 | if (list_empty(&sb->s_instances)) | 609 | if (list_empty(&sb->s_instances)) |
610 | continue; | 610 | continue; |
611 | sb->s_count++; | 611 | sb->s_count++; |
@@ -618,8 +618,8 @@ static void do_emergency_remount(struct work_struct *work) | |||
618 | do_remount_sb(sb, MS_RDONLY, NULL, 1); | 618 | do_remount_sb(sb, MS_RDONLY, NULL, 1); |
619 | } | 619 | } |
620 | up_write(&sb->s_umount); | 620 | up_write(&sb->s_umount); |
621 | put_super(sb); | ||
622 | spin_lock(&sb_lock); | 621 | spin_lock(&sb_lock); |
622 | __put_super(sb); | ||
623 | } | 623 | } |
624 | spin_unlock(&sb_lock); | 624 | spin_unlock(&sb_lock); |
625 | kfree(work); | 625 | kfree(work); |