@@ -621,11 +621,18 @@ static void block_group_err(const struct extent_buffer *eb, int slot,
vaf.fmt = fmt;
vaf.va = &args;
- btrfs_crit(fs_info,
- "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
- btrfs_header_level(eb) == 0 ? "leaf" : "node",
- btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
- key.objectid, key.offset, &vaf);
+ if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY)
+ btrfs_crit(fs_info,
+"corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
+ btrfs_header_level(eb) == 0 ? "leaf" : "node",
+ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+ key.objectid, key.offset, &vaf);
+ else
+ btrfs_crit(fs_info,
+"corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu, %pV",
+ btrfs_header_level(eb) == 0 ? "leaf" : "node",
+ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+ key.objectid, &vaf);
va_end(args);
}
@@ -698,6 +705,42 @@ static int check_block_group_item(struct extent_buffer *leaf,
return 0;
}
+static int check_skinny_block_group_item(struct extent_buffer *leaf,
+ struct btrfs_key *key,
+ struct btrfs_key *prev_key, int slot)
+{
+ if (btrfs_header_owner(leaf) != BTRFS_BLOCK_GROUP_TREE_OBJECTID) {
+ block_group_err(leaf, slot,
+ "bad tree owner for skinny block group item, have %llu expect %llu",
+ btrfs_header_owner(leaf),
+ BTRFS_BLOCK_GROUP_TREE_OBJECTID);
+ return -EUCLEAN;
+ }
+ /*
+ * We can't do direct key->offset check, but at least we shouldn't
+ * have anything larger than max chunk size.
+ * Here we use something way larger than that to ensure we only catch
+ * obviouly wrong result.
+ */
+ if (key->offset >= SZ_64T) {
+ block_group_err(leaf, slot,
+ "too large used num bytes, have %llu expect [0, %llu)",
+ key->offset, BTRFS_MAX_DATA_CHUNK_SIZE);
+ return -EUCLEAN;
+ }
+
+ /*
+ * There shouldn't be any duplicated skinny bg items
+ * (same objectid but different offset)
+ */
+ if (slot > 0 && prev_key->objectid == key->objectid) {
+ block_group_err(leaf, slot,
+ "duplicated skinny block group items found");
+ return -EUCLEAN;
+ }
+ return 0;
+}
+
__printf(4, 5)
__cold
static void chunk_err(const struct extent_buffer *leaf,
@@ -1511,6 +1554,9 @@ static int check_leaf_item(struct extent_buffer *leaf,
case BTRFS_BLOCK_GROUP_ITEM_KEY:
ret = check_block_group_item(leaf, key, slot);
break;
+ case BTRFS_SKINNY_BLOCK_GROUP_ITEM_KEY:
+ ret = check_skinny_block_group_item(leaf, key, prev_key, slot);
+ break;
case BTRFS_CHUNK_ITEM_KEY:
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
ret = check_leaf_chunk_item(leaf, chunk, key, slot);
The check is pretty simple, just two checks: - Tree owner check Skinny block group item should only exist in block group tree. - Used num bytes (key->offset) To avoid possible later chunk size change, here we use super large value (64T) as threshold to reduce false alert. - Duplicated skinny block group items There shouldn't be duplicated items for the same block group. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/tree-checker.c | 56 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-)