aboutsummaryrefslogtreecommitdiffstats
path: root/fs/reiserfs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-08-06 13:43:56 -0400
committerJan Kara <jack@suse.cz>2014-08-12 06:46:30 -0400
commit01777836c87081e4f68c4a43c9abe6114805f91e (patch)
tree249981494b2563e689b091fe4e67929e4ddc113c /fs/reiserfs
parent27d0e5bc85f3341b9ba66f0c23627cf9d7538c9d (diff)
reiserfs: Fix use after free in journal teardown
If do_journal_release() races with do_journal_end() which requeues delayed works for transaction flushing, we can leave work items for flushing outstanding transactions queued while freeing them. That results in use after free and possible crash in run_timers_softirq(). Fix the problem by not requeueing works if superblock is being shut down (MS_ACTIVE not set) and using cancel_delayed_work_sync() in do_journal_release(). CC: stable@vger.kernel.org Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/reiserfs')
-rw-r--r--fs/reiserfs/journal.c22
-rw-r--r--fs/reiserfs/super.c6
2 files changed, 21 insertions, 7 deletions
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index e8870de4627e..a88b1b3e7db3 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1947,8 +1947,6 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
1947 } 1947 }
1948 } 1948 }
1949 1949
1950 /* wait for all commits to finish */
1951 cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
1952 1950
1953 /* 1951 /*
1954 * We must release the write lock here because 1952 * We must release the write lock here because
@@ -1956,8 +1954,14 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
1956 */ 1954 */
1957 reiserfs_write_unlock(sb); 1955 reiserfs_write_unlock(sb);
1958 1956
1957 /*
1958 * Cancel flushing of old commits. Note that neither of these works
1959 * will be requeued because superblock is being shutdown and doesn't
1960 * have MS_ACTIVE set.
1961 */
1959 cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work); 1962 cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work);
1960 flush_workqueue(REISERFS_SB(sb)->commit_wq); 1963 /* wait for all commits to finish */
1964 cancel_delayed_work_sync(&SB_JOURNAL(sb)->j_work);
1961 1965
1962 free_journal_ram(sb); 1966 free_journal_ram(sb);
1963 1967
@@ -4292,9 +4296,15 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, int flags)
4292 if (flush) { 4296 if (flush) {
4293 flush_commit_list(sb, jl, 1); 4297 flush_commit_list(sb, jl, 1);
4294 flush_journal_list(sb, jl, 1); 4298 flush_journal_list(sb, jl, 1);
4295 } else if (!(jl->j_state & LIST_COMMIT_PENDING)) 4299 } else if (!(jl->j_state & LIST_COMMIT_PENDING)) {
4296 queue_delayed_work(REISERFS_SB(sb)->commit_wq, 4300 /*
4297 &journal->j_work, HZ / 10); 4301 * Avoid queueing work when sb is being shut down. Transaction
4302 * will be flushed on journal shutdown.
4303 */
4304 if (sb->s_flags & MS_ACTIVE)
4305 queue_delayed_work(REISERFS_SB(sb)->commit_wq,
4306 &journal->j_work, HZ / 10);
4307 }
4298 4308
4299 /* 4309 /*
4300 * if the next transaction has any chance of wrapping, flush 4310 * if the next transaction has any chance of wrapping, flush
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index a392cef6acc6..5fd8f57e07fc 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -100,7 +100,11 @@ void reiserfs_schedule_old_flush(struct super_block *s)
100 struct reiserfs_sb_info *sbi = REISERFS_SB(s); 100 struct reiserfs_sb_info *sbi = REISERFS_SB(s);
101 unsigned long delay; 101 unsigned long delay;
102 102
103 if (s->s_flags & MS_RDONLY) 103 /*
104 * Avoid scheduling flush when sb is being shut down. It can race
105 * with journal shutdown and free still queued delayed work.
106 */
107 if (s->s_flags & MS_RDONLY || !(s->s_flags & MS_ACTIVE))
104 return; 108 return;
105 109
106 spin_lock(&sbi->old_work_lock); 110 spin_lock(&sbi->old_work_lock);