aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2013-04-03 22:06:52 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-03 22:06:52 -0400
commit794446c6946513c684d448205fbd76fa35f38b72 (patch)
treee6c507e1884238acfe507fa8fec3831875f1337e /fs/jbd2
parent996bb9fddd5b68d1dfb5e27d30ca2c7a72448596 (diff)
jbd2: fix race between jbd2_journal_remove_checkpoint and ->j_commit_callback
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> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/jbd2')
-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 750c70148eff..0f53946f13c1 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;
@@ -1134,7 +1134,7 @@ restart_loop:
1134 journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; 1134 journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
1135 spin_unlock(&journal->j_history_lock); 1135 spin_unlock(&journal->j_history_lock);
1136 1136
1137 commit_transaction->t_state = T_FINISHED; 1137 commit_transaction->t_state = T_COMMIT_CALLBACK;
1138 J_ASSERT(commit_transaction == journal->j_committing_transaction); 1138 J_ASSERT(commit_transaction == journal->j_committing_transaction);
1139 journal->j_commit_sequence = commit_transaction->t_tid; 1139 journal->j_commit_sequence = commit_transaction->t_tid;
1140 journal->j_committing_transaction = NULL; 1140 journal->j_committing_transaction = NULL;
@@ -1149,38 +1149,44 @@ restart_loop:
1149 journal->j_average_commit_time*3) / 4; 1149 journal->j_average_commit_time*3) / 4;
1150 else 1150 else
1151 journal->j_average_commit_time = commit_time; 1151 journal->j_average_commit_time = commit_time;
1152
1152 write_unlock(&journal->j_state_lock); 1153 write_unlock(&journal->j_state_lock);
1153 1154
1154 if (commit_transaction->t_checkpoint_list == NULL && 1155 if (journal->j_checkpoint_transactions == NULL) {
1155 commit_transaction->t_checkpoint_io_list == NULL) { 1156 journal->j_checkpoint_transactions = commit_transaction;
1156 __jbd2_journal_drop_transaction(journal, commit_transaction); 1157 commit_transaction->t_cpnext = commit_transaction;
1157 to_free = 1; 1158 commit_transaction->t_cpprev = commit_transaction;
1158 } else { 1159 } else {
1159 if (journal->j_checkpoint_transactions == NULL) { 1160 commit_transaction->t_cpnext =
1160 journal->j_checkpoint_transactions = commit_transaction; 1161 journal->j_checkpoint_transactions;
1161 commit_transaction->t_cpnext = commit_transaction; 1162 commit_transaction->t_cpprev =
1162 commit_transaction->t_cpprev = commit_transaction; 1163 commit_transaction->t_cpnext->t_cpprev;
1163 } else { 1164 commit_transaction->t_cpnext->t_cpprev =
1164 commit_transaction->t_cpnext = 1165 commit_transaction;
1165 journal->j_checkpoint_transactions; 1166 commit_transaction->t_cpprev->t_cpnext =
1166 commit_transaction->t_cpprev =
1167 commit_transaction->t_cpnext->t_cpprev;
1168 commit_transaction->t_cpnext->t_cpprev =
1169 commit_transaction;
1170 commit_transaction->t_cpprev->t_cpnext =
1171 commit_transaction; 1167 commit_transaction;
1172 }
1173 } 1168 }
1174 spin_unlock(&journal->j_list_lock); 1169 spin_unlock(&journal->j_list_lock);
1175 1170 /* Drop all spin_locks because commit_callback may be block.
1171 * __journal_remove_checkpoint() can not destroy transaction
1172 * under us because it is not marked as T_FINISHED yet */
1176 if (journal->j_commit_callback) 1173 if (journal->j_commit_callback)
1177 journal->j_commit_callback(journal, commit_transaction); 1174 journal->j_commit_callback(journal, commit_transaction);
1178 1175
1179 trace_jbd2_end_commit(journal, commit_transaction); 1176 trace_jbd2_end_commit(journal, commit_transaction);
1180 jbd_debug(1, "JBD2: commit %d complete, head %d\n", 1177 jbd_debug(1, "JBD2: commit %d complete, head %d\n",
1181 journal->j_commit_sequence, journal->j_tail_sequence); 1178 journal->j_commit_sequence, journal->j_tail_sequence);
1182 if (to_free)
1183 jbd2_journal_free_transaction(commit_transaction);
1184 1179
1180 write_lock(&journal->j_state_lock);
1181 spin_lock(&journal->j_list_lock);
1182 commit_transaction->t_state = T_FINISHED;
1183 /* Recheck checkpoint lists after j_list_lock was dropped */
1184 if (commit_transaction->t_checkpoint_list == NULL &&
1185 commit_transaction->t_checkpoint_io_list == NULL) {
1186 __jbd2_journal_drop_transaction(journal, commit_transaction);
1187 jbd2_journal_free_transaction(commit_transaction);
1188 }
1189 spin_unlock(&journal->j_list_lock);
1190 write_unlock(&journal->j_state_lock);
1185 wake_up(&journal->j_wait_done_commit); 1191 wake_up(&journal->j_wait_done_commit);
1186} 1192}