diff options
author | Jan Kara <jack@suse.cz> | 2007-07-16 02:41:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:48 -0400 |
commit | 32c3773011a9b3522bd4abadc7fad8c27417119f (patch) | |
tree | c3a07aecbef3cdb66a4126e2822c69166aee1c97 /fs/ext4/super.c | |
parent | 030703e49d4966bd348660e0fdc2699507efb82b (diff) |
ext4: fix deadlock in ext4_remount() and orphan list handling
ext4_orphan_add() and ext4_orphan_del() functions lock sb->s_lock with a
transaction started with ext4_mark_recovery_complete() waits for a transaction
holding sb->s_lock, thus leading to a possible deadlock. At the moment we
call ext4_mark_recovery_complete() from ext4_remount() we have done all the
work needed for remounting and thus we are safe to drop sb->s_lock before we
wait for transactions to commit. Note that at this moment we are still
guarded by s_umount lock against other remounts/umounts.
Signed-off-by: Jan Kara <jack@suse.cz>
Cc: Eric Sandeen <sandeen@sandeen.net>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6768c5aa3fee..bd9aff9701c0 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -2222,12 +2222,14 @@ static void ext4_mark_recovery_complete(struct super_block * sb, | |||
2222 | 2222 | ||
2223 | jbd2_journal_lock_updates(journal); | 2223 | jbd2_journal_lock_updates(journal); |
2224 | jbd2_journal_flush(journal); | 2224 | jbd2_journal_flush(journal); |
2225 | lock_super(sb); | ||
2225 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && | 2226 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && |
2226 | sb->s_flags & MS_RDONLY) { | 2227 | sb->s_flags & MS_RDONLY) { |
2227 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); | 2228 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); |
2228 | sb->s_dirt = 0; | 2229 | sb->s_dirt = 0; |
2229 | ext4_commit_super(sb, es, 1); | 2230 | ext4_commit_super(sb, es, 1); |
2230 | } | 2231 | } |
2232 | unlock_super(sb); | ||
2231 | jbd2_journal_unlock_updates(journal); | 2233 | jbd2_journal_unlock_updates(journal); |
2232 | } | 2234 | } |
2233 | 2235 | ||
@@ -2416,7 +2418,13 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) | |||
2416 | (sbi->s_mount_state & EXT4_VALID_FS)) | 2418 | (sbi->s_mount_state & EXT4_VALID_FS)) |
2417 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 2419 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
2418 | 2420 | ||
2421 | /* | ||
2422 | * We have to unlock super so that we can wait for | ||
2423 | * transactions. | ||
2424 | */ | ||
2425 | unlock_super(sb); | ||
2419 | ext4_mark_recovery_complete(sb, es); | 2426 | ext4_mark_recovery_complete(sb, es); |
2427 | lock_super(sb); | ||
2420 | } else { | 2428 | } else { |
2421 | __le32 ret; | 2429 | __le32 ret; |
2422 | if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, | 2430 | if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, |