Skip to content

Commit 1af4595

Browse files
naotakdave
authored andcommitted
btrfs: zoned: do not remove unwritten non-data block group
There are some reports of "unable to find chunk map for logical 2147483648 length 16384" error message appears in dmesg. This means some IOs are occurring after a block group is removed. When a metadata tree node is cleaned on a zoned setup, we keep that node still dirty and write it out not to create a write hole. However, this can make a block group's used bytes == 0 while there is a dirty region left. Such an unused block group is moved into the unused_bg list and processed for removal. When the removal succeeds, the block group is removed from the transaction->dirty_bgs list, so the unused dirty nodes in the block group are not sent at the transaction commit time. It will be written at some later time e.g, sync or umount, and causes "unable to find chunk map" errors. This can happen relatively easy on SMR whose zone size is 256MB. However, calling do_zone_finish() on such block group returns -EAGAIN and keep that block group intact, which is why the issue is hidden until now. Fixes: afba2bc ("btrfs: zoned: implement active zone tracking") CC: [email protected] # 6.1+ Reviewed-by: Johannes Thumshirn <[email protected]> Signed-off-by: Naohiro Aota <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 239c68b commit 1af4595

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

fs/btrfs/block-group.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ int btrfs_should_fragment_free_space(const struct btrfs_block_group *block_group
3434
}
3535
#endif
3636

37+
static inline bool has_unwritten_metadata(struct btrfs_block_group *block_group)
38+
{
39+
/* The meta_write_pointer is available only on the zoned setup. */
40+
if (!btrfs_is_zoned(block_group->fs_info))
41+
return false;
42+
43+
if (block_group->flags & BTRFS_BLOCK_GROUP_DATA)
44+
return false;
45+
46+
return block_group->start + block_group->alloc_offset >
47+
block_group->meta_write_pointer;
48+
}
49+
3750
/*
3851
* Return target flags in extended format or 0 if restripe for this chunk_type
3952
* is not in progress
@@ -1244,6 +1257,15 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
12441257
goto out;
12451258

12461259
spin_lock(&block_group->lock);
1260+
/*
1261+
* Hitting this WARN means we removed a block group with an unwritten
1262+
* region. It will cause "unable to find chunk map for logical" errors.
1263+
*/
1264+
if (WARN_ON(has_unwritten_metadata(block_group)))
1265+
btrfs_warn(fs_info,
1266+
"block group %llu is removed before metadata write out",
1267+
block_group->start);
1268+
12471269
set_bit(BLOCK_GROUP_FLAG_REMOVED, &block_group->runtime_flags);
12481270

12491271
/*
@@ -1586,8 +1608,9 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
15861608
* needing to allocate extents from the block group.
15871609
*/
15881610
used = btrfs_space_info_used(space_info, true);
1589-
if (space_info->total_bytes - block_group->length < used &&
1590-
block_group->zone_unusable < block_group->length) {
1611+
if ((space_info->total_bytes - block_group->length < used &&
1612+
block_group->zone_unusable < block_group->length) ||
1613+
has_unwritten_metadata(block_group)) {
15911614
/*
15921615
* Add a reference for the list, compensate for the ref
15931616
* drop under the "next" label for the

0 commit comments

Comments
 (0)