btrfs-progs: kernel-shared: sync tree-checker.c

Sync from kernel 6.12 queue:

- dir type range
- DEV_EXTENT item checks

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2024-09-17 15:05:31 +02:00
parent 158a25af0d
commit bc2317381d
2 changed files with 73 additions and 2 deletions

View File

@ -585,9 +585,10 @@ static int check_dir_item(struct extent_buffer *leaf,
/* dir type check */ /* dir type check */
dir_type = btrfs_dir_ftype(leaf, di); dir_type = btrfs_dir_ftype(leaf, di);
if (unlikely(dir_type >= BTRFS_FT_MAX)) { if (unlikely(dir_type <= BTRFS_FT_UNKNOWN ||
dir_type >= BTRFS_FT_MAX)) {
dir_item_err(leaf, slot, dir_item_err(leaf, slot,
"invalid dir item type, have %u expect [0, %u)", "invalid dir item type, have %u expect (0, %u)",
dir_type, BTRFS_FT_MAX); dir_type, BTRFS_FT_MAX);
return -EUCLEAN; return -EUCLEAN;
} }
@ -1737,6 +1738,72 @@ static int check_raid_stripe_extent(const struct extent_buffer *leaf,
return 0; return 0;
} }
static int check_dev_extent_item(const struct extent_buffer *leaf,
const struct btrfs_key *key,
int slot,
struct btrfs_key *prev_key)
{
struct btrfs_dev_extent *de;
const u32 sectorsize = leaf->fs_info->sectorsize;
de = btrfs_item_ptr(leaf, slot, struct btrfs_dev_extent);
/* Basic fixed member checks. */
if (unlikely(btrfs_dev_extent_chunk_tree(leaf, de) !=
BTRFS_CHUNK_TREE_OBJECTID)) {
generic_err(leaf, slot,
"invalid dev extent chunk tree id, has %llu expect %llu",
btrfs_dev_extent_chunk_tree(leaf, de),
BTRFS_CHUNK_TREE_OBJECTID);
return -EUCLEAN;
}
if (unlikely(btrfs_dev_extent_chunk_objectid(leaf, de) !=
BTRFS_FIRST_CHUNK_TREE_OBJECTID)) {
generic_err(leaf, slot,
"invalid dev extent chunk objectid, has %llu expect %llu",
btrfs_dev_extent_chunk_objectid(leaf, de),
BTRFS_FIRST_CHUNK_TREE_OBJECTID);
return -EUCLEAN;
}
/* Alignment check. */
if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
generic_err(leaf, slot,
"invalid dev extent key.offset, has %llu not aligned to %u",
key->offset, sectorsize);
return -EUCLEAN;
}
if (unlikely(!IS_ALIGNED(btrfs_dev_extent_chunk_offset(leaf, de),
sectorsize))) {
generic_err(leaf, slot,
"invalid dev extent chunk offset, has %llu not aligned to %u",
btrfs_dev_extent_chunk_objectid(leaf, de),
sectorsize);
return -EUCLEAN;
}
if (unlikely(!IS_ALIGNED(btrfs_dev_extent_length(leaf, de),
sectorsize))) {
generic_err(leaf, slot,
"invalid dev extent length, has %llu not aligned to %u",
btrfs_dev_extent_length(leaf, de), sectorsize);
return -EUCLEAN;
}
/* Overlap check with previous dev extent. */
if (slot && prev_key->objectid == key->objectid &&
prev_key->type == key->type) {
struct btrfs_dev_extent *prev_de;
u64 prev_len;
prev_de = btrfs_item_ptr(leaf, slot - 1, struct btrfs_dev_extent);
prev_len = btrfs_dev_extent_length(leaf, prev_de);
if (unlikely(prev_key->offset + prev_len > key->offset)) {
generic_err(leaf, slot,
"dev extent overlap, prev offset %llu len %llu current offset %llu",
prev_key->objectid, prev_len, key->offset);
return -EUCLEAN;
}
}
return 0;
}
/* /*
* Common point to switch the item-specific validation. * Common point to switch the item-specific validation.
*/ */
@ -1777,6 +1844,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
case BTRFS_DEV_ITEM_KEY: case BTRFS_DEV_ITEM_KEY:
ret = check_dev_item(leaf, key, slot); ret = check_dev_item(leaf, key, slot);
break; break;
case BTRFS_DEV_EXTENT_KEY:
ret = check_dev_extent_item(leaf, key, slot, prev_key);
break;
case BTRFS_INODE_ITEM_KEY: case BTRFS_INODE_ITEM_KEY:
ret = check_inode_item(leaf, key, slot); ret = check_inode_item(leaf, key, slot);
break; break;

View File

@ -54,6 +54,7 @@ enum btrfs_tree_block_status {
BTRFS_TREE_BLOCK_INVALID_BLOCKPTR, BTRFS_TREE_BLOCK_INVALID_BLOCKPTR,
BTRFS_TREE_BLOCK_INVALID_ITEM, BTRFS_TREE_BLOCK_INVALID_ITEM,
BTRFS_TREE_BLOCK_INVALID_OWNER, BTRFS_TREE_BLOCK_INVALID_OWNER,
BTRFS_TREE_BLOCK_WRITTEN_NOT_SET,
}; };
/* /*