diff mbox

Btrfs: bail out if block group has different mixed flag

Message ID 1472173707-4533-1-git-send-email-bo.li.liu@oracle.com (mailing list archive)
State Accepted
Headers show

Commit Message

Liu Bo Aug. 26, 2016, 1:08 a.m. UTC
Currently we allow inconsistence about mixed flag
 (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA).

We'd get ENOSPC if block group has mixed flag and btrfs doesn't.
If that happens, we have one space_info with mixed flag and another
space_info only with BTRFS_BLOCK_GROUP_METADATA, and
global_block_rsv.space_info points to the latter one, but all bytes
from block_group contributes to the mixed space_info, thus all the
allocation will fail with ENOSPC.

This adds a check for the above case.

Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
---
 fs/btrfs/extent-tree.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

Comments

David Sterba Sept. 1, 2016, 3:28 p.m. UTC | #1
On Thu, Aug 25, 2016 at 06:08:27PM -0700, Liu Bo wrote:
> Currently we allow inconsistence about mixed flag
>  (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA).
> 
> We'd get ENOSPC if block group has mixed flag and btrfs doesn't.
> If that happens, we have one space_info with mixed flag and another
> space_info only with BTRFS_BLOCK_GROUP_METADATA, and
> global_block_rsv.space_info points to the latter one, but all bytes
> from block_group contributes to the mixed space_info, thus all the
> allocation will fail with ENOSPC.
> 
> This adds a check for the above case.
> 
> Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
> Signed-off-by: Liu Bo <bo.li.liu@oracle.com>

OK for the fix. Even if we allow combining mixed and split bg, the
incompat bit must be present. This could be also part of fsck, as we
don't give an option how to fix that.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 806921f..642e0f0 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -10150,6 +10150,11 @@  int btrfs_read_block_groups(struct btrfs_root *root)
 	struct extent_buffer *leaf;
 	int need_clear = 0;
 	u64 cache_gen;
+	u64 feature;
+	int mixed;
+
+	feature = btrfs_super_incompat_flags(info->super_copy);
+	mixed = !!(feature & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS);
 
 	root = info->extent_root;
 	key.objectid = 0;
@@ -10203,6 +10208,15 @@  int btrfs_read_block_groups(struct btrfs_root *root)
 				   btrfs_item_ptr_offset(leaf, path->slots[0]),
 				   sizeof(cache->item));
 		cache->flags = btrfs_block_group_flags(&cache->item);
+		if (!mixed &&
+		    ((cache->flags & BTRFS_BLOCK_GROUP_METADATA) &&
+		    (cache->flags & BTRFS_BLOCK_GROUP_DATA))) {
+			btrfs_err(info,
+	 "bg(%llu) is a mixed block group but this is not a mixed btrfs image.",
+				  cache->key.objectid);
+			ret = -EINVAL;
+			goto error;
+		}
 
 		key.objectid = found_key.objectid + found_key.offset;
 		btrfs_release_path(path);