[PATCH] btrfs: zoned: don't submit orphaned extent buffers
Johannes Thumshirn <[email protected]>
| Newsgroups | org.kernel.vger.linux-btrfs,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
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); } nr_to_write_done = (wbc->nr_to_write <= 0); eb_batch_release(&batch); -- 2.54.0