History

btrfs: tree-checker: introduce checks for FREE_SPACE_INFO

Introduce checks for FREE_SPACE_INFO item, which include: - Key alignment check The objectid is the logical bytenr of the chunk/bg, and offset is the length of the chunk/bg, thus they should all be aligned to the fs block size. - Item size check The FREE_SPACE_INFO should a fix size. - Flags check The flags member should have no other flags than BTRFS_FREE_SPACE_USING_BITMAPS. For future expansion, introduce a new macro BTRFS_FREE_SPACE_FLAGS_MASK for such checks. And since we're here, the BTRFS_FREE_SPACE_USING_BITMAPS should not use unsigned long long, as the flags is only 32 bits wide. So fix that to use unsigned long. - Extent count check That member shows how many free space bitmap/extent items there are inside the chunk/bg. We know the chunk size (from key->offset), thus there should be at most (key->offset >> sectorsize_bits) blocks inside the chunk. Use that value as the upper limit and if that counter is larger than that, there is a high chance it's a bitflip in high bits.

Qu Wenruo committed 8 months ago

Commit 52e71eb1 parent ad0c23c2 files · +52 −1Browse files

Unified · Split

2 files
  1. fs/btrfs/tree-checker.c +50 −0
  2. include/uapi/linux/btrfs_tree.h +2 −1
fs/btrfs/tree-checker.c+50−0
@@ -1945,6 +1945,53 @@ static int check_dev_extent_item(const struct extent_buffer *leaf, · 1944 unmodified lines
19451945 return 0;
19461946 }
19471947
1948+static int check_free_space_info(struct extent_buffer *leaf, struct btrfs_key *key,
1949+ int slot)
1950+{
1951+ struct btrfs_fs_info *fs_info = leaf->fs_info;
1952+ struct btrfs_free_space_info *fsi;
1953+ const u32 blocksize = fs_info->sectorsize;
1954+ u32 flags;
1955+
1956+ if (unlikely(!IS_ALIGNED(key->objectid, blocksize))) {
1957+ generic_err(leaf, slot,
1958+ "free space info key objectid is not aligned to %u, has " BTRFS_KEY_FMT,
1959+ blocksize, BTRFS_KEY_FMT_VALUE(key));
1960+ return -EUCLEAN;
1961+ }
1962+ if (unlikely(!IS_ALIGNED(key->offset, blocksize))) {
1963+ generic_err(leaf, slot,
1964+ "free space info key offset is not aligned to %u, has " BTRFS_KEY_FMT,
1965+ blocksize, BTRFS_KEY_FMT_VALUE(key));
1966+ return -EUCLEAN;
1967+ }
1968+ if (unlikely(btrfs_item_size(leaf, slot) !=
1969+ sizeof(struct btrfs_free_space_info))) {
1970+ generic_err(leaf, slot,
1971+ "invalid item size for free space info, has %u expect %zu",
1972+ btrfs_item_size(leaf, slot),
1973+ sizeof(struct btrfs_free_space_info));
1974+ return -EUCLEAN;
1975+ }
1976+ fsi = btrfs_item_ptr(leaf, slot, struct btrfs_free_space_info);
1977+ flags = btrfs_free_space_flags(leaf, fsi);
1978+ if (unlikely(flags & ~BTRFS_FREE_SPACE_FLAGS_MASK)) {
1979+ generic_err(leaf, slot,
1980+ "unknown flags for free space info, has 0x%x valid mask 0x%lx",
1981+ flags, BTRFS_FREE_SPACE_FLAGS_MASK);
1982+ return -EUCLEAN;
1983+ }
1984+ if (unlikely(btrfs_free_space_extent_count(leaf, fsi) >
1985+ key->offset >> fs_info->sectorsize_bits)) {
1986+ generic_err(leaf, slot,
1987+ "suspicious extent count, has %u max valid %llu",
1988+ btrfs_free_space_extent_count(leaf, fsi),
1989+ key->offset >> fs_info->sectorsize_bits);
1990+ return -EUCLEAN;
1991+ }
1992+ return 0;
1993+}
1994+
19481995 /*
19491996 * Common point to switch the item-specific validation.
19501997 */
@@ -2008,6 +2055,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf, · 57 unmodified lines
20082055 case BTRFS_RAID_STRIPE_KEY:
20092056 ret = check_raid_stripe_extent(leaf, key, slot);
20102057 break;
2058+ case BTRFS_FREE_SPACE_INFO_KEY:
2059+ ret = check_free_space_info(leaf, key, slot);
2060+ break;
20112061 }
20122062
20132063 if (unlikely(ret))
include/uapi/linux/btrfs_tree.h+2−1
@@ -1245,7 +1245,8 @@ struct btrfs_free_space_info { · 1244 unmodified lines
12451245 __le32 flags;
12461246 } __attribute__ ((__packed__));
12471247
1248−#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0)
1248+#define BTRFS_FREE_SPACE_USING_BITMAPS (1UL << 0)
1249+#define BTRFS_FREE_SPACE_FLAGS_MASK (BTRFS_FREE_SPACE_USING_BITMAPS)
12491250
12501251 #define BTRFS_QGROUP_LEVEL_SHIFT 48
12511252 static inline __u16 btrfs_qgroup_level(__u64 qgroupid)