Re: [PATCH 14/19] ocfs2: check for a stale write error before reusing a metadata buffer
Jan Kara <[email protected]> Tue, 4 Aug 2026 10:50:18 +0200
| Newsgroups | org.kernel.vger.linux-ext4,dev.linux.lists.gfs2,dev.linux.lists.ocfs2-devel,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <zkfpbzavypza6z427zvsjohfrtrowlktdv7nstt3pciph2m2hi@6fhq6rpyguoa> |
On Sat 01-08-26 18:00:58, Chao Shi wrote: > __ocfs2_journal_access() refuses to journal a buffer whose previous write > failed, and turns the filesystem read-only rather than risk metadata > inconsistency. That check sits inside an if (!buffer_uptodate(bh)) block, > because until now a failed write also cleared BH_Uptodate. > > This series stops clearing BH_Uptodate on write error, so that outer test > would never fire again and ocfs2 would silently start reusing buffers whose > last write failed. Hoist the check out of the debug block, where it does > not depend on BH_Uptodate any more, and drop the now dead second half of > its condition. > > The mlog() pair keeps its own !buffer_uptodate() guard: it is a separate > "we can safely remove this assertion after testing" debug aid about being > handed a buffer with no valid contents, which is a different question from > whether the last write of that buffer failed. > > The unlocked test followed by a locked retest is deliberate. BH_Write_EIO > is cleared under the buffer lock when the buffer is submitted for write > again, so taking the lock and looking a second time avoids turning the > filesystem read-only over an error that a concurrent rewrite has already > cleared, while keeping the common case lock-free. > > The code in this patch is Jan's, from the review discussion linked in the > cover letter. > > Suggested-by: Jan Kara <[email protected]> > Signed-off-by: Chao Shi <[email protected]> Looks good. Feel free to add: Reviewed-by: Jan Kara <[email protected]> Honza > --- > fs/ocfs2/journal.c | 25 +++++++++++++------------ > 1 file changed, 13 insertions(+), 12 deletions(-) > > diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c > index d8afbc1a76bb..ea6802d894c2 100644 > --- a/fs/ocfs2/journal.c > +++ b/fs/ocfs2/journal.c > @@ -676,19 +676,20 @@ static int __ocfs2_journal_access(handle_t *handle, > mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); > mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n", > (unsigned long long)bh->b_blocknr, bh->b_state); > - > + } > + /* > + * A previous transaction with a couple of buffer heads fail > + * to checkpoint, so all the bhs are marked as BH_Write_EIO. > + * For current transaction, the bh is just among those error > + * bhs which previous transaction handle. We can't just clear > + * its BH_Write_EIO and reuse directly, since other bhs are > + * not written to disk yet and that will cause metadata > + * inconsistency. So we should set fs read-only to avoid > + * further damage. > + */ > + if (buffer_write_io_error(bh)) { > lock_buffer(bh); > - /* > - * A previous transaction with a couple of buffer heads fail > - * to checkpoint, so all the bhs are marked as BH_Write_EIO. > - * For current transaction, the bh is just among those error > - * bhs which previous transaction handle. We can't just clear > - * its BH_Write_EIO and reuse directly, since other bhs are > - * not written to disk yet and that will cause metadata > - * inconsistency. So we should set fs read-only to avoid > - * further damage. > - */ > - if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) { > + if (buffer_write_io_error(bh)) { > unlock_buffer(bh); > return ocfs2_error(osb->sb, "A previous attempt to " > "write this buffer head failed\n"); > -- > 2.43.0 > -- Jan Kara <[email protected]> SUSE Labs, CR