From: Jan Kara <jack@suse.cz>
To: zhangshida <starzhangzsd@gmail.com>
Cc: tytso@mit.edu, jack@suse.com, linux-ext4@vger.kernel.org,
linux-kernel@vger.kernel.org, zhangshida@kylinos.cn,
Baolin Liu <liubaolin@kylinos.cn>
Subject: Re: [RFC PATCH] jbd2: fix a potential assertion failure due to improperly dirtied buffer
Date: Tue, 6 Aug 2024 15:40:23 +0200 [thread overview]
Message-ID: <20240806134023.rm2ggd7swopryqci@quack3> (raw)
In-Reply-To: <20240720062356.2522658-1-zhangshida@kylinos.cn>
Hello!
On Sat 20-07-24 14:23:56, zhangshida wrote:
> From: Shida Zhang <zhangshida@kylinos.cn>
>
> On an old kernel version(4.19, ext3, journal=data, pagesize=64k),
> an assertion failure will occasionally be triggered by the line below:
OK, just out of curiosity, why are you using data=journal mode? It doesn't
really get that much testing and the performance is quite bad...
> jbd2_journal_commit_transaction
> {
> ...
> J_ASSERT_BH(bh, !buffer_dirty(bh));
> /*
> * The buffer on BJ_Forget list and not jbddirty means
> ...
> }
>
> AFAIC, that's how the problem works:
> --------
> journal_unmap_buffer
> jbd2_journal_invalidatepage
> __ext4_journalled_invalidatepage
> ext4_journalled_invalidatepage
> do_invalidatepage
> truncate_inode_pages_range
> truncate_inode_pages
> truncate_pagecache
> ext4_setattr
> --------
>
> First try to truncate and invalidate the page.
> Sometimes the buffer and the page won't be freed immediately.
> the buffer will be sent to the BJ_Forget list of the currently
> committing transaction. Maybe the transaction knows when and how
> to free the buffer better.
> The buffer's states now: !jbd_dirty !mapped !dirty
>
> Then jbd2_journal_commit_transaction()will try to iterate over the
> BJ_Forget list:
> --------
> jbd2_journal_commit_transaction()
> while (commit_transaction->t_forget) {
> ...
> }
> --------
>
> At this exact moment, another write comes:
> --------
> mark_buffer_dirty
> __block_write_begin_int
> __block_write_begin
> ext4_write_begin
> --------
> it sees a unmapped new buffer, and marks it as dirty.
This should not happen. When ext4_setattr() truncates the file, we do not
allow reallocating these blocks for other purposes until the transaction
commits. Did you find this using some tracing or just code analysis?
There have been quite some fixes to data=journal mode since 4.19 so it may
quite well be that your problem is actually already fixed in current
kernels...
Honza
> Finally, jbd2_journal_commit_transaction()will trip over the assertion
> during the BJ_Forget list iteration.
>
> After an code analysis, it seems that nothing can prevent the
> __block_write_begin() from dirtying the buffer at this very moment.
>
> The same condition may also be applied to the lattest kernel version.
>
> To fix it:
> Add some checks to see if it is the case dirtied by __block_write_begin().
> if yes, it's okay and just let it go. The one who dirtied it and the
> jbd2_journal_commit_transaction() will know how to cooperate together and
> deal with it in a proper manner.
> if no, try to complain as we normally will do.
>
> Reported-by: Baolin Liu <liubaolin@kylinos.cn>
> Signed-off-by: Shida Zhang <zhangshida@kylinos.cn>
> ---
> fs/jbd2/commit.c | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
> index 75ea4e9a5cab..2c13d0af92d8 100644
> --- a/fs/jbd2/commit.c
> +++ b/fs/jbd2/commit.c
> @@ -1023,7 +1023,20 @@ void jbd2_journal_commit_transaction(journal_t *journal)
> if (is_journal_aborted(journal))
> clear_buffer_jbddirty(bh);
> } else {
> - J_ASSERT_BH(bh, !buffer_dirty(bh));
> + bool try_to_complain = 1;
> + struct folio *folio = NULL;
> +
> + folio = bh->b_folio;
> + /*
> + * Try not to complain about the dirty buffer marked dirty
> + * by __block_write_begin().
> + */
> + if (buffer_dirty(bh) && folio && folio->mapping
> + && folio_test_locked(folio))
> + try_to_complain = 0;
> +
> + if (try_to_complain)
> + J_ASSERT_BH(bh, !buffer_dirty(bh));
> /*
> * The buffer on BJ_Forget list and not jbddirty means
> * it has been freed by this transaction and hence it
> --
> 2.33.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
next prev parent reply other threads:[~2024-08-06 13:40 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-20 6:23 [RFC PATCH] jbd2: fix a potential assertion failure due to improperly dirtied buffer zhangshida
2024-08-06 13:40 ` Jan Kara [this message]
2024-08-07 8:10 ` Stephen Zhang
2024-08-07 12:06 ` Jan Kara
2024-08-08 3:05 ` Stephen Zhang
2024-08-09 15:55 ` Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240806134023.rm2ggd7swopryqci@quack3 \
--to=jack@suse.cz \
--cc=jack@suse.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=liubaolin@kylinos.cn \
--cc=starzhangzsd@gmail.com \
--cc=tytso@mit.edu \
--cc=zhangshida@kylinos.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox