From 0ae7840775003aa4bc10d154a23d4aa99920c704 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 16 Jun 2020 14:32:29 +0800 Subject: [PATCH] btrfs-progs: fix wrong chunk profile for do_chunk_alloc() [BUG] There is a bug report that using DUP data profile, with a 400MiB source dir, on a 7G disk leads to mkfs failure caused by ENOSPC. [CAUSE] After some debugging, it turns out that do_chunk_alloc() is always passing SINGLE profile for new chunks. The offending code looks like: extent-tree.c:: do_chunk_alloc() ret = btrfs_alloc_chunk(trans, fs_info, &start, &num_bytes, space_info->flags); However since commit bce7dbba2859 ("Btrfs-progs: only build space info's for the main flags"), we no longer store the profile bits in space_info anymore. This makes space_info never get updated properly, and causing us to creating more and more chunks to eat up most of the disk with unused SINGLE chunks, and finally leads to ENOSPC. [FIX] Fix the bug by passing the proper flags to btrfs_alloc_chunk(). Also, to address the original problem commit 2689259501c1 ("btrfs progs: fix extra metadata chunk allocation in --mixed case") tries to fix, here we do extra bit OR to ensure we get the proper flags. Issue: #258 Reviewed-by: Anand Jain Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- extent-tree.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extent-tree.c b/extent-tree.c index 65bde0e3..527fc532 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -1718,8 +1718,14 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, return 0; trans->allocating_chunk = 1; - ret = btrfs_alloc_chunk(trans, fs_info, &start, &num_bytes, - space_info->flags); + /* + * The space_info only has block group type (data/meta/sys), doesn't + * have the proper profile. + * While we still want to handle mixed block groups properly. + * So here add the extra bits for mixed profile. + */ + flags |= space_info->flags; + ret = btrfs_alloc_chunk(trans, fs_info, &start, &num_bytes, flags); if (ret == -ENOSPC) { space_info->full = 1; trans->allocating_chunk = 0; @@ -1728,8 +1734,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, BUG_ON(ret); - ret = btrfs_make_block_group(trans, fs_info, 0, space_info->flags, - start, num_bytes); + ret = btrfs_make_block_group(trans, fs_info, 0, flags, start, + num_bytes); BUG_ON(ret); trans->allocating_chunk = 0; return 0;