Skip to content

Commit db2485b

Browse files
committed
btrfs: tree-checker: add more cross checks for free space tree
This introduces extra checks using the previous key. If there is a previous key, we can do extra validations: - The previous key is FREE_SPACE_INFO This means the current extent/bitmap should be inside the free space info key range. And matches the type of the free space info. - The previous key is FREE_SPACE_EXTENT or FREE_SPACE_BITMAP In that case both the current and previous key should belong to the same block group. Thus the key type must match, and no overlap between the two keys. These extra checks are inspired by the recently added type checks during free space tree loading. The new tree-checker checks will allow earlier detection, but the loading time checks are still needed, as the tree-checker checks are still inside the same leaf, not matching per-bg level checks. Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com>
1 parent f368b81 commit db2485b

1 file changed

Lines changed: 60 additions & 7 deletions

File tree

fs/btrfs/tree-checker.c

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,8 @@ static int check_free_space_info(struct extent_buffer *leaf, struct btrfs_key *k
21502150
return 0;
21512151
}
21522152

2153-
static int check_free_space_common_key(struct extent_buffer *leaf, struct btrfs_key *key, int slot)
2153+
static int check_free_space_common_key(struct extent_buffer *leaf, struct btrfs_key *key, int slot,
2154+
struct btrfs_key *prev_key)
21542155
{
21552156
struct btrfs_fs_info *fs_info = leaf->fs_info;
21562157
const u32 blocksize = fs_info->sectorsize;
@@ -2179,14 +2180,65 @@ static int check_free_space_common_key(struct extent_buffer *leaf, struct btrfs_
21792180
type_str, key->objectid, key->offset);
21802181
return -EUCLEAN;
21812182
}
2183+
if (slot == 0)
2184+
return 0;
2185+
2186+
/*
2187+
* Make sure the current key is inside the block group, and matching
2188+
* the expected info type.
2189+
*/
2190+
if (prev_key->type == BTRFS_FREE_SPACE_INFO_KEY) {
2191+
struct btrfs_free_space_info *fsi;
2192+
u32 info_flags;
2193+
2194+
if (unlikely(key->objectid < prev_key->objectid ||
2195+
key->objectid + key->offset > prev_key->objectid + prev_key->offset)) {
2196+
generic_err(leaf, slot,
2197+
"free space %s is not inside the space info, prev key " BTRFS_KEY_FMT " current key " BTRFS_KEY_FMT,
2198+
type_str, BTRFS_KEY_FMT_VALUE(prev_key),
2199+
BTRFS_KEY_FMT_VALUE(key));
2200+
return -EUCLEAN;
2201+
}
2202+
fsi = btrfs_item_ptr(leaf, slot - 1, struct btrfs_free_space_info);
2203+
info_flags = btrfs_free_space_flags(leaf, fsi);
2204+
if (unlikely((info_flags == BTRFS_FREE_SPACE_USING_BITMAPS &&
2205+
key->type == BTRFS_FREE_SPACE_EXTENT_KEY) ||
2206+
(info_flags != BTRFS_FREE_SPACE_USING_BITMAPS &&
2207+
key->type == BTRFS_FREE_SPACE_BITMAP_KEY))) {
2208+
generic_err(leaf, slot,
2209+
"free space %s key type is not matching the type of space info, key type %u space info flags %u",
2210+
type_str, key->type, info_flags);
2211+
return -EUCLEAN;
2212+
}
2213+
return 0;
2214+
}
2215+
/*
2216+
* Previous key should be either FREE_SPACE_EXTENT or FREE_SPACE_BITMAP.
2217+
* Inside the same block group the key type should match each other, and
2218+
* no overlaps.
2219+
*/
2220+
if (unlikely(key->type != prev_key->type)) {
2221+
generic_err(leaf, slot,
2222+
"free space %s key type is not matching the type of previous key, key type %u prev key type %u",
2223+
type_str, key->type, prev_key->type);
2224+
return -EUCLEAN;
2225+
}
2226+
if (unlikely(prev_key->objectid + prev_key->offset > key->objectid)) {
2227+
generic_err(leaf, slot,
2228+
"free space %s key overlaps previous key, prev key " BTRFS_KEY_FMT " current key " BTRFS_KEY_FMT,
2229+
type_str, BTRFS_KEY_FMT_VALUE(prev_key),
2230+
BTRFS_KEY_FMT_VALUE(key));
2231+
return -EUCLEAN;
2232+
}
21822233
return 0;
21832234
}
21842235

2185-
static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key *key, int slot)
2236+
static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key *key, int slot,
2237+
struct btrfs_key *prev_key)
21862238
{
21872239
int ret;
21882240

2189-
ret = check_free_space_common_key(leaf, key, slot);
2241+
ret = check_free_space_common_key(leaf, key, slot, prev_key);
21902242
if (unlikely(ret < 0))
21912243
return ret;
21922244

@@ -2200,13 +2252,14 @@ static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key
22002252
}
22012253

22022254
static int check_free_space_bitmap(struct extent_buffer *leaf,
2203-
struct btrfs_key *key, int slot)
2255+
struct btrfs_key *key, int slot,
2256+
struct btrfs_key *prev_key)
22042257
{
22052258
struct btrfs_fs_info *fs_info = leaf->fs_info;
22062259
u32 expected_item_size;
22072260
int ret;
22082261

2209-
ret = check_free_space_common_key(leaf, key, slot);
2262+
ret = check_free_space_common_key(leaf, key, slot, prev_key);
22102263
if (unlikely(ret < 0))
22112264
return ret;
22122265

@@ -2298,10 +2351,10 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
22982351
ret = check_free_space_info(leaf, key, slot);
22992352
break;
23002353
case BTRFS_FREE_SPACE_EXTENT_KEY:
2301-
ret = check_free_space_extent(leaf, key, slot);
2354+
ret = check_free_space_extent(leaf, key, slot, prev_key);
23022355
break;
23032356
case BTRFS_FREE_SPACE_BITMAP_KEY:
2304-
ret = check_free_space_bitmap(leaf, key, slot);
2357+
ret = check_free_space_bitmap(leaf, key, slot, prev_key);
23052358
break;
23062359
case BTRFS_IDENTITY_REMAP_KEY:
23072360
case BTRFS_REMAP_KEY:

0 commit comments

Comments
 (0)