| From 4c82652496da375301655e011a0aec360c40f7f4 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 17 Jun 2020 11:25:49 +0200 |
| Subject: jbd2: make sure jh have b_transaction set in refile/unfile_buffer |
| |
| From: Lukas Czerner <lczerner@redhat.com> |
| |
| [ Upstream commit 24dc9864914eb5813173cfa53313fcd02e4aea7d ] |
| |
| Callers of __jbd2_journal_unfile_buffer() and |
| __jbd2_journal_refile_buffer() assume that the b_transaction is set. In |
| fact if it's not, we can end up with journal_head refcounting errors |
| leading to crash much later that might be very hard to track down. Add |
| asserts to make sure that is the case. |
| |
| We also make sure that b_next_transaction is NULL in |
| __jbd2_journal_unfile_buffer() since the callers expect that as well and |
| we should not get into that stage in this state anyway, leading to |
| problems later on if we do. |
| |
| Tested with fstests. |
| |
| Signed-off-by: Lukas Czerner <lczerner@redhat.com> |
| Reviewed-by: Jan Kara <jack@suse.cz> |
| Link: https://lore.kernel.org/r/20200617092549.6712-1-lczerner@redhat.com |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/jbd2/transaction.c | 10 ++++++++++ |
| 1 file changed, 10 insertions(+) |
| |
| diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c |
| index 8de458d64134a..1478512ecab3e 100644 |
| --- a/fs/jbd2/transaction.c |
| +++ b/fs/jbd2/transaction.c |
| @@ -1896,6 +1896,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) |
| */ |
| static void __jbd2_journal_unfile_buffer(struct journal_head *jh) |
| { |
| + J_ASSERT_JH(jh, jh->b_transaction != NULL); |
| + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); |
| + |
| __jbd2_journal_temp_unlink_buffer(jh); |
| jh->b_transaction = NULL; |
| jbd2_journal_put_journal_head(jh); |
| @@ -2443,6 +2446,13 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) |
| |
| was_dirty = test_clear_buffer_jbddirty(bh); |
| __jbd2_journal_temp_unlink_buffer(jh); |
| + |
| + /* |
| + * b_transaction must be set, otherwise the new b_transaction won't |
| + * be holding jh reference |
| + */ |
| + J_ASSERT_JH(jh, jh->b_transaction != NULL); |
| + |
| /* |
| * We set b_transaction here because b_next_transaction will inherit |
| * our jh reference and thus __jbd2_journal_file_buffer() must not |
| -- |
| 2.25.1 |
| |