On Mar 17, 2015, at 8:08 PM, Taesoo Kim <tsgatesv@xxxxxxxxx> wrote: > > When 'jh->b_transaction == transaction' (asserted by below) > > J_ASSERT_JH(jh, (jh->b_transaction == transaction || ... > > 'journal->j_list_lock' will be incorrectly unlocked, since > spin_lock() is called only in the 'if' and 'else-if' blocks but > not in the missing 'else' case, which results in a hang or an oops: > > ------------[ cut here ]------------ > kernel BUG at fs/jbd2/transaction.c:2239! > invalid opcode: 0000 [#1] SMP > RIP: 0010: __jbd2_journal_file_buffer+0x206/0x220 [jbd2] > Call Trace: > do_get_write_access+0x33c/0x4e0 [jbd2] > jbd2_journal_get_write_access+0x27/0x40 [jbd2] > __ext4_journal_get_write_access+0x3b/0x80 [ext4] > ext4_delete_entry+0xa9/0x1a0 [ext4] > ext4_unlink+0x600/0xa90 [ext4] > > which is assert_spin_locked(&transaction->t_journal->j_list_lock). > > Move spin_unlock() into the two cases where it is actually locked. > > Signed-off-by: Taesoo Kim <tsgatesv@xxxxxxxxx> We've hit this repeatedly on kernels with commit v3.14-rc2-30-g6e4862a "jbd2: minimize region locked by j_list_lock in journal_get_create_access" under heavy load and this patch has fixed the problem. It should also be considered for stable kernels after 3.14. [I've updated the above commit message slightly to give more details.] Reviewed-by: Andreas Dilger <adilger@xxxxxxxxx> > --- > fs/jbd2/transaction.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c > index 5f09370..edb7f59 100644 > --- a/fs/jbd2/transaction.c > +++ b/fs/jbd2/transaction.c > @@ -1091,6 +1091,7 @@ int jbd2_journal_get_create_access(handle_t > JBUFFER_TRACE(jh, "file as BJ_Reserved"); > spin_lock(&journal->j_list_lock); > __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); > + spin_unlock(&journal->j_list_lock); > } else if (jh->b_transaction == journal->j_committing_transaction) { > /* first access by this transaction */ > jh->b_modified = 0; > @@ -1098,8 +1099,8 @@ int jbd2_journal_get_create_access(handle_t > JBUFFER_TRACE(jh, "set next transaction"); > spin_lock(&journal->j_list_lock); > jh->b_next_transaction = transaction; > + spin_unlock(&journal->j_list_lock); > } > - spin_unlock(&journal->j_list_lock); > jbd_unlock_bh_state(bh); > > /* > -- > 2.3.3 Cheers, Andreas
Attachment:
signature.asc
Description: Message signed with OpenPGP using GPGMail