Skip to content

Commit 9ea7a0d

Browse files
committed
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" <[email protected]>
1 parent 5688978 commit 9ea7a0d

File tree

3 files changed

+64
-12
lines changed

3 files changed

+64
-12
lines changed

fs/ext4/ext4_jbd2.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,11 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
109109

110110
if (ext4_handle_valid(handle)) {
111111
err = jbd2_journal_dirty_metadata(handle, bh);
112-
if (err)
113-
ext4_journal_abort_handle(where, line, __func__,
114-
bh, handle, err);
112+
if (err) {
113+
/* Errors can only happen if there is a bug */
114+
handle->h_err = err;
115+
__ext4_journal_stop(where, line, handle);
116+
}
115117
} else {
116118
if (inode)
117119
mark_buffer_dirty_inode(bh, inode);

fs/ext4/extents.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,17 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
9696
* - ENOMEM
9797
* - EIO
9898
*/
99-
static int ext4_ext_dirty(handle_t *handle, struct inode *inode,
100-
struct ext4_ext_path *path)
99+
#define ext4_ext_dirty(handle, inode, path) \
100+
__ext4_ext_dirty(__func__, __LINE__, (handle), (inode), (path))
101+
static int __ext4_ext_dirty(const char *where, unsigned int line,
102+
handle_t *handle, struct inode *inode,
103+
struct ext4_ext_path *path)
101104
{
102105
int err;
103106
if (path->p_bh) {
104107
/* path points to block */
105-
err = ext4_handle_dirty_metadata(handle, inode, path->p_bh);
108+
err = __ext4_handle_dirty_metadata(where, line, handle,
109+
inode, path->p_bh);
106110
} else {
107111
/* path points to leaf/index in inode body */
108112
err = ext4_mark_inode_dirty(handle, inode);

fs/jbd2/transaction.c

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,10 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh,
10491049
* mark dirty metadata which needs to be journaled as part of the current
10501050
* transaction.
10511051
*
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+
*
10521056
* The buffer is placed on the transaction's metadata list and is marked
10531057
* as belonging to the transaction.
10541058
*
@@ -1065,11 +1069,16 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
10651069
transaction_t *transaction = handle->h_transaction;
10661070
journal_t *journal = transaction->t_journal;
10671071
struct journal_head *jh = bh2jh(bh);
1072+
int ret = 0;
10681073

10691074
jbd_debug(5, "journal_head %p\n", jh);
10701075
JBUFFER_TRACE(jh, "entry");
10711076
if (is_handle_aborted(handle))
10721077
goto out;
1078+
if (!buffer_jbd(bh)) {
1079+
ret = -EUCLEAN;
1080+
goto out;
1081+
}
10731082

10741083
jbd_lock_bh_state(bh);
10751084

@@ -1093,8 +1102,20 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
10931102
*/
10941103
if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) {
10951104
JBUFFER_TRACE(jh, "fastpath");
1096-
J_ASSERT_JH(jh, jh->b_transaction ==
1097-
journal->j_running_transaction);
1105+
if (unlikely(jh->b_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+
}
10981119
goto out_unlock_bh;
10991120
}
11001121

@@ -1108,9 +1129,32 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
11081129
*/
11091130
if (jh->b_transaction != transaction) {
11101131
JBUFFER_TRACE(jh, "already on other transaction");
1111-
J_ASSERT_JH(jh, jh->b_transaction ==
1112-
journal->j_committing_transaction);
1113-
J_ASSERT_JH(jh, jh->b_next_transaction == transaction);
1132+
if (unlikely(jh->b_transaction !=
1133+
journal->j_committing_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+
}
11141158
/* And this case is illegal: we can't reuse another
11151159
* transaction's data buffer, ever. */
11161160
goto out_unlock_bh;
@@ -1127,7 +1171,9 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
11271171
jbd_unlock_bh_state(bh);
11281172
out:
11291173
JBUFFER_TRACE(jh, "exit");
1130-
return 0;
1174+
if (ret)
1175+
__WARN(); /* All errors are bugs, so dump the stack */
1176+
return ret;
11311177
}
11321178

11331179
/*

0 commit comments

Comments
 (0)