aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDmitry Monakhov2013-04-03 21:06:52 -0500
committerGreg Kroah-Hartman2013-05-07 22:08:24 -0500
commit45932b3fd127c47269e3ba43d771033f30d25f78 (patch)
treefb9e592fb48bdd82e230804c920c88c5395c3bb3 /fs
parentaab8960fc9c05f82842586235fae4de1082708e1 (diff)
downloadkernel-omap-45932b3fd127c47269e3ba43d771033f30d25f78.tar.gz
kernel-omap-45932b3fd127c47269e3ba43d771033f30d25f78.tar.xz
kernel-omap-45932b3fd127c47269e3ba43d771033f30d25f78.zip
jbd2: fix race between jbd2_journal_remove_checkpoint and ->j_commit_callback
commit 794446c6946513c684d448205fbd76fa35f38b72 upstream. The following race is possible: [kjournald2] other_task jbd2_journal_commit_transaction() j_state = T_FINISHED; spin_unlock(&journal->j_list_lock); ->jbd2_journal_remove_checkpoint() ->jbd2_journal_free_transaction(); ->kmem_cache_free(transaction) ->j_commit_callback(journal, transaction); -> USE_AFTER_FREE WARNING: at lib/list_debug.c:62 __list_del_entry+0x1c0/0x250() Hardware name: list_del corruption. prev->next should be ffff88019a4ec198, but was 6b6b6b6b6b6b6b6b Modules linked in: cpufreq_ondemand acpi_cpufreq freq_table mperf coretemp kvm_intel kvm crc32c_intel ghash_clmulni_intel microcode sg xhci_hcd button sd_mod crc_t10dif aesni_intel ablk_helper cryptd lrw aes_x86_64 xts gf128mul ahci libahci pata_acpi ata_generic dm_mirror dm_region_hash dm_log dm_mod Pid: 16400, comm: jbd2/dm-1-8 Tainted: G W 3.8.0-rc3+ #107 Call Trace: [<ffffffff8106fb0d>] warn_slowpath_common+0xad/0xf0 [<ffffffff8106fc06>] warn_slowpath_fmt+0x46/0x50 [<ffffffff813637e9>] ? ext4_journal_commit_callback+0x99/0xc0 [<ffffffff8148cae0>] __list_del_entry+0x1c0/0x250 [<ffffffff813637bf>] ext4_journal_commit_callback+0x6f/0xc0 [<ffffffff813ca336>] jbd2_journal_commit_transaction+0x23a6/0x2570 [<ffffffff8108aa42>] ? try_to_del_timer_sync+0x82/0xa0 [<ffffffff8108b491>] ? del_timer_sync+0x91/0x1e0 [<ffffffff813d3ecf>] kjournald2+0x19f/0x6a0 [<ffffffff810ad630>] ? wake_up_bit+0x40/0x40 [<ffffffff813d3d30>] ? bit_spin_lock+0x80/0x80 [<ffffffff810ac6be>] kthread+0x10e/0x120 [<ffffffff810ac5b0>] ? __init_kthread_worker+0x70/0x70 [<ffffffff818ff6ac>] ret_from_fork+0x7c/0xb0 [<ffffffff810ac5b0>] ? __init_kthread_worker+0x70/0x70 In order to demonstrace this issue one should mount ext4 with mount -o discard option on SSD disk. This makes callback longer and race window becomes wider. In order to fix this we should mark transaction as finished only after callbacks have completed Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/jbd2/commit.c50
1 files changed, 28 insertions, 22 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 3091d42992f0..069bf58428c0 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -382,7 +382,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
382 int space_left = 0; 382 int space_left = 0;
383 int first_tag = 0; 383 int first_tag = 0;
384 int tag_flag; 384 int tag_flag;
385 int i, to_free = 0; 385 int i;
386 int tag_bytes = journal_tag_bytes(journal); 386 int tag_bytes = journal_tag_bytes(journal);
387 struct buffer_head *cbh = NULL; /* For transactional checksums */ 387 struct buffer_head *cbh = NULL; /* For transactional checksums */
388 __u32 crc32_sum = ~0; 388 __u32 crc32_sum = ~0;
@@ -1126,7 +1126,7 @@ restart_loop:
1126 journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; 1126 journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
1127 spin_unlock(&journal->j_history_lock); 1127 spin_unlock(&journal->j_history_lock);
1128 1128
1129 commit_transaction->t_state = T_FINISHED; 1129 commit_transaction->t_state = T_COMMIT_CALLBACK;
1130 J_ASSERT(commit_transaction == journal->j_committing_transaction); 1130 J_ASSERT(commit_transaction == journal->j_committing_transaction);
1131 journal->j_commit_sequence = commit_transaction->t_tid; 1131 journal->j_commit_sequence = commit_transaction->t_tid;
1132 journal->j_committing_transaction = NULL; 1132 journal->j_committing_transaction = NULL;
@@ -1141,38 +1141,44 @@ restart_loop:
1141 journal->j_average_commit_time*3) / 4; 1141 journal->j_average_commit_time*3) / 4;
1142 else 1142 else
1143 journal->j_average_commit_time = commit_time; 1143 journal->j_average_commit_time = commit_time;
1144
1144 write_unlock(&journal->j_state_lock); 1145 write_unlock(&journal->j_state_lock);
1145 1146
1146 if (commit_transaction->t_checkpoint_list == NULL && 1147 if (journal->j_checkpoint_transactions == NULL) {
1147 commit_transaction->t_checkpoint_io_list == NULL) { 1148 journal->j_checkpoint_transactions = commit_transaction;
1148 __jbd2_journal_drop_transaction(journal, commit_transaction); 1149 commit_transaction->t_cpnext = commit_transaction;
1149 to_free = 1; 1150 commit_transaction->t_cpprev = commit_transaction;
1150 } else { 1151 } else {
1151 if (journal->j_checkpoint_transactions == NULL) { 1152 commit_transaction->t_cpnext =
1152 journal->j_checkpoint_transactions = commit_transaction; 1153 journal->j_checkpoint_transactions;
1153 commit_transaction->t_cpnext = commit_transaction; 1154 commit_transaction->t_cpprev =
1154 commit_transaction->t_cpprev = commit_transaction; 1155 commit_transaction->t_cpnext->t_cpprev;
1155 } else { 1156 commit_transaction->t_cpnext->t_cpprev =
1156 commit_transaction->t_cpnext = 1157 commit_transaction;
1157 journal->j_checkpoint_transactions; 1158 commit_transaction->t_cpprev->t_cpnext =
1158 commit_transaction->t_cpprev =
1159 commit_transaction->t_cpnext->t_cpprev;
1160 commit_transaction->t_cpnext->t_cpprev =
1161 commit_transaction;
1162 commit_transaction->t_cpprev->t_cpnext =
1163 commit_transaction; 1159 commit_transaction;
1164 }
1165 } 1160 }
1166 spin_unlock(&journal->j_list_lock); 1161 spin_unlock(&journal->j_list_lock);
1167 1162 /* Drop all spin_locks because commit_callback may be block.
1163 * __journal_remove_checkpoint() can not destroy transaction
1164 * under us because it is not marked as T_FINISHED yet */
1168 if (journal->j_commit_callback) 1165 if (journal->j_commit_callback)
1169 journal->j_commit_callback(journal, commit_transaction); 1166 journal->j_commit_callback(journal, commit_transaction);
1170 1167
1171 trace_jbd2_end_commit(journal, commit_transaction); 1168 trace_jbd2_end_commit(journal, commit_transaction);
1172 jbd_debug(1, "JBD2: commit %d complete, head %d\n", 1169 jbd_debug(1, "JBD2: commit %d complete, head %d\n",
1173 journal->j_commit_sequence, journal->j_tail_sequence); 1170 journal->j_commit_sequence, journal->j_tail_sequence);
1174 if (to_free)
1175 jbd2_journal_free_transaction(commit_transaction);
1176 1171
1172 write_lock(&journal->j_state_lock);
1173 spin_lock(&journal->j_list_lock);
1174 commit_transaction->t_state = T_FINISHED;
1175 /* Recheck checkpoint lists after j_list_lock was dropped */
1176 if (commit_transaction->t_checkpoint_list == NULL &&
1177 commit_transaction->t_checkpoint_io_list == NULL) {
1178 __jbd2_journal_drop_transaction(journal, commit_transaction);
1179 jbd2_journal_free_transaction(commit_transaction);
1180 }
1181 spin_unlock(&journal->j_list_lock);
1182 write_unlock(&journal->j_state_lock);
1177 wake_up(&journal->j_wait_done_commit); 1183 wake_up(&journal->j_wait_done_commit);
1178} 1184}