aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2011-09-04 10:18:14 -0400
committerTheodore Ts'o <tytso@mit.edu>2011-09-04 10:18:14 -0400
commit9ea7a0df63630ad8197716cd313ea66e28906fc0 (patch)
tree2f9cb8bb3f4c709aa666c7863b496f2757b261fb /fs/jbd2
parent56889787cfa77dfd96f0b3a3e6a4f26c2e4a5134 (diff)
jbd2: add debugging information to jbd2_journal_dirty_metadata()
Add debugging information in case jbd2_journal_dirty_metadata() is called with a buffer_head which didn't have jbd2_journal_get_write_access() called on it, or if the journal_head has the wrong transaction in it. In addition, return an error code. This won't change anything for ocfs2, which will BUG_ON() the non-zero exit code. For ext4, the caller of this function is ext4_handle_dirty_metadata(), and on seeing a non-zero return code, will call __ext4_journal_stop(), which will print the function and line number of the (buggy) calling function and abort the journal. This will allow us to recover instead of bug halting, which is better from a robustness and reliability point of view. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2')
-rw-r--r--fs/jbd2/transaction.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 2d7109414cdd..cb56fe9aaabb 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1049,6 +1049,10 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh,
1049 * mark dirty metadata which needs to be journaled as part of the current 1049 * mark dirty metadata which needs to be journaled as part of the current
1050 * transaction. 1050 * transaction.
1051 * 1051 *
1052 * The buffer must have previously had jbd2_journal_get_write_access()
1053 * called so that it has a valid journal_head attached to the buffer
1054 * head.
1055 *
1052 * The buffer is placed on the transaction's metadata list and is marked 1056 * The buffer is placed on the transaction's metadata list and is marked
1053 * as belonging to the transaction. 1057 * as belonging to the transaction.
1054 * 1058 *
@@ -1065,11 +1069,16 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
1065 transaction_t *transaction = handle->h_transaction; 1069 transaction_t *transaction = handle->h_transaction;
1066 journal_t *journal = transaction->t_journal; 1070 journal_t *journal = transaction->t_journal;
1067 struct journal_head *jh = bh2jh(bh); 1071 struct journal_head *jh = bh2jh(bh);
1072 int ret = 0;
1068 1073
1069 jbd_debug(5, "journal_head %p\n", jh); 1074 jbd_debug(5, "journal_head %p\n", jh);
1070 JBUFFER_TRACE(jh, "entry"); 1075 JBUFFER_TRACE(jh, "entry");
1071 if (is_handle_aborted(handle)) 1076 if (is_handle_aborted(handle))
1072 goto out; 1077 goto out;
1078 if (!buffer_jbd(bh)) {
1079 ret = -EUCLEAN;
1080 goto out;
1081 }
1073 1082
1074 jbd_lock_bh_state(bh); 1083 jbd_lock_bh_state(bh);
1075 1084
@@ -1093,8 +1102,20 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
1093 */ 1102 */
1094 if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) { 1103 if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) {
1095 JBUFFER_TRACE(jh, "fastpath"); 1104 JBUFFER_TRACE(jh, "fastpath");
1096 J_ASSERT_JH(jh, jh->b_transaction == 1105 if (unlikely(jh->b_transaction !=
1097 journal->j_running_transaction); 1106 journal->j_running_transaction)) {
1107 printk(KERN_EMERG "JBD: %s: "
1108 "jh->b_transaction (%llu, %p, %u) != "
1109 "journal->j_running_transaction (%p, %u)",
1110 journal->j_devname,
1111 (unsigned long long) bh->b_blocknr,
1112 jh->b_transaction,
1113 jh->b_transaction ? jh->b_transaction->t_tid : 0,
1114 journal->j_running_transaction,
1115 journal->j_running_transaction ?
1116 journal->j_running_transaction->t_tid : 0);
1117 ret = -EINVAL;
1118 }
1098 goto out_unlock_bh; 1119 goto out_unlock_bh;
1099 } 1120 }
1100 1121
@@ -1108,9 +1129,32 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
1108 */ 1129 */
1109 if (jh->b_transaction != transaction) { 1130 if (jh->b_transaction != transaction) {
1110 JBUFFER_TRACE(jh, "already on other transaction"); 1131 JBUFFER_TRACE(jh, "already on other transaction");
1111 J_ASSERT_JH(jh, jh->b_transaction == 1132 if (unlikely(jh->b_transaction !=
1112 journal->j_committing_transaction); 1133 journal->j_committing_transaction)) {
1113 J_ASSERT_JH(jh, jh->b_next_transaction == transaction); 1134 printk(KERN_EMERG "JBD: %s: "
1135 "jh->b_transaction (%llu, %p, %u) != "
1136 "journal->j_committing_transaction (%p, %u)",
1137 journal->j_devname,
1138 (unsigned long long) bh->b_blocknr,
1139 jh->b_transaction,
1140 jh->b_transaction ? jh->b_transaction->t_tid : 0,
1141 journal->j_committing_transaction,
1142 journal->j_committing_transaction ?
1143 journal->j_committing_transaction->t_tid : 0);
1144 ret = -EINVAL;
1145 }
1146 if (unlikely(jh->b_next_transaction != transaction)) {
1147 printk(KERN_EMERG "JBD: %s: "
1148 "jh->b_next_transaction (%llu, %p, %u) != "
1149 "transaction (%p, %u)",
1150 journal->j_devname,
1151 (unsigned long long) bh->b_blocknr,
1152 jh->b_next_transaction,
1153 jh->b_next_transaction ?
1154 jh->b_next_transaction->t_tid : 0,
1155 transaction, transaction->t_tid);
1156 ret = -EINVAL;
1157 }
1114 /* And this case is illegal: we can't reuse another 1158 /* And this case is illegal: we can't reuse another
1115 * transaction's data buffer, ever. */ 1159 * transaction's data buffer, ever. */
1116 goto out_unlock_bh; 1160 goto out_unlock_bh;
@@ -1127,7 +1171,9 @@ out_unlock_bh:
1127 jbd_unlock_bh_state(bh); 1171 jbd_unlock_bh_state(bh);
1128out: 1172out:
1129 JBUFFER_TRACE(jh, "exit"); 1173 JBUFFER_TRACE(jh, "exit");
1130 return 0; 1174 if (ret)
1175 __WARN(); /* All errors are bugs, so dump the stack */
1176 return ret;
1131} 1177}
1132 1178
1133/* 1179/*