18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Facebook. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include "btrfs-tests.h" 88c2ecf20Sopenharmony_ci#include "../ctree.h" 98c2ecf20Sopenharmony_ci#include "../disk-io.h" 108c2ecf20Sopenharmony_ci#include "../free-space-tree.h" 118c2ecf20Sopenharmony_ci#include "../transaction.h" 128c2ecf20Sopenharmony_ci#include "../block-group.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistruct free_space_extent { 158c2ecf20Sopenharmony_ci u64 start; 168c2ecf20Sopenharmony_ci u64 length; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int __check_free_space_extents(struct btrfs_trans_handle *trans, 208c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 218c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 228c2ecf20Sopenharmony_ci struct btrfs_path *path, 238c2ecf20Sopenharmony_ci const struct free_space_extent * const extents, 248c2ecf20Sopenharmony_ci unsigned int num_extents) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct btrfs_free_space_info *info; 278c2ecf20Sopenharmony_ci struct btrfs_key key; 288c2ecf20Sopenharmony_ci int prev_bit = 0, bit; 298c2ecf20Sopenharmony_ci u64 extent_start = 0, offset, end; 308c2ecf20Sopenharmony_ci u32 flags, extent_count; 318c2ecf20Sopenharmony_ci unsigned int i; 328c2ecf20Sopenharmony_ci int ret; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci info = search_free_space_info(trans, cache, path, 0); 358c2ecf20Sopenharmony_ci if (IS_ERR(info)) { 368c2ecf20Sopenharmony_ci test_err("could not find free space info"); 378c2ecf20Sopenharmony_ci ret = PTR_ERR(info); 388c2ecf20Sopenharmony_ci goto out; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci flags = btrfs_free_space_flags(path->nodes[0], info); 418c2ecf20Sopenharmony_ci extent_count = btrfs_free_space_extent_count(path->nodes[0], info); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (extent_count != num_extents) { 448c2ecf20Sopenharmony_ci test_err("extent count is wrong"); 458c2ecf20Sopenharmony_ci ret = -EINVAL; 468c2ecf20Sopenharmony_ci goto out; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 498c2ecf20Sopenharmony_ci if (path->slots[0] != 0) 508c2ecf20Sopenharmony_ci goto invalid; 518c2ecf20Sopenharmony_ci end = cache->start + cache->length; 528c2ecf20Sopenharmony_ci i = 0; 538c2ecf20Sopenharmony_ci while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) { 548c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 558c2ecf20Sopenharmony_ci if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY) 568c2ecf20Sopenharmony_ci goto invalid; 578c2ecf20Sopenharmony_ci offset = key.objectid; 588c2ecf20Sopenharmony_ci while (offset < key.objectid + key.offset) { 598c2ecf20Sopenharmony_ci bit = free_space_test_bit(cache, path, offset); 608c2ecf20Sopenharmony_ci if (prev_bit == 0 && bit == 1) { 618c2ecf20Sopenharmony_ci extent_start = offset; 628c2ecf20Sopenharmony_ci } else if (prev_bit == 1 && bit == 0) { 638c2ecf20Sopenharmony_ci if (i >= num_extents || 648c2ecf20Sopenharmony_ci extent_start != extents[i].start || 658c2ecf20Sopenharmony_ci offset - extent_start != extents[i].length) 668c2ecf20Sopenharmony_ci goto invalid; 678c2ecf20Sopenharmony_ci i++; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci prev_bit = bit; 708c2ecf20Sopenharmony_ci offset += fs_info->sectorsize; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci if (prev_bit == 1) { 748c2ecf20Sopenharmony_ci if (i >= num_extents || 758c2ecf20Sopenharmony_ci extent_start != extents[i].start || 768c2ecf20Sopenharmony_ci end - extent_start != extents[i].length) 778c2ecf20Sopenharmony_ci goto invalid; 788c2ecf20Sopenharmony_ci i++; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci if (i != num_extents) 818c2ecf20Sopenharmony_ci goto invalid; 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 || 848c2ecf20Sopenharmony_ci path->slots[0] != 0) 858c2ecf20Sopenharmony_ci goto invalid; 868c2ecf20Sopenharmony_ci for (i = 0; i < num_extents; i++) { 878c2ecf20Sopenharmony_ci path->slots[0]++; 888c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 898c2ecf20Sopenharmony_ci if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY || 908c2ecf20Sopenharmony_ci key.objectid != extents[i].start || 918c2ecf20Sopenharmony_ci key.offset != extents[i].length) 928c2ecf20Sopenharmony_ci goto invalid; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = 0; 978c2ecf20Sopenharmony_ciout: 988c2ecf20Sopenharmony_ci btrfs_release_path(path); 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ciinvalid: 1018c2ecf20Sopenharmony_ci test_err("free space tree is invalid"); 1028c2ecf20Sopenharmony_ci ret = -EINVAL; 1038c2ecf20Sopenharmony_ci goto out; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int check_free_space_extents(struct btrfs_trans_handle *trans, 1078c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 1088c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 1098c2ecf20Sopenharmony_ci struct btrfs_path *path, 1108c2ecf20Sopenharmony_ci const struct free_space_extent * const extents, 1118c2ecf20Sopenharmony_ci unsigned int num_extents) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct btrfs_free_space_info *info; 1148c2ecf20Sopenharmony_ci u32 flags; 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci info = search_free_space_info(trans, cache, path, 0); 1188c2ecf20Sopenharmony_ci if (IS_ERR(info)) { 1198c2ecf20Sopenharmony_ci test_err("could not find free space info"); 1208c2ecf20Sopenharmony_ci btrfs_release_path(path); 1218c2ecf20Sopenharmony_ci return PTR_ERR(info); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci flags = btrfs_free_space_flags(path->nodes[0], info); 1248c2ecf20Sopenharmony_ci btrfs_release_path(path); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = __check_free_space_extents(trans, fs_info, cache, path, extents, 1278c2ecf20Sopenharmony_ci num_extents); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Flip it to the other format and check that for good measure. */ 1328c2ecf20Sopenharmony_ci if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 1338c2ecf20Sopenharmony_ci ret = convert_free_space_to_extents(trans, cache, path); 1348c2ecf20Sopenharmony_ci if (ret) { 1358c2ecf20Sopenharmony_ci test_err("could not convert to extents"); 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } else { 1398c2ecf20Sopenharmony_ci ret = convert_free_space_to_bitmaps(trans, cache, path); 1408c2ecf20Sopenharmony_ci if (ret) { 1418c2ecf20Sopenharmony_ci test_err("could not convert to bitmaps"); 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci return __check_free_space_extents(trans, fs_info, cache, path, extents, 1468c2ecf20Sopenharmony_ci num_extents); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int test_empty_block_group(struct btrfs_trans_handle *trans, 1508c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 1518c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 1528c2ecf20Sopenharmony_ci struct btrfs_path *path, 1538c2ecf20Sopenharmony_ci u32 alignment) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 1568c2ecf20Sopenharmony_ci {cache->start, cache->length}, 1578c2ecf20Sopenharmony_ci }; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 1608c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int test_remove_all(struct btrfs_trans_handle *trans, 1648c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 1658c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 1668c2ecf20Sopenharmony_ci struct btrfs_path *path, 1678c2ecf20Sopenharmony_ci u32 alignment) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = {}; 1708c2ecf20Sopenharmony_ci int ret; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 1738c2ecf20Sopenharmony_ci cache->start, 1748c2ecf20Sopenharmony_ci cache->length); 1758c2ecf20Sopenharmony_ci if (ret) { 1768c2ecf20Sopenharmony_ci test_err("could not remove free space"); 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 1818c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int test_remove_beginning(struct btrfs_trans_handle *trans, 1858c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 1868c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 1878c2ecf20Sopenharmony_ci struct btrfs_path *path, 1888c2ecf20Sopenharmony_ci u32 alignment) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 1918c2ecf20Sopenharmony_ci {cache->start + alignment, cache->length - alignment}, 1928c2ecf20Sopenharmony_ci }; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 1968c2ecf20Sopenharmony_ci cache->start, alignment); 1978c2ecf20Sopenharmony_ci if (ret) { 1988c2ecf20Sopenharmony_ci test_err("could not remove free space"); 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 2038c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int test_remove_end(struct btrfs_trans_handle *trans, 2088c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 2098c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 2108c2ecf20Sopenharmony_ci struct btrfs_path *path, 2118c2ecf20Sopenharmony_ci u32 alignment) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 2148c2ecf20Sopenharmony_ci {cache->start, cache->length - alignment}, 2158c2ecf20Sopenharmony_ci }; 2168c2ecf20Sopenharmony_ci int ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 2198c2ecf20Sopenharmony_ci cache->start + cache->length - alignment, 2208c2ecf20Sopenharmony_ci alignment); 2218c2ecf20Sopenharmony_ci if (ret) { 2228c2ecf20Sopenharmony_ci test_err("could not remove free space"); 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 2278c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int test_remove_middle(struct btrfs_trans_handle *trans, 2318c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 2328c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 2338c2ecf20Sopenharmony_ci struct btrfs_path *path, 2348c2ecf20Sopenharmony_ci u32 alignment) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 2378c2ecf20Sopenharmony_ci {cache->start, alignment}, 2388c2ecf20Sopenharmony_ci {cache->start + 2 * alignment, cache->length - 2 * alignment}, 2398c2ecf20Sopenharmony_ci }; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 2438c2ecf20Sopenharmony_ci cache->start + alignment, 2448c2ecf20Sopenharmony_ci alignment); 2458c2ecf20Sopenharmony_ci if (ret) { 2468c2ecf20Sopenharmony_ci test_err("could not remove free space"); 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 2518c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int test_merge_left(struct btrfs_trans_handle *trans, 2558c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 2568c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 2578c2ecf20Sopenharmony_ci struct btrfs_path *path, 2588c2ecf20Sopenharmony_ci u32 alignment) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 2618c2ecf20Sopenharmony_ci {cache->start, 2 * alignment}, 2628c2ecf20Sopenharmony_ci }; 2638c2ecf20Sopenharmony_ci int ret; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 2668c2ecf20Sopenharmony_ci cache->start, cache->length); 2678c2ecf20Sopenharmony_ci if (ret) { 2688c2ecf20Sopenharmony_ci test_err("could not remove free space"); 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, cache->start, 2738c2ecf20Sopenharmony_ci alignment); 2748c2ecf20Sopenharmony_ci if (ret) { 2758c2ecf20Sopenharmony_ci test_err("could not add free space"); 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 2808c2ecf20Sopenharmony_ci cache->start + alignment, 2818c2ecf20Sopenharmony_ci alignment); 2828c2ecf20Sopenharmony_ci if (ret) { 2838c2ecf20Sopenharmony_ci test_err("could not add free space"); 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 2888c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int test_merge_right(struct btrfs_trans_handle *trans, 2928c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 2938c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 2948c2ecf20Sopenharmony_ci struct btrfs_path *path, 2958c2ecf20Sopenharmony_ci u32 alignment) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 2988c2ecf20Sopenharmony_ci {cache->start + alignment, 2 * alignment}, 2998c2ecf20Sopenharmony_ci }; 3008c2ecf20Sopenharmony_ci int ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 3038c2ecf20Sopenharmony_ci cache->start, cache->length); 3048c2ecf20Sopenharmony_ci if (ret) { 3058c2ecf20Sopenharmony_ci test_err("could not remove free space"); 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 3108c2ecf20Sopenharmony_ci cache->start + 2 * alignment, 3118c2ecf20Sopenharmony_ci alignment); 3128c2ecf20Sopenharmony_ci if (ret) { 3138c2ecf20Sopenharmony_ci test_err("could not add free space"); 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 3188c2ecf20Sopenharmony_ci cache->start + alignment, 3198c2ecf20Sopenharmony_ci alignment); 3208c2ecf20Sopenharmony_ci if (ret) { 3218c2ecf20Sopenharmony_ci test_err("could not add free space"); 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 3268c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int test_merge_both(struct btrfs_trans_handle *trans, 3308c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 3318c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 3328c2ecf20Sopenharmony_ci struct btrfs_path *path, 3338c2ecf20Sopenharmony_ci u32 alignment) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 3368c2ecf20Sopenharmony_ci {cache->start, 3 * alignment}, 3378c2ecf20Sopenharmony_ci }; 3388c2ecf20Sopenharmony_ci int ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 3418c2ecf20Sopenharmony_ci cache->start, cache->length); 3428c2ecf20Sopenharmony_ci if (ret) { 3438c2ecf20Sopenharmony_ci test_err("could not remove free space"); 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, cache->start, 3488c2ecf20Sopenharmony_ci alignment); 3498c2ecf20Sopenharmony_ci if (ret) { 3508c2ecf20Sopenharmony_ci test_err("could not add free space"); 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 3558c2ecf20Sopenharmony_ci cache->start + 2 * alignment, alignment); 3568c2ecf20Sopenharmony_ci if (ret) { 3578c2ecf20Sopenharmony_ci test_err("could not add free space"); 3588c2ecf20Sopenharmony_ci return ret; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 3628c2ecf20Sopenharmony_ci cache->start + alignment, alignment); 3638c2ecf20Sopenharmony_ci if (ret) { 3648c2ecf20Sopenharmony_ci test_err("could not add free space"); 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 3698c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int test_merge_none(struct btrfs_trans_handle *trans, 3738c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info, 3748c2ecf20Sopenharmony_ci struct btrfs_block_group *cache, 3758c2ecf20Sopenharmony_ci struct btrfs_path *path, 3768c2ecf20Sopenharmony_ci u32 alignment) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci const struct free_space_extent extents[] = { 3798c2ecf20Sopenharmony_ci {cache->start, alignment}, 3808c2ecf20Sopenharmony_ci {cache->start + 2 * alignment, alignment}, 3818c2ecf20Sopenharmony_ci {cache->start + 4 * alignment, alignment}, 3828c2ecf20Sopenharmony_ci }; 3838c2ecf20Sopenharmony_ci int ret; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ret = __remove_from_free_space_tree(trans, cache, path, 3868c2ecf20Sopenharmony_ci cache->start, cache->length); 3878c2ecf20Sopenharmony_ci if (ret) { 3888c2ecf20Sopenharmony_ci test_err("could not remove free space"); 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, cache->start, 3938c2ecf20Sopenharmony_ci alignment); 3948c2ecf20Sopenharmony_ci if (ret) { 3958c2ecf20Sopenharmony_ci test_err("could not add free space"); 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 4008c2ecf20Sopenharmony_ci cache->start + 4 * alignment, alignment); 4018c2ecf20Sopenharmony_ci if (ret) { 4028c2ecf20Sopenharmony_ci test_err("could not add free space"); 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci ret = __add_to_free_space_tree(trans, cache, path, 4078c2ecf20Sopenharmony_ci cache->start + 2 * alignment, alignment); 4088c2ecf20Sopenharmony_ci if (ret) { 4098c2ecf20Sopenharmony_ci test_err("could not add free space"); 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return check_free_space_extents(trans, fs_info, cache, path, 4148c2ecf20Sopenharmony_ci extents, ARRAY_SIZE(extents)); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_citypedef int (*test_func_t)(struct btrfs_trans_handle *, 4188c2ecf20Sopenharmony_ci struct btrfs_fs_info *, 4198c2ecf20Sopenharmony_ci struct btrfs_block_group *, 4208c2ecf20Sopenharmony_ci struct btrfs_path *, 4218c2ecf20Sopenharmony_ci u32 alignment); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, 4248c2ecf20Sopenharmony_ci u32 nodesize, u32 alignment) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info; 4278c2ecf20Sopenharmony_ci struct btrfs_root *root = NULL; 4288c2ecf20Sopenharmony_ci struct btrfs_block_group *cache = NULL; 4298c2ecf20Sopenharmony_ci struct btrfs_trans_handle trans; 4308c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 4348c2ecf20Sopenharmony_ci if (!fs_info) { 4358c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_FS_INFO); 4368c2ecf20Sopenharmony_ci ret = -ENOMEM; 4378c2ecf20Sopenharmony_ci goto out; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci root = btrfs_alloc_dummy_root(fs_info); 4418c2ecf20Sopenharmony_ci if (IS_ERR(root)) { 4428c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 4438c2ecf20Sopenharmony_ci ret = PTR_ERR(root); 4448c2ecf20Sopenharmony_ci goto out; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, 4488c2ecf20Sopenharmony_ci BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); 4498c2ecf20Sopenharmony_ci root->fs_info->free_space_root = root; 4508c2ecf20Sopenharmony_ci root->fs_info->tree_root = root; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci root->node = alloc_test_extent_buffer(root->fs_info, nodesize); 4538c2ecf20Sopenharmony_ci if (IS_ERR(root->node)) { 4548c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_BUFFER); 4558c2ecf20Sopenharmony_ci ret = PTR_ERR(root->node); 4568c2ecf20Sopenharmony_ci goto out; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci btrfs_set_header_level(root->node, 0); 4598c2ecf20Sopenharmony_ci btrfs_set_header_nritems(root->node, 0); 4608c2ecf20Sopenharmony_ci root->alloc_bytenr += 2 * nodesize; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci cache = btrfs_alloc_dummy_block_group(fs_info, 8 * alignment); 4638c2ecf20Sopenharmony_ci if (!cache) { 4648c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_BLOCK_GROUP); 4658c2ecf20Sopenharmony_ci ret = -ENOMEM; 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci cache->bitmap_low_thresh = 0; 4698c2ecf20Sopenharmony_ci cache->bitmap_high_thresh = (u32)-1; 4708c2ecf20Sopenharmony_ci cache->needs_free_space = 1; 4718c2ecf20Sopenharmony_ci cache->fs_info = root->fs_info; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci btrfs_init_dummy_trans(&trans, root->fs_info); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 4768c2ecf20Sopenharmony_ci if (!path) { 4778c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 4788c2ecf20Sopenharmony_ci ret = -ENOMEM; 4798c2ecf20Sopenharmony_ci goto out; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ret = add_block_group_free_space(&trans, cache); 4838c2ecf20Sopenharmony_ci if (ret) { 4848c2ecf20Sopenharmony_ci test_err("could not add block group free space"); 4858c2ecf20Sopenharmony_ci goto out; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (bitmaps) { 4898c2ecf20Sopenharmony_ci ret = convert_free_space_to_bitmaps(&trans, cache, path); 4908c2ecf20Sopenharmony_ci if (ret) { 4918c2ecf20Sopenharmony_ci test_err("could not convert block group to bitmaps"); 4928c2ecf20Sopenharmony_ci goto out; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = test_func(&trans, root->fs_info, cache, path, alignment); 4978c2ecf20Sopenharmony_ci if (ret) 4988c2ecf20Sopenharmony_ci goto out; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci ret = remove_block_group_free_space(&trans, cache); 5018c2ecf20Sopenharmony_ci if (ret) { 5028c2ecf20Sopenharmony_ci test_err("could not remove block group free space"); 5038c2ecf20Sopenharmony_ci goto out; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (btrfs_header_nritems(root->node) != 0) { 5078c2ecf20Sopenharmony_ci test_err("free space tree has leftover items"); 5088c2ecf20Sopenharmony_ci ret = -EINVAL; 5098c2ecf20Sopenharmony_ci goto out; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ret = 0; 5138c2ecf20Sopenharmony_ciout: 5148c2ecf20Sopenharmony_ci btrfs_free_path(path); 5158c2ecf20Sopenharmony_ci btrfs_free_dummy_block_group(cache); 5168c2ecf20Sopenharmony_ci btrfs_free_dummy_root(root); 5178c2ecf20Sopenharmony_ci btrfs_free_dummy_fs_info(fs_info); 5188c2ecf20Sopenharmony_ci return ret; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int run_test_both_formats(test_func_t test_func, u32 sectorsize, 5228c2ecf20Sopenharmony_ci u32 nodesize, u32 alignment) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci int test_ret = 0; 5258c2ecf20Sopenharmony_ci int ret; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci ret = run_test(test_func, 0, sectorsize, nodesize, alignment); 5288c2ecf20Sopenharmony_ci if (ret) { 5298c2ecf20Sopenharmony_ci test_err( 5308c2ecf20Sopenharmony_ci "%ps failed with extents, sectorsize=%u, nodesize=%u, alignment=%u", 5318c2ecf20Sopenharmony_ci test_func, sectorsize, nodesize, alignment); 5328c2ecf20Sopenharmony_ci test_ret = ret; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ret = run_test(test_func, 1, sectorsize, nodesize, alignment); 5368c2ecf20Sopenharmony_ci if (ret) { 5378c2ecf20Sopenharmony_ci test_err( 5388c2ecf20Sopenharmony_ci "%ps failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u", 5398c2ecf20Sopenharmony_ci test_func, sectorsize, nodesize, alignment); 5408c2ecf20Sopenharmony_ci test_ret = ret; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return test_ret; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ciint btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci test_func_t tests[] = { 5498c2ecf20Sopenharmony_ci test_empty_block_group, 5508c2ecf20Sopenharmony_ci test_remove_all, 5518c2ecf20Sopenharmony_ci test_remove_beginning, 5528c2ecf20Sopenharmony_ci test_remove_end, 5538c2ecf20Sopenharmony_ci test_remove_middle, 5548c2ecf20Sopenharmony_ci test_merge_left, 5558c2ecf20Sopenharmony_ci test_merge_right, 5568c2ecf20Sopenharmony_ci test_merge_both, 5578c2ecf20Sopenharmony_ci test_merge_none, 5588c2ecf20Sopenharmony_ci }; 5598c2ecf20Sopenharmony_ci u32 bitmap_alignment; 5608c2ecf20Sopenharmony_ci int test_ret = 0; 5618c2ecf20Sopenharmony_ci int i; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * Align some operations to a page to flush out bugs in the extent 5658c2ecf20Sopenharmony_ci * buffer bitmap handling of highmem. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci test_msg("running free space tree tests"); 5708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tests); i++) { 5718c2ecf20Sopenharmony_ci int ret; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci ret = run_test_both_formats(tests[i], sectorsize, nodesize, 5748c2ecf20Sopenharmony_ci sectorsize); 5758c2ecf20Sopenharmony_ci if (ret) 5768c2ecf20Sopenharmony_ci test_ret = ret; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci ret = run_test_both_formats(tests[i], sectorsize, nodesize, 5798c2ecf20Sopenharmony_ci bitmap_alignment); 5808c2ecf20Sopenharmony_ci if (ret) 5818c2ecf20Sopenharmony_ci test_ret = ret; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return test_ret; 5858c2ecf20Sopenharmony_ci} 586