1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 27c55ee0cSOmar Sandoval /* 37c55ee0cSOmar Sandoval * Copyright (C) 2015 Facebook. All rights reserved. 47c55ee0cSOmar Sandoval */ 57c55ee0cSOmar Sandoval 6b9ef22deSFeifei Xu #include <linux/types.h> 77c55ee0cSOmar Sandoval #include "btrfs-tests.h" 87c55ee0cSOmar Sandoval #include "../ctree.h" 97c55ee0cSOmar Sandoval #include "../disk-io.h" 107c55ee0cSOmar Sandoval #include "../free-space-tree.h" 117c55ee0cSOmar Sandoval #include "../transaction.h" 12*aac0023cSJosef Bacik #include "../block-group.h" 137c55ee0cSOmar Sandoval 147c55ee0cSOmar Sandoval struct free_space_extent { 150e675785SDavid Sterba u64 start; 160e675785SDavid Sterba u64 length; 177c55ee0cSOmar Sandoval }; 187c55ee0cSOmar Sandoval 197c55ee0cSOmar Sandoval static int __check_free_space_extents(struct btrfs_trans_handle *trans, 207c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 217c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 227c55ee0cSOmar Sandoval struct btrfs_path *path, 23d2d9ac6aSDavid Sterba const struct free_space_extent * const extents, 247c55ee0cSOmar Sandoval unsigned int num_extents) 257c55ee0cSOmar Sandoval { 267c55ee0cSOmar Sandoval struct btrfs_free_space_info *info; 277c55ee0cSOmar Sandoval struct btrfs_key key; 287c55ee0cSOmar Sandoval int prev_bit = 0, bit; 297c55ee0cSOmar Sandoval u64 extent_start = 0, offset, end; 307c55ee0cSOmar Sandoval u32 flags, extent_count; 317c55ee0cSOmar Sandoval unsigned int i; 327c55ee0cSOmar Sandoval int ret; 337c55ee0cSOmar Sandoval 342ccf545eSDavid Sterba info = search_free_space_info(trans, cache, path, 0); 357c55ee0cSOmar Sandoval if (IS_ERR(info)) { 363c7251f2SDavid Sterba test_err("could not find free space info"); 377c55ee0cSOmar Sandoval ret = PTR_ERR(info); 387c55ee0cSOmar Sandoval goto out; 397c55ee0cSOmar Sandoval } 407c55ee0cSOmar Sandoval flags = btrfs_free_space_flags(path->nodes[0], info); 417c55ee0cSOmar Sandoval extent_count = btrfs_free_space_extent_count(path->nodes[0], info); 427c55ee0cSOmar Sandoval 437c55ee0cSOmar Sandoval if (extent_count != num_extents) { 443c7251f2SDavid Sterba test_err("extent count is wrong"); 457c55ee0cSOmar Sandoval ret = -EINVAL; 467c55ee0cSOmar Sandoval goto out; 477c55ee0cSOmar Sandoval } 487c55ee0cSOmar Sandoval if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 497c55ee0cSOmar Sandoval if (path->slots[0] != 0) 507c55ee0cSOmar Sandoval goto invalid; 517c55ee0cSOmar Sandoval end = cache->key.objectid + cache->key.offset; 527c55ee0cSOmar Sandoval i = 0; 537c55ee0cSOmar Sandoval while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) { 547c55ee0cSOmar Sandoval btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 557c55ee0cSOmar Sandoval if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY) 567c55ee0cSOmar Sandoval goto invalid; 577c55ee0cSOmar Sandoval offset = key.objectid; 587c55ee0cSOmar Sandoval while (offset < key.objectid + key.offset) { 597c55ee0cSOmar Sandoval bit = free_space_test_bit(cache, path, offset); 607c55ee0cSOmar Sandoval if (prev_bit == 0 && bit == 1) { 617c55ee0cSOmar Sandoval extent_start = offset; 627c55ee0cSOmar Sandoval } else if (prev_bit == 1 && bit == 0) { 637c55ee0cSOmar Sandoval if (i >= num_extents) 647c55ee0cSOmar Sandoval goto invalid; 657c55ee0cSOmar Sandoval if (i >= num_extents || 667c55ee0cSOmar Sandoval extent_start != extents[i].start || 677c55ee0cSOmar Sandoval offset - extent_start != extents[i].length) 687c55ee0cSOmar Sandoval goto invalid; 697c55ee0cSOmar Sandoval i++; 707c55ee0cSOmar Sandoval } 717c55ee0cSOmar Sandoval prev_bit = bit; 7223d1f737SNikolay Borisov offset += fs_info->sectorsize; 737c55ee0cSOmar Sandoval } 747c55ee0cSOmar Sandoval } 757c55ee0cSOmar Sandoval if (prev_bit == 1) { 767c55ee0cSOmar Sandoval if (i >= num_extents || 777c55ee0cSOmar Sandoval extent_start != extents[i].start || 787c55ee0cSOmar Sandoval end - extent_start != extents[i].length) 797c55ee0cSOmar Sandoval goto invalid; 807c55ee0cSOmar Sandoval i++; 817c55ee0cSOmar Sandoval } 827c55ee0cSOmar Sandoval if (i != num_extents) 837c55ee0cSOmar Sandoval goto invalid; 847c55ee0cSOmar Sandoval } else { 857c55ee0cSOmar Sandoval if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 || 867c55ee0cSOmar Sandoval path->slots[0] != 0) 877c55ee0cSOmar Sandoval goto invalid; 887c55ee0cSOmar Sandoval for (i = 0; i < num_extents; i++) { 897c55ee0cSOmar Sandoval path->slots[0]++; 907c55ee0cSOmar Sandoval btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 917c55ee0cSOmar Sandoval if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY || 927c55ee0cSOmar Sandoval key.objectid != extents[i].start || 937c55ee0cSOmar Sandoval key.offset != extents[i].length) 947c55ee0cSOmar Sandoval goto invalid; 957c55ee0cSOmar Sandoval } 967c55ee0cSOmar Sandoval } 977c55ee0cSOmar Sandoval 987c55ee0cSOmar Sandoval ret = 0; 997c55ee0cSOmar Sandoval out: 1007c55ee0cSOmar Sandoval btrfs_release_path(path); 1017c55ee0cSOmar Sandoval return ret; 1027c55ee0cSOmar Sandoval invalid: 1033c7251f2SDavid Sterba test_err("free space tree is invalid"); 1047c55ee0cSOmar Sandoval ret = -EINVAL; 1057c55ee0cSOmar Sandoval goto out; 1067c55ee0cSOmar Sandoval } 1077c55ee0cSOmar Sandoval 1087c55ee0cSOmar Sandoval static int check_free_space_extents(struct btrfs_trans_handle *trans, 1097c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1107c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 1117c55ee0cSOmar Sandoval struct btrfs_path *path, 112d2d9ac6aSDavid Sterba const struct free_space_extent * const extents, 1137c55ee0cSOmar Sandoval unsigned int num_extents) 1147c55ee0cSOmar Sandoval { 1157c55ee0cSOmar Sandoval struct btrfs_free_space_info *info; 1167c55ee0cSOmar Sandoval u32 flags; 1177c55ee0cSOmar Sandoval int ret; 1187c55ee0cSOmar Sandoval 1192ccf545eSDavid Sterba info = search_free_space_info(trans, cache, path, 0); 1207c55ee0cSOmar Sandoval if (IS_ERR(info)) { 1213c7251f2SDavid Sterba test_err("could not find free space info"); 1227c55ee0cSOmar Sandoval btrfs_release_path(path); 1237c55ee0cSOmar Sandoval return PTR_ERR(info); 1247c55ee0cSOmar Sandoval } 1257c55ee0cSOmar Sandoval flags = btrfs_free_space_flags(path->nodes[0], info); 1267c55ee0cSOmar Sandoval btrfs_release_path(path); 1277c55ee0cSOmar Sandoval 1287c55ee0cSOmar Sandoval ret = __check_free_space_extents(trans, fs_info, cache, path, extents, 1297c55ee0cSOmar Sandoval num_extents); 1307c55ee0cSOmar Sandoval if (ret) 1317c55ee0cSOmar Sandoval return ret; 1327c55ee0cSOmar Sandoval 1337c55ee0cSOmar Sandoval /* Flip it to the other format and check that for good measure. */ 1347c55ee0cSOmar Sandoval if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 1355296c2bfSNikolay Borisov ret = convert_free_space_to_extents(trans, cache, path); 1367c55ee0cSOmar Sandoval if (ret) { 1373c7251f2SDavid Sterba test_err("could not convert to extents"); 1387c55ee0cSOmar Sandoval return ret; 1397c55ee0cSOmar Sandoval } 1407c55ee0cSOmar Sandoval } else { 141719fb4deSNikolay Borisov ret = convert_free_space_to_bitmaps(trans, cache, path); 1427c55ee0cSOmar Sandoval if (ret) { 1433c7251f2SDavid Sterba test_err("could not convert to bitmaps"); 1447c55ee0cSOmar Sandoval return ret; 1457c55ee0cSOmar Sandoval } 1467c55ee0cSOmar Sandoval } 1477c55ee0cSOmar Sandoval return __check_free_space_extents(trans, fs_info, cache, path, extents, 1487c55ee0cSOmar Sandoval num_extents); 1497c55ee0cSOmar Sandoval } 1507c55ee0cSOmar Sandoval 1517c55ee0cSOmar Sandoval static int test_empty_block_group(struct btrfs_trans_handle *trans, 1527c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1537c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 154781e3bcfSOmar Sandoval struct btrfs_path *path, 155781e3bcfSOmar Sandoval u32 alignment) 1567c55ee0cSOmar Sandoval { 157d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 1587c55ee0cSOmar Sandoval {cache->key.objectid, cache->key.offset}, 1597c55ee0cSOmar Sandoval }; 1607c55ee0cSOmar Sandoval 1617c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1627c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1637c55ee0cSOmar Sandoval } 1647c55ee0cSOmar Sandoval 1657c55ee0cSOmar Sandoval static int test_remove_all(struct btrfs_trans_handle *trans, 1667c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1677c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 168781e3bcfSOmar Sandoval struct btrfs_path *path, 169781e3bcfSOmar Sandoval u32 alignment) 1707c55ee0cSOmar Sandoval { 171d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = {}; 1727c55ee0cSOmar Sandoval int ret; 1737c55ee0cSOmar Sandoval 174c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 1757c55ee0cSOmar Sandoval cache->key.objectid, 1767c55ee0cSOmar Sandoval cache->key.offset); 1777c55ee0cSOmar Sandoval if (ret) { 1783c7251f2SDavid Sterba test_err("could not remove free space"); 1797c55ee0cSOmar Sandoval return ret; 1807c55ee0cSOmar Sandoval } 1817c55ee0cSOmar Sandoval 1827c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1837c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1847c55ee0cSOmar Sandoval } 1857c55ee0cSOmar Sandoval 1867c55ee0cSOmar Sandoval static int test_remove_beginning(struct btrfs_trans_handle *trans, 1877c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1887c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 189781e3bcfSOmar Sandoval struct btrfs_path *path, 190781e3bcfSOmar Sandoval u32 alignment) 1917c55ee0cSOmar Sandoval { 192d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 193781e3bcfSOmar Sandoval {cache->key.objectid + alignment, 194781e3bcfSOmar Sandoval cache->key.offset - alignment}, 1957c55ee0cSOmar Sandoval }; 1967c55ee0cSOmar Sandoval int ret; 1977c55ee0cSOmar Sandoval 198c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 199781e3bcfSOmar Sandoval cache->key.objectid, alignment); 2007c55ee0cSOmar Sandoval if (ret) { 2013c7251f2SDavid Sterba test_err("could not remove free space"); 2027c55ee0cSOmar Sandoval return ret; 2037c55ee0cSOmar Sandoval } 2047c55ee0cSOmar Sandoval 2057c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2067c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2077c55ee0cSOmar Sandoval 2087c55ee0cSOmar Sandoval } 2097c55ee0cSOmar Sandoval 2107c55ee0cSOmar Sandoval static int test_remove_end(struct btrfs_trans_handle *trans, 2117c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2127c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 213781e3bcfSOmar Sandoval struct btrfs_path *path, 214781e3bcfSOmar Sandoval u32 alignment) 2157c55ee0cSOmar Sandoval { 216d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 217781e3bcfSOmar Sandoval {cache->key.objectid, cache->key.offset - alignment}, 2187c55ee0cSOmar Sandoval }; 2197c55ee0cSOmar Sandoval int ret; 2207c55ee0cSOmar Sandoval 221c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 2227c55ee0cSOmar Sandoval cache->key.objectid + 223781e3bcfSOmar Sandoval cache->key.offset - alignment, 224781e3bcfSOmar Sandoval alignment); 2257c55ee0cSOmar Sandoval if (ret) { 2263c7251f2SDavid Sterba test_err("could not remove free space"); 2277c55ee0cSOmar Sandoval return ret; 2287c55ee0cSOmar Sandoval } 2297c55ee0cSOmar Sandoval 2307c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2317c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2327c55ee0cSOmar Sandoval } 2337c55ee0cSOmar Sandoval 2347c55ee0cSOmar Sandoval static int test_remove_middle(struct btrfs_trans_handle *trans, 2357c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2367c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 237781e3bcfSOmar Sandoval struct btrfs_path *path, 238781e3bcfSOmar Sandoval u32 alignment) 2397c55ee0cSOmar Sandoval { 240d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 241781e3bcfSOmar Sandoval {cache->key.objectid, alignment}, 242781e3bcfSOmar Sandoval {cache->key.objectid + 2 * alignment, 243781e3bcfSOmar Sandoval cache->key.offset - 2 * alignment}, 2447c55ee0cSOmar Sandoval }; 2457c55ee0cSOmar Sandoval int ret; 2467c55ee0cSOmar Sandoval 247c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 248781e3bcfSOmar Sandoval cache->key.objectid + alignment, 249781e3bcfSOmar Sandoval alignment); 2507c55ee0cSOmar Sandoval if (ret) { 2513c7251f2SDavid Sterba test_err("could not remove free space"); 2527c55ee0cSOmar Sandoval return ret; 2537c55ee0cSOmar Sandoval } 2547c55ee0cSOmar Sandoval 2557c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2567c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2577c55ee0cSOmar Sandoval } 2587c55ee0cSOmar Sandoval 2597c55ee0cSOmar Sandoval static int test_merge_left(struct btrfs_trans_handle *trans, 2607c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2617c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 262781e3bcfSOmar Sandoval struct btrfs_path *path, 263781e3bcfSOmar Sandoval u32 alignment) 2647c55ee0cSOmar Sandoval { 265d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 266781e3bcfSOmar Sandoval {cache->key.objectid, 2 * alignment}, 2677c55ee0cSOmar Sandoval }; 2687c55ee0cSOmar Sandoval int ret; 2697c55ee0cSOmar Sandoval 270c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 2717c55ee0cSOmar Sandoval cache->key.objectid, 2727c55ee0cSOmar Sandoval cache->key.offset); 2737c55ee0cSOmar Sandoval if (ret) { 2743c7251f2SDavid Sterba test_err("could not remove free space"); 2757c55ee0cSOmar Sandoval return ret; 2767c55ee0cSOmar Sandoval } 2777c55ee0cSOmar Sandoval 2782d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, cache->key.objectid, 2792d5cffa1SNikolay Borisov alignment); 2807c55ee0cSOmar Sandoval if (ret) { 2813c7251f2SDavid Sterba test_err("could not add free space"); 2827c55ee0cSOmar Sandoval return ret; 2837c55ee0cSOmar Sandoval } 2847c55ee0cSOmar Sandoval 2852d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 286781e3bcfSOmar Sandoval cache->key.objectid + alignment, 287781e3bcfSOmar Sandoval alignment); 2887c55ee0cSOmar Sandoval if (ret) { 2893c7251f2SDavid Sterba test_err("could not add free space"); 2907c55ee0cSOmar Sandoval return ret; 2917c55ee0cSOmar Sandoval } 2927c55ee0cSOmar Sandoval 2937c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2947c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2957c55ee0cSOmar Sandoval } 2967c55ee0cSOmar Sandoval 2977c55ee0cSOmar Sandoval static int test_merge_right(struct btrfs_trans_handle *trans, 2987c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2997c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 300781e3bcfSOmar Sandoval struct btrfs_path *path, 301781e3bcfSOmar Sandoval u32 alignment) 3027c55ee0cSOmar Sandoval { 303d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 304781e3bcfSOmar Sandoval {cache->key.objectid + alignment, 2 * alignment}, 3057c55ee0cSOmar Sandoval }; 3067c55ee0cSOmar Sandoval int ret; 3077c55ee0cSOmar Sandoval 308c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 3097c55ee0cSOmar Sandoval cache->key.objectid, 3107c55ee0cSOmar Sandoval cache->key.offset); 3117c55ee0cSOmar Sandoval if (ret) { 3123c7251f2SDavid Sterba test_err("could not remove free space"); 3137c55ee0cSOmar Sandoval return ret; 3147c55ee0cSOmar Sandoval } 3157c55ee0cSOmar Sandoval 3162d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 317781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 318781e3bcfSOmar Sandoval alignment); 3197c55ee0cSOmar Sandoval if (ret) { 3203c7251f2SDavid Sterba test_err("could not add free space"); 3217c55ee0cSOmar Sandoval return ret; 3227c55ee0cSOmar Sandoval } 3237c55ee0cSOmar Sandoval 3242d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 325781e3bcfSOmar Sandoval cache->key.objectid + alignment, 326781e3bcfSOmar Sandoval alignment); 3277c55ee0cSOmar Sandoval if (ret) { 3283c7251f2SDavid Sterba test_err("could not add free space"); 3297c55ee0cSOmar Sandoval return ret; 3307c55ee0cSOmar Sandoval } 3317c55ee0cSOmar Sandoval 3327c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3337c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3347c55ee0cSOmar Sandoval } 3357c55ee0cSOmar Sandoval 3367c55ee0cSOmar Sandoval static int test_merge_both(struct btrfs_trans_handle *trans, 3377c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 3387c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 339781e3bcfSOmar Sandoval struct btrfs_path *path, 340781e3bcfSOmar Sandoval u32 alignment) 3417c55ee0cSOmar Sandoval { 342d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 343781e3bcfSOmar Sandoval {cache->key.objectid, 3 * alignment}, 3447c55ee0cSOmar Sandoval }; 3457c55ee0cSOmar Sandoval int ret; 3467c55ee0cSOmar Sandoval 347c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 3487c55ee0cSOmar Sandoval cache->key.objectid, 3497c55ee0cSOmar Sandoval cache->key.offset); 3507c55ee0cSOmar Sandoval if (ret) { 3513c7251f2SDavid Sterba test_err("could not remove free space"); 3527c55ee0cSOmar Sandoval return ret; 3537c55ee0cSOmar Sandoval } 3547c55ee0cSOmar Sandoval 3552d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, cache->key.objectid, 3562d5cffa1SNikolay Borisov alignment); 3577c55ee0cSOmar Sandoval if (ret) { 3583c7251f2SDavid Sterba test_err("could not add free space"); 3597c55ee0cSOmar Sandoval return ret; 3607c55ee0cSOmar Sandoval } 3617c55ee0cSOmar Sandoval 3622d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 363781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 364781e3bcfSOmar Sandoval alignment); 3657c55ee0cSOmar Sandoval if (ret) { 3663c7251f2SDavid Sterba test_err("could not add free space"); 3677c55ee0cSOmar Sandoval return ret; 3687c55ee0cSOmar Sandoval } 3697c55ee0cSOmar Sandoval 3702d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 371781e3bcfSOmar Sandoval cache->key.objectid + alignment, 372781e3bcfSOmar Sandoval alignment); 3737c55ee0cSOmar Sandoval if (ret) { 3743c7251f2SDavid Sterba test_err("could not add free space"); 3757c55ee0cSOmar Sandoval return ret; 3767c55ee0cSOmar Sandoval } 3777c55ee0cSOmar Sandoval 3787c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3797c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3807c55ee0cSOmar Sandoval } 3817c55ee0cSOmar Sandoval 3827c55ee0cSOmar Sandoval static int test_merge_none(struct btrfs_trans_handle *trans, 3837c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 3847c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 385781e3bcfSOmar Sandoval struct btrfs_path *path, 386781e3bcfSOmar Sandoval u32 alignment) 3877c55ee0cSOmar Sandoval { 388d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 389781e3bcfSOmar Sandoval {cache->key.objectid, alignment}, 390781e3bcfSOmar Sandoval {cache->key.objectid + 2 * alignment, alignment}, 391781e3bcfSOmar Sandoval {cache->key.objectid + 4 * alignment, alignment}, 3927c55ee0cSOmar Sandoval }; 3937c55ee0cSOmar Sandoval int ret; 3947c55ee0cSOmar Sandoval 395c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 3967c55ee0cSOmar Sandoval cache->key.objectid, 3977c55ee0cSOmar Sandoval cache->key.offset); 3987c55ee0cSOmar Sandoval if (ret) { 3993c7251f2SDavid Sterba test_err("could not remove free space"); 4007c55ee0cSOmar Sandoval return ret; 4017c55ee0cSOmar Sandoval } 4027c55ee0cSOmar Sandoval 4032d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, cache->key.objectid, 4042d5cffa1SNikolay Borisov alignment); 4057c55ee0cSOmar Sandoval if (ret) { 4063c7251f2SDavid Sterba test_err("could not add free space"); 4077c55ee0cSOmar Sandoval return ret; 4087c55ee0cSOmar Sandoval } 4097c55ee0cSOmar Sandoval 4102d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 411781e3bcfSOmar Sandoval cache->key.objectid + 4 * alignment, 412781e3bcfSOmar Sandoval alignment); 4137c55ee0cSOmar Sandoval if (ret) { 4143c7251f2SDavid Sterba test_err("could not add free space"); 4157c55ee0cSOmar Sandoval return ret; 4167c55ee0cSOmar Sandoval } 4177c55ee0cSOmar Sandoval 4182d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 419781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 420781e3bcfSOmar Sandoval alignment); 4217c55ee0cSOmar Sandoval if (ret) { 4223c7251f2SDavid Sterba test_err("could not add free space"); 4237c55ee0cSOmar Sandoval return ret; 4247c55ee0cSOmar Sandoval } 4257c55ee0cSOmar Sandoval 4267c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 4277c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 4287c55ee0cSOmar Sandoval } 4297c55ee0cSOmar Sandoval 4307c55ee0cSOmar Sandoval typedef int (*test_func_t)(struct btrfs_trans_handle *, 4317c55ee0cSOmar Sandoval struct btrfs_fs_info *, 4327c55ee0cSOmar Sandoval struct btrfs_block_group_cache *, 433781e3bcfSOmar Sandoval struct btrfs_path *, 434781e3bcfSOmar Sandoval u32 alignment); 4357c55ee0cSOmar Sandoval 436781e3bcfSOmar Sandoval static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, 437781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 4387c55ee0cSOmar Sandoval { 4397c0260eeSJeff Mahoney struct btrfs_fs_info *fs_info; 4407c55ee0cSOmar Sandoval struct btrfs_root *root = NULL; 4417c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache = NULL; 4427c55ee0cSOmar Sandoval struct btrfs_trans_handle trans; 4437c55ee0cSOmar Sandoval struct btrfs_path *path = NULL; 4447c55ee0cSOmar Sandoval int ret; 4457c55ee0cSOmar Sandoval 446da17066cSJeff Mahoney fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 4477c0260eeSJeff Mahoney if (!fs_info) { 44837b2a7bcSDavid Sterba test_std_err(TEST_ALLOC_FS_INFO); 4497c0260eeSJeff Mahoney ret = -ENOMEM; 4507c55ee0cSOmar Sandoval goto out; 4517c55ee0cSOmar Sandoval } 4527c55ee0cSOmar Sandoval 453da17066cSJeff Mahoney root = btrfs_alloc_dummy_root(fs_info); 4547c0260eeSJeff Mahoney if (IS_ERR(root)) { 45552ab7bcaSDavid Sterba test_std_err(TEST_ALLOC_ROOT); 4567c0260eeSJeff Mahoney ret = PTR_ERR(root); 4577c55ee0cSOmar Sandoval goto out; 4587c55ee0cSOmar Sandoval } 4597c55ee0cSOmar Sandoval 4607c55ee0cSOmar Sandoval btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, 4617c55ee0cSOmar Sandoval BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); 4627c55ee0cSOmar Sandoval root->fs_info->free_space_root = root; 4637c55ee0cSOmar Sandoval root->fs_info->tree_root = root; 4647c55ee0cSOmar Sandoval 465da17066cSJeff Mahoney root->node = alloc_test_extent_buffer(root->fs_info, nodesize); 4667c55ee0cSOmar Sandoval if (!root->node) { 4679e3d9f84SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_BUFFER); 4687c55ee0cSOmar Sandoval ret = -ENOMEM; 4697c55ee0cSOmar Sandoval goto out; 4707c55ee0cSOmar Sandoval } 4717c55ee0cSOmar Sandoval btrfs_set_header_level(root->node, 0); 4727c55ee0cSOmar Sandoval btrfs_set_header_nritems(root->node, 0); 473b9ef22deSFeifei Xu root->alloc_bytenr += 2 * nodesize; 4747c55ee0cSOmar Sandoval 475da17066cSJeff Mahoney cache = btrfs_alloc_dummy_block_group(fs_info, 8 * alignment); 4767c55ee0cSOmar Sandoval if (!cache) { 4773199366dSDavid Sterba test_std_err(TEST_ALLOC_BLOCK_GROUP); 4787c55ee0cSOmar Sandoval ret = -ENOMEM; 4797c55ee0cSOmar Sandoval goto out; 4807c55ee0cSOmar Sandoval } 4817c55ee0cSOmar Sandoval cache->bitmap_low_thresh = 0; 4827c55ee0cSOmar Sandoval cache->bitmap_high_thresh = (u32)-1; 4837c55ee0cSOmar Sandoval cache->needs_free_space = 1; 484aa66b0bbSKinglong Mee cache->fs_info = root->fs_info; 4857c55ee0cSOmar Sandoval 486483bce06SNikolay Borisov btrfs_init_dummy_trans(&trans, root->fs_info); 4877c55ee0cSOmar Sandoval 4887c55ee0cSOmar Sandoval path = btrfs_alloc_path(); 4897c55ee0cSOmar Sandoval if (!path) { 490770e0cc0SDavid Sterba test_std_err(TEST_ALLOC_ROOT); 4919ca2e97fSChristophe JAILLET ret = -ENOMEM; 4929ca2e97fSChristophe JAILLET goto out; 4937c55ee0cSOmar Sandoval } 4947c55ee0cSOmar Sandoval 495e4e0711cSNikolay Borisov ret = add_block_group_free_space(&trans, cache); 4967c55ee0cSOmar Sandoval if (ret) { 4973c7251f2SDavid Sterba test_err("could not add block group free space"); 4987c55ee0cSOmar Sandoval goto out; 4997c55ee0cSOmar Sandoval } 5007c55ee0cSOmar Sandoval 5017c55ee0cSOmar Sandoval if (bitmaps) { 502719fb4deSNikolay Borisov ret = convert_free_space_to_bitmaps(&trans, cache, path); 5037c55ee0cSOmar Sandoval if (ret) { 5043c7251f2SDavid Sterba test_err("could not convert block group to bitmaps"); 5057c55ee0cSOmar Sandoval goto out; 5067c55ee0cSOmar Sandoval } 5077c55ee0cSOmar Sandoval } 5087c55ee0cSOmar Sandoval 509781e3bcfSOmar Sandoval ret = test_func(&trans, root->fs_info, cache, path, alignment); 5107c55ee0cSOmar Sandoval if (ret) 5117c55ee0cSOmar Sandoval goto out; 5127c55ee0cSOmar Sandoval 513f3f72779SNikolay Borisov ret = remove_block_group_free_space(&trans, cache); 5147c55ee0cSOmar Sandoval if (ret) { 5153c7251f2SDavid Sterba test_err("could not remove block group free space"); 5167c55ee0cSOmar Sandoval goto out; 5177c55ee0cSOmar Sandoval } 5187c55ee0cSOmar Sandoval 5197c55ee0cSOmar Sandoval if (btrfs_header_nritems(root->node) != 0) { 5203c7251f2SDavid Sterba test_err("free space tree has leftover items"); 5217c55ee0cSOmar Sandoval ret = -EINVAL; 5227c55ee0cSOmar Sandoval goto out; 5237c55ee0cSOmar Sandoval } 5247c55ee0cSOmar Sandoval 5257c55ee0cSOmar Sandoval ret = 0; 5267c55ee0cSOmar Sandoval out: 5277c55ee0cSOmar Sandoval btrfs_free_path(path); 5287c55ee0cSOmar Sandoval btrfs_free_dummy_block_group(cache); 5297c55ee0cSOmar Sandoval btrfs_free_dummy_root(root); 5307c0260eeSJeff Mahoney btrfs_free_dummy_fs_info(fs_info); 5317c55ee0cSOmar Sandoval return ret; 5327c55ee0cSOmar Sandoval } 5337c55ee0cSOmar Sandoval 534781e3bcfSOmar Sandoval static int run_test_both_formats(test_func_t test_func, u32 sectorsize, 535781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 5367c55ee0cSOmar Sandoval { 537781e3bcfSOmar Sandoval int test_ret = 0; 5387c55ee0cSOmar Sandoval int ret; 5397c55ee0cSOmar Sandoval 540781e3bcfSOmar Sandoval ret = run_test(test_func, 0, sectorsize, nodesize, alignment); 541781e3bcfSOmar Sandoval if (ret) { 5423c7251f2SDavid Sterba test_err( 543d75f773cSSakari Ailus "%ps failed with extents, sectorsize=%u, nodesize=%u, alignment=%u", 544781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 545781e3bcfSOmar Sandoval test_ret = ret; 546781e3bcfSOmar Sandoval } 547781e3bcfSOmar Sandoval 548781e3bcfSOmar Sandoval ret = run_test(test_func, 1, sectorsize, nodesize, alignment); 549781e3bcfSOmar Sandoval if (ret) { 5503c7251f2SDavid Sterba test_err( 551d75f773cSSakari Ailus "%ps failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u", 552781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 553781e3bcfSOmar Sandoval test_ret = ret; 554781e3bcfSOmar Sandoval } 555781e3bcfSOmar Sandoval 556781e3bcfSOmar Sandoval return test_ret; 5577c55ee0cSOmar Sandoval } 5587c55ee0cSOmar Sandoval 559b9ef22deSFeifei Xu int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) 5607c55ee0cSOmar Sandoval { 5617c55ee0cSOmar Sandoval test_func_t tests[] = { 5627c55ee0cSOmar Sandoval test_empty_block_group, 5637c55ee0cSOmar Sandoval test_remove_all, 5647c55ee0cSOmar Sandoval test_remove_beginning, 5657c55ee0cSOmar Sandoval test_remove_end, 5667c55ee0cSOmar Sandoval test_remove_middle, 5677c55ee0cSOmar Sandoval test_merge_left, 5687c55ee0cSOmar Sandoval test_merge_right, 5697c55ee0cSOmar Sandoval test_merge_both, 5707c55ee0cSOmar Sandoval test_merge_none, 5717c55ee0cSOmar Sandoval }; 572781e3bcfSOmar Sandoval u32 bitmap_alignment; 573781e3bcfSOmar Sandoval int test_ret = 0; 5747c55ee0cSOmar Sandoval int i; 5757c55ee0cSOmar Sandoval 576781e3bcfSOmar Sandoval /* 577781e3bcfSOmar Sandoval * Align some operations to a page to flush out bugs in the extent 578781e3bcfSOmar Sandoval * buffer bitmap handling of highmem. 579781e3bcfSOmar Sandoval */ 580781e3bcfSOmar Sandoval bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; 581781e3bcfSOmar Sandoval 582315b76b4SDavid Sterba test_msg("running free space tree tests"); 5837c55ee0cSOmar Sandoval for (i = 0; i < ARRAY_SIZE(tests); i++) { 584781e3bcfSOmar Sandoval int ret; 585781e3bcfSOmar Sandoval 586781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 587781e3bcfSOmar Sandoval sectorsize); 588781e3bcfSOmar Sandoval if (ret) 589781e3bcfSOmar Sandoval test_ret = ret; 590781e3bcfSOmar Sandoval 591781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 592781e3bcfSOmar Sandoval bitmap_alignment); 593781e3bcfSOmar Sandoval if (ret) 594781e3bcfSOmar Sandoval test_ret = ret; 5957c55ee0cSOmar Sandoval } 5967c55ee0cSOmar Sandoval 597781e3bcfSOmar Sandoval return test_ret; 5987c55ee0cSOmar Sandoval } 599