Re: [PATCH] btrfs: zoned: don't submit orphaned extent buffers
Qu Wenruo <[email protected]>
| Newsgroups | org.kernel.vger.linux-btrfs,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
在 2026/7/3 15:24, Johannes Thumshirn 写道: > On a zoned filesystem btree_writepages() can encounter a dirty metadata > extent buffer whose block group no longer exists. Submitting a write for > such a buffer maps it to a stale/removed block-group and leaves the folio > under writeback forever, hanging later in filemap_fdatawait_range(), for > example the iput(btree_inode) in close_ctree(), which then hangs unmount. > > This is caused by btrfs_clear_buffer_dirty() not clearing the dirty bit of > a freed tree block but it sets EXTENT_BUFFER_ZONED_ZEROOUT and keeps the > buffer dirty so that it is still written out to keep the zone's > meta_write_pointer advancing sequentially. So a freed metadata block > legitimately stays dirty until that zero-write completes. > > Dropping these buffers is safe: the block group is empty, so they are > stale, unreferenced, already-freed blocks. Once the zone is reset their > zero-write is unneeded. Instead of submitting a such a write, finish the > writeback immediately. > > Reported-by: Shin'ichiro Kawasaki <[email protected]> > Fixes: 7db94301a980 ("btrfs: zoned: introduce block group context to btrfs_eb_write_context") > Cc: [email protected] > Signed-off-by: Johannes Thumshirn <[email protected]> > --- > fs/btrfs/extent_io.c | 16 ++++++++++++++-- > 1 file changed, 14 insertions(+), 2 deletions(-) > > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c > index 0edd532174fa..4a029ae719e9 100644 > --- a/fs/btrfs/extent_io.c > +++ b/fs/btrfs/extent_io.c > @@ -2280,7 +2280,8 @@ static void prepare_eb_write(struct extent_buffer *eb) > } > > static noinline_for_stack void write_one_eb(struct extent_buffer *eb, > - struct writeback_control *wbc) > + struct writeback_control *wbc, > + bool submit) > { > struct btrfs_fs_info *fs_info = eb->fs_info; > struct btrfs_bio *bbio; > @@ -2310,6 +2311,12 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb, > wbc_account_cgroup_owner(wbc, folio, range_len); > folio_unlock(folio); > } > + > + if (!submit) { > + btrfs_bio_end_io(bbio, BLK_STS_OK); > + return; > + } > + > /* > * If the fs is already in error status, do not submit any writeback > * but immediately finish it. > @@ -2397,6 +2404,8 @@ int btree_writepages(struct address_space *mapping, struct writeback_control *wb > struct extent_buffer *eb; > > while ((eb = eb_batch_next(&batch)) != NULL) { > + bool submit = true; > + > ctx.eb = eb; > > ret = btrfs_check_meta_write_pointer(eb->fs_info, &ctx); > @@ -2411,6 +2420,9 @@ int btree_writepages(struct address_space *mapping, struct writeback_control *wb > continue; > } > > + if (btrfs_is_zoned(fs_info) && !ctx.zoned_bg) > + submit = false; > + > if (!lock_extent_buffer_for_io(eb, wbc)) > continue; > > @@ -2420,7 +2432,7 @@ int btree_writepages(struct address_space *mapping, struct writeback_control *wb > btrfs_schedule_zone_finish_bg(ctx.zoned_bg, eb); > ctx.zoned_bg->meta_write_pointer += eb->len; > } > - write_one_eb(eb, wbc); > + write_one_eb(eb, wbc, submit); I understand this is the minimal fix, but I can't help but wondering, would it be more instinctual to release all ebs inside a zoned metadata bg when freeing the bg? Thanks, Qu > } > nr_to_write_done = (wbc->nr_to_write <= 0); > eb_batch_release(&batch);