diff options
Diffstat (limited to 'fs/btrfs/tree-checker.c')
| -rw-r--r-- | fs/btrfs/tree-checker.c | 74 | 
1 files changed, 72 insertions, 2 deletions
| diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index a825fa598e3c..634d69964fe4 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -569,9 +569,10 @@ static int check_dir_item(struct extent_buffer *leaf,  		/* dir type check */  		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, -			"invalid dir item type, have %u expect [0, %u)", +			"invalid dir item type, have %u expect (0, %u)",  				dir_type, BTRFS_FT_MAX);  			return -EUCLEAN;  		} @@ -1763,6 +1764,72 @@ static int check_raid_stripe_extent(const struct extent_buffer *leaf,  	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.   */ @@ -1799,6 +1866,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,  	case BTRFS_DEV_ITEM_KEY:  		ret = check_dev_item(leaf, key, slot);  		break; +	case BTRFS_DEV_EXTENT_KEY: +		ret = check_dev_extent_item(leaf, key, slot, prev_key); +		break;  	case BTRFS_INODE_ITEM_KEY:  		ret = check_inode_item(leaf, key, slot);  		break; |