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" 12aac0023cSJosef 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, 2132da5386SDavid Sterba struct btrfs_block_group *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; 51b3470b5dSDavid Sterba end = cache->start + cache->length; 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 extent_start != extents[i].start || 657c55ee0cSOmar Sandoval offset - extent_start != extents[i].length) 667c55ee0cSOmar Sandoval goto invalid; 677c55ee0cSOmar Sandoval i++; 687c55ee0cSOmar Sandoval } 697c55ee0cSOmar Sandoval prev_bit = bit; 7023d1f737SNikolay Borisov offset += fs_info->sectorsize; 717c55ee0cSOmar Sandoval } 727c55ee0cSOmar Sandoval } 737c55ee0cSOmar Sandoval if (prev_bit == 1) { 747c55ee0cSOmar Sandoval if (i >= num_extents || 757c55ee0cSOmar Sandoval extent_start != extents[i].start || 767c55ee0cSOmar Sandoval end - extent_start != extents[i].length) 777c55ee0cSOmar Sandoval goto invalid; 787c55ee0cSOmar Sandoval i++; 797c55ee0cSOmar Sandoval } 807c55ee0cSOmar Sandoval if (i != num_extents) 817c55ee0cSOmar Sandoval goto invalid; 827c55ee0cSOmar Sandoval } else { 837c55ee0cSOmar Sandoval if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 || 847c55ee0cSOmar Sandoval path->slots[0] != 0) 857c55ee0cSOmar Sandoval goto invalid; 867c55ee0cSOmar Sandoval for (i = 0; i < num_extents; i++) { 877c55ee0cSOmar Sandoval path->slots[0]++; 887c55ee0cSOmar Sandoval btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 897c55ee0cSOmar Sandoval if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY || 907c55ee0cSOmar Sandoval key.objectid != extents[i].start || 917c55ee0cSOmar Sandoval key.offset != extents[i].length) 927c55ee0cSOmar Sandoval goto invalid; 937c55ee0cSOmar Sandoval } 947c55ee0cSOmar Sandoval } 957c55ee0cSOmar Sandoval 967c55ee0cSOmar Sandoval ret = 0; 977c55ee0cSOmar Sandoval out: 987c55ee0cSOmar Sandoval btrfs_release_path(path); 997c55ee0cSOmar Sandoval return ret; 1007c55ee0cSOmar Sandoval invalid: 1013c7251f2SDavid Sterba test_err("free space tree is invalid"); 1027c55ee0cSOmar Sandoval ret = -EINVAL; 1037c55ee0cSOmar Sandoval goto out; 1047c55ee0cSOmar Sandoval } 1057c55ee0cSOmar Sandoval 1067c55ee0cSOmar Sandoval static int check_free_space_extents(struct btrfs_trans_handle *trans, 1077c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 10832da5386SDavid Sterba struct btrfs_block_group *cache, 1097c55ee0cSOmar Sandoval struct btrfs_path *path, 110d2d9ac6aSDavid Sterba const struct free_space_extent * const extents, 1117c55ee0cSOmar Sandoval unsigned int num_extents) 1127c55ee0cSOmar Sandoval { 1137c55ee0cSOmar Sandoval struct btrfs_free_space_info *info; 1147c55ee0cSOmar Sandoval u32 flags; 1157c55ee0cSOmar Sandoval int ret; 1167c55ee0cSOmar Sandoval 1172ccf545eSDavid Sterba info = search_free_space_info(trans, cache, path, 0); 1187c55ee0cSOmar Sandoval if (IS_ERR(info)) { 1193c7251f2SDavid Sterba test_err("could not find free space info"); 1207c55ee0cSOmar Sandoval btrfs_release_path(path); 1217c55ee0cSOmar Sandoval return PTR_ERR(info); 1227c55ee0cSOmar Sandoval } 1237c55ee0cSOmar Sandoval flags = btrfs_free_space_flags(path->nodes[0], info); 1247c55ee0cSOmar Sandoval btrfs_release_path(path); 1257c55ee0cSOmar Sandoval 1267c55ee0cSOmar Sandoval ret = __check_free_space_extents(trans, fs_info, cache, path, extents, 1277c55ee0cSOmar Sandoval num_extents); 1287c55ee0cSOmar Sandoval if (ret) 1297c55ee0cSOmar Sandoval return ret; 1307c55ee0cSOmar Sandoval 1317c55ee0cSOmar Sandoval /* Flip it to the other format and check that for good measure. */ 1327c55ee0cSOmar Sandoval if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 1335296c2bfSNikolay Borisov ret = convert_free_space_to_extents(trans, cache, path); 1347c55ee0cSOmar Sandoval if (ret) { 1353c7251f2SDavid Sterba test_err("could not convert to extents"); 1367c55ee0cSOmar Sandoval return ret; 1377c55ee0cSOmar Sandoval } 1387c55ee0cSOmar Sandoval } else { 139719fb4deSNikolay Borisov ret = convert_free_space_to_bitmaps(trans, cache, path); 1407c55ee0cSOmar Sandoval if (ret) { 1413c7251f2SDavid Sterba test_err("could not convert to bitmaps"); 1427c55ee0cSOmar Sandoval return ret; 1437c55ee0cSOmar Sandoval } 1447c55ee0cSOmar Sandoval } 1457c55ee0cSOmar Sandoval return __check_free_space_extents(trans, fs_info, cache, path, extents, 1467c55ee0cSOmar Sandoval num_extents); 1477c55ee0cSOmar Sandoval } 1487c55ee0cSOmar Sandoval 1497c55ee0cSOmar Sandoval static int test_empty_block_group(struct btrfs_trans_handle *trans, 1507c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 15132da5386SDavid Sterba struct btrfs_block_group *cache, 152781e3bcfSOmar Sandoval struct btrfs_path *path, 153781e3bcfSOmar Sandoval u32 alignment) 1547c55ee0cSOmar Sandoval { 155d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 156b3470b5dSDavid Sterba {cache->start, cache->length}, 1577c55ee0cSOmar Sandoval }; 1587c55ee0cSOmar Sandoval 1597c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1607c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1617c55ee0cSOmar Sandoval } 1627c55ee0cSOmar Sandoval 1637c55ee0cSOmar Sandoval static int test_remove_all(struct btrfs_trans_handle *trans, 1647c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 16532da5386SDavid Sterba struct btrfs_block_group *cache, 166781e3bcfSOmar Sandoval struct btrfs_path *path, 167781e3bcfSOmar Sandoval u32 alignment) 1687c55ee0cSOmar Sandoval { 169d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = {}; 1707c55ee0cSOmar Sandoval int ret; 1717c55ee0cSOmar Sandoval 172c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 173b3470b5dSDavid Sterba cache->start, 174b3470b5dSDavid Sterba cache->length); 1757c55ee0cSOmar Sandoval if (ret) { 1763c7251f2SDavid Sterba test_err("could not remove free space"); 1777c55ee0cSOmar Sandoval return ret; 1787c55ee0cSOmar Sandoval } 1797c55ee0cSOmar Sandoval 1807c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1817c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1827c55ee0cSOmar Sandoval } 1837c55ee0cSOmar Sandoval 1847c55ee0cSOmar Sandoval static int test_remove_beginning(struct btrfs_trans_handle *trans, 1857c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 18632da5386SDavid Sterba struct btrfs_block_group *cache, 187781e3bcfSOmar Sandoval struct btrfs_path *path, 188781e3bcfSOmar Sandoval u32 alignment) 1897c55ee0cSOmar Sandoval { 190d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 191b3470b5dSDavid Sterba {cache->start + alignment, cache->length - alignment}, 1927c55ee0cSOmar Sandoval }; 1937c55ee0cSOmar Sandoval int ret; 1947c55ee0cSOmar Sandoval 195c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 196b3470b5dSDavid Sterba cache->start, alignment); 1977c55ee0cSOmar Sandoval if (ret) { 1983c7251f2SDavid Sterba test_err("could not remove free space"); 1997c55ee0cSOmar Sandoval return ret; 2007c55ee0cSOmar Sandoval } 2017c55ee0cSOmar Sandoval 2027c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2037c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2047c55ee0cSOmar Sandoval 2057c55ee0cSOmar Sandoval } 2067c55ee0cSOmar Sandoval 2077c55ee0cSOmar Sandoval static int test_remove_end(struct btrfs_trans_handle *trans, 2087c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 20932da5386SDavid Sterba struct btrfs_block_group *cache, 210781e3bcfSOmar Sandoval struct btrfs_path *path, 211781e3bcfSOmar Sandoval u32 alignment) 2127c55ee0cSOmar Sandoval { 213d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 214b3470b5dSDavid Sterba {cache->start, cache->length - alignment}, 2157c55ee0cSOmar Sandoval }; 2167c55ee0cSOmar Sandoval int ret; 2177c55ee0cSOmar Sandoval 218c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 219b3470b5dSDavid Sterba cache->start + cache->length - alignment, 220781e3bcfSOmar Sandoval alignment); 2217c55ee0cSOmar Sandoval if (ret) { 2223c7251f2SDavid Sterba test_err("could not remove free space"); 2237c55ee0cSOmar Sandoval return ret; 2247c55ee0cSOmar Sandoval } 2257c55ee0cSOmar Sandoval 2267c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2277c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2287c55ee0cSOmar Sandoval } 2297c55ee0cSOmar Sandoval 2307c55ee0cSOmar Sandoval static int test_remove_middle(struct btrfs_trans_handle *trans, 2317c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 23232da5386SDavid Sterba struct btrfs_block_group *cache, 233781e3bcfSOmar Sandoval struct btrfs_path *path, 234781e3bcfSOmar Sandoval u32 alignment) 2357c55ee0cSOmar Sandoval { 236d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 237b3470b5dSDavid Sterba {cache->start, alignment}, 238b3470b5dSDavid Sterba {cache->start + 2 * alignment, cache->length - 2 * alignment}, 2397c55ee0cSOmar Sandoval }; 2407c55ee0cSOmar Sandoval int ret; 2417c55ee0cSOmar Sandoval 242c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 243b3470b5dSDavid Sterba cache->start + alignment, 244781e3bcfSOmar Sandoval alignment); 2457c55ee0cSOmar Sandoval if (ret) { 2463c7251f2SDavid Sterba test_err("could not remove free space"); 2477c55ee0cSOmar Sandoval return ret; 2487c55ee0cSOmar Sandoval } 2497c55ee0cSOmar Sandoval 2507c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2517c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2527c55ee0cSOmar Sandoval } 2537c55ee0cSOmar Sandoval 2547c55ee0cSOmar Sandoval static int test_merge_left(struct btrfs_trans_handle *trans, 2557c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 25632da5386SDavid Sterba struct btrfs_block_group *cache, 257781e3bcfSOmar Sandoval struct btrfs_path *path, 258781e3bcfSOmar Sandoval u32 alignment) 2597c55ee0cSOmar Sandoval { 260d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 261b3470b5dSDavid Sterba {cache->start, 2 * alignment}, 2627c55ee0cSOmar Sandoval }; 2637c55ee0cSOmar Sandoval int ret; 2647c55ee0cSOmar Sandoval 265c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 266b3470b5dSDavid Sterba cache->start, cache->length); 2677c55ee0cSOmar Sandoval if (ret) { 2683c7251f2SDavid Sterba test_err("could not remove free space"); 2697c55ee0cSOmar Sandoval return ret; 2707c55ee0cSOmar Sandoval } 2717c55ee0cSOmar Sandoval 272b3470b5dSDavid Sterba ret = __add_to_free_space_tree(trans, cache, path, cache->start, 2732d5cffa1SNikolay Borisov alignment); 2747c55ee0cSOmar Sandoval if (ret) { 2753c7251f2SDavid Sterba test_err("could not add free space"); 2767c55ee0cSOmar Sandoval return ret; 2777c55ee0cSOmar Sandoval } 2787c55ee0cSOmar Sandoval 2792d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 280b3470b5dSDavid Sterba cache->start + alignment, 281781e3bcfSOmar Sandoval alignment); 2827c55ee0cSOmar Sandoval if (ret) { 2833c7251f2SDavid Sterba test_err("could not add free space"); 2847c55ee0cSOmar Sandoval return ret; 2857c55ee0cSOmar Sandoval } 2867c55ee0cSOmar Sandoval 2877c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2887c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2897c55ee0cSOmar Sandoval } 2907c55ee0cSOmar Sandoval 2917c55ee0cSOmar Sandoval static int test_merge_right(struct btrfs_trans_handle *trans, 2927c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 29332da5386SDavid Sterba struct btrfs_block_group *cache, 294781e3bcfSOmar Sandoval struct btrfs_path *path, 295781e3bcfSOmar Sandoval u32 alignment) 2967c55ee0cSOmar Sandoval { 297d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 298b3470b5dSDavid Sterba {cache->start + alignment, 2 * alignment}, 2997c55ee0cSOmar Sandoval }; 3007c55ee0cSOmar Sandoval int ret; 3017c55ee0cSOmar Sandoval 302c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 303b3470b5dSDavid Sterba cache->start, cache->length); 3047c55ee0cSOmar Sandoval if (ret) { 3053c7251f2SDavid Sterba test_err("could not remove free space"); 3067c55ee0cSOmar Sandoval return ret; 3077c55ee0cSOmar Sandoval } 3087c55ee0cSOmar Sandoval 3092d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 310b3470b5dSDavid Sterba cache->start + 2 * alignment, 311781e3bcfSOmar Sandoval alignment); 3127c55ee0cSOmar Sandoval if (ret) { 3133c7251f2SDavid Sterba test_err("could not add free space"); 3147c55ee0cSOmar Sandoval return ret; 3157c55ee0cSOmar Sandoval } 3167c55ee0cSOmar Sandoval 3172d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 318b3470b5dSDavid Sterba cache->start + alignment, 319781e3bcfSOmar Sandoval alignment); 3207c55ee0cSOmar Sandoval if (ret) { 3213c7251f2SDavid Sterba test_err("could not add free space"); 3227c55ee0cSOmar Sandoval return ret; 3237c55ee0cSOmar Sandoval } 3247c55ee0cSOmar Sandoval 3257c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3267c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3277c55ee0cSOmar Sandoval } 3287c55ee0cSOmar Sandoval 3297c55ee0cSOmar Sandoval static int test_merge_both(struct btrfs_trans_handle *trans, 3307c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 33132da5386SDavid Sterba struct btrfs_block_group *cache, 332781e3bcfSOmar Sandoval struct btrfs_path *path, 333781e3bcfSOmar Sandoval u32 alignment) 3347c55ee0cSOmar Sandoval { 335d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 336b3470b5dSDavid Sterba {cache->start, 3 * alignment}, 3377c55ee0cSOmar Sandoval }; 3387c55ee0cSOmar Sandoval int ret; 3397c55ee0cSOmar Sandoval 340c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 341b3470b5dSDavid Sterba cache->start, cache->length); 3427c55ee0cSOmar Sandoval if (ret) { 3433c7251f2SDavid Sterba test_err("could not remove free space"); 3447c55ee0cSOmar Sandoval return ret; 3457c55ee0cSOmar Sandoval } 3467c55ee0cSOmar Sandoval 347b3470b5dSDavid Sterba ret = __add_to_free_space_tree(trans, cache, path, cache->start, 3482d5cffa1SNikolay Borisov alignment); 3497c55ee0cSOmar Sandoval if (ret) { 3503c7251f2SDavid Sterba test_err("could not add free space"); 3517c55ee0cSOmar Sandoval return ret; 3527c55ee0cSOmar Sandoval } 3537c55ee0cSOmar Sandoval 3542d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 355b3470b5dSDavid Sterba cache->start + 2 * alignment, alignment); 3567c55ee0cSOmar Sandoval if (ret) { 3573c7251f2SDavid Sterba test_err("could not add free space"); 3587c55ee0cSOmar Sandoval return ret; 3597c55ee0cSOmar Sandoval } 3607c55ee0cSOmar Sandoval 3612d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 362b3470b5dSDavid Sterba cache->start + alignment, alignment); 3637c55ee0cSOmar Sandoval if (ret) { 3643c7251f2SDavid Sterba test_err("could not add free space"); 3657c55ee0cSOmar Sandoval return ret; 3667c55ee0cSOmar Sandoval } 3677c55ee0cSOmar Sandoval 3687c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3697c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3707c55ee0cSOmar Sandoval } 3717c55ee0cSOmar Sandoval 3727c55ee0cSOmar Sandoval static int test_merge_none(struct btrfs_trans_handle *trans, 3737c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 37432da5386SDavid Sterba struct btrfs_block_group *cache, 375781e3bcfSOmar Sandoval struct btrfs_path *path, 376781e3bcfSOmar Sandoval u32 alignment) 3777c55ee0cSOmar Sandoval { 378d2d9ac6aSDavid Sterba const struct free_space_extent extents[] = { 379b3470b5dSDavid Sterba {cache->start, alignment}, 380b3470b5dSDavid Sterba {cache->start + 2 * alignment, alignment}, 381b3470b5dSDavid Sterba {cache->start + 4 * alignment, alignment}, 3827c55ee0cSOmar Sandoval }; 3837c55ee0cSOmar Sandoval int ret; 3847c55ee0cSOmar Sandoval 385c31683a6SNikolay Borisov ret = __remove_from_free_space_tree(trans, cache, path, 386b3470b5dSDavid Sterba cache->start, cache->length); 3877c55ee0cSOmar Sandoval if (ret) { 3883c7251f2SDavid Sterba test_err("could not remove free space"); 3897c55ee0cSOmar Sandoval return ret; 3907c55ee0cSOmar Sandoval } 3917c55ee0cSOmar Sandoval 392b3470b5dSDavid Sterba ret = __add_to_free_space_tree(trans, cache, path, cache->start, 3932d5cffa1SNikolay Borisov alignment); 3947c55ee0cSOmar Sandoval if (ret) { 3953c7251f2SDavid Sterba test_err("could not add free space"); 3967c55ee0cSOmar Sandoval return ret; 3977c55ee0cSOmar Sandoval } 3987c55ee0cSOmar Sandoval 3992d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 400b3470b5dSDavid Sterba cache->start + 4 * alignment, alignment); 4017c55ee0cSOmar Sandoval if (ret) { 4023c7251f2SDavid Sterba test_err("could not add free space"); 4037c55ee0cSOmar Sandoval return ret; 4047c55ee0cSOmar Sandoval } 4057c55ee0cSOmar Sandoval 4062d5cffa1SNikolay Borisov ret = __add_to_free_space_tree(trans, cache, path, 407b3470b5dSDavid Sterba cache->start + 2 * alignment, alignment); 4087c55ee0cSOmar Sandoval if (ret) { 4093c7251f2SDavid Sterba test_err("could not add free space"); 4107c55ee0cSOmar Sandoval return ret; 4117c55ee0cSOmar Sandoval } 4127c55ee0cSOmar Sandoval 4137c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 4147c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 4157c55ee0cSOmar Sandoval } 4167c55ee0cSOmar Sandoval 4177c55ee0cSOmar Sandoval typedef int (*test_func_t)(struct btrfs_trans_handle *, 4187c55ee0cSOmar Sandoval struct btrfs_fs_info *, 41932da5386SDavid Sterba struct btrfs_block_group *, 420781e3bcfSOmar Sandoval struct btrfs_path *, 421781e3bcfSOmar Sandoval u32 alignment); 4227c55ee0cSOmar Sandoval 423781e3bcfSOmar Sandoval static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, 424781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 4257c55ee0cSOmar Sandoval { 4267c0260eeSJeff Mahoney struct btrfs_fs_info *fs_info; 4277c55ee0cSOmar Sandoval struct btrfs_root *root = NULL; 42832da5386SDavid Sterba struct btrfs_block_group *cache = NULL; 4297c55ee0cSOmar Sandoval struct btrfs_trans_handle trans; 4307c55ee0cSOmar Sandoval struct btrfs_path *path = NULL; 4317c55ee0cSOmar Sandoval int ret; 4327c55ee0cSOmar Sandoval 433da17066cSJeff Mahoney fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize); 4347c0260eeSJeff Mahoney if (!fs_info) { 43537b2a7bcSDavid Sterba test_std_err(TEST_ALLOC_FS_INFO); 4367c0260eeSJeff Mahoney ret = -ENOMEM; 4377c55ee0cSOmar Sandoval goto out; 4387c55ee0cSOmar Sandoval } 4397c55ee0cSOmar Sandoval 440da17066cSJeff Mahoney root = btrfs_alloc_dummy_root(fs_info); 4417c0260eeSJeff Mahoney if (IS_ERR(root)) { 44252ab7bcaSDavid Sterba test_std_err(TEST_ALLOC_ROOT); 4437c0260eeSJeff Mahoney ret = PTR_ERR(root); 4447c55ee0cSOmar Sandoval goto out; 4457c55ee0cSOmar Sandoval } 4467c55ee0cSOmar Sandoval 4477c55ee0cSOmar Sandoval btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, 4487c55ee0cSOmar Sandoval BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); 449*abed4aaaSJosef Bacik root->root_key.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID; 450*abed4aaaSJosef Bacik root->root_key.type = BTRFS_ROOT_ITEM_KEY; 451*abed4aaaSJosef Bacik root->root_key.offset = 0; 452*abed4aaaSJosef Bacik btrfs_global_root_insert(root); 4537c55ee0cSOmar Sandoval root->fs_info->tree_root = root; 4547c55ee0cSOmar Sandoval 455da17066cSJeff Mahoney root->node = alloc_test_extent_buffer(root->fs_info, nodesize); 456b6293c82SDan Carpenter if (IS_ERR(root->node)) { 4579e3d9f84SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_BUFFER); 458b6293c82SDan Carpenter ret = PTR_ERR(root->node); 4597c55ee0cSOmar Sandoval goto out; 4607c55ee0cSOmar Sandoval } 4617c55ee0cSOmar Sandoval btrfs_set_header_level(root->node, 0); 4627c55ee0cSOmar Sandoval btrfs_set_header_nritems(root->node, 0); 463b9ef22deSFeifei Xu root->alloc_bytenr += 2 * nodesize; 4647c55ee0cSOmar Sandoval 465da17066cSJeff Mahoney cache = btrfs_alloc_dummy_block_group(fs_info, 8 * alignment); 4667c55ee0cSOmar Sandoval if (!cache) { 4673199366dSDavid Sterba test_std_err(TEST_ALLOC_BLOCK_GROUP); 4687c55ee0cSOmar Sandoval ret = -ENOMEM; 4697c55ee0cSOmar Sandoval goto out; 4707c55ee0cSOmar Sandoval } 4717c55ee0cSOmar Sandoval cache->bitmap_low_thresh = 0; 4727c55ee0cSOmar Sandoval cache->bitmap_high_thresh = (u32)-1; 4737c55ee0cSOmar Sandoval cache->needs_free_space = 1; 474aa66b0bbSKinglong Mee cache->fs_info = root->fs_info; 4757c55ee0cSOmar Sandoval 476483bce06SNikolay Borisov btrfs_init_dummy_trans(&trans, root->fs_info); 4777c55ee0cSOmar Sandoval 4787c55ee0cSOmar Sandoval path = btrfs_alloc_path(); 4797c55ee0cSOmar Sandoval if (!path) { 480770e0cc0SDavid Sterba test_std_err(TEST_ALLOC_ROOT); 4819ca2e97fSChristophe JAILLET ret = -ENOMEM; 4829ca2e97fSChristophe JAILLET goto out; 4837c55ee0cSOmar Sandoval } 4847c55ee0cSOmar Sandoval 485e4e0711cSNikolay Borisov ret = add_block_group_free_space(&trans, cache); 4867c55ee0cSOmar Sandoval if (ret) { 4873c7251f2SDavid Sterba test_err("could not add block group free space"); 4887c55ee0cSOmar Sandoval goto out; 4897c55ee0cSOmar Sandoval } 4907c55ee0cSOmar Sandoval 4917c55ee0cSOmar Sandoval if (bitmaps) { 492719fb4deSNikolay Borisov ret = convert_free_space_to_bitmaps(&trans, cache, path); 4937c55ee0cSOmar Sandoval if (ret) { 4943c7251f2SDavid Sterba test_err("could not convert block group to bitmaps"); 4957c55ee0cSOmar Sandoval goto out; 4967c55ee0cSOmar Sandoval } 4977c55ee0cSOmar Sandoval } 4987c55ee0cSOmar Sandoval 499781e3bcfSOmar Sandoval ret = test_func(&trans, root->fs_info, cache, path, alignment); 5007c55ee0cSOmar Sandoval if (ret) 5017c55ee0cSOmar Sandoval goto out; 5027c55ee0cSOmar Sandoval 503f3f72779SNikolay Borisov ret = remove_block_group_free_space(&trans, cache); 5047c55ee0cSOmar Sandoval if (ret) { 5053c7251f2SDavid Sterba test_err("could not remove block group free space"); 5067c55ee0cSOmar Sandoval goto out; 5077c55ee0cSOmar Sandoval } 5087c55ee0cSOmar Sandoval 5097c55ee0cSOmar Sandoval if (btrfs_header_nritems(root->node) != 0) { 5103c7251f2SDavid Sterba test_err("free space tree has leftover items"); 5117c55ee0cSOmar Sandoval ret = -EINVAL; 5127c55ee0cSOmar Sandoval goto out; 5137c55ee0cSOmar Sandoval } 5147c55ee0cSOmar Sandoval 5157c55ee0cSOmar Sandoval ret = 0; 5167c55ee0cSOmar Sandoval out: 5177c55ee0cSOmar Sandoval btrfs_free_path(path); 5187c55ee0cSOmar Sandoval btrfs_free_dummy_block_group(cache); 5197c55ee0cSOmar Sandoval btrfs_free_dummy_root(root); 5207c0260eeSJeff Mahoney btrfs_free_dummy_fs_info(fs_info); 5217c55ee0cSOmar Sandoval return ret; 5227c55ee0cSOmar Sandoval } 5237c55ee0cSOmar Sandoval 524781e3bcfSOmar Sandoval static int run_test_both_formats(test_func_t test_func, u32 sectorsize, 525781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 5267c55ee0cSOmar Sandoval { 527781e3bcfSOmar Sandoval int test_ret = 0; 5287c55ee0cSOmar Sandoval int ret; 5297c55ee0cSOmar Sandoval 530781e3bcfSOmar Sandoval ret = run_test(test_func, 0, sectorsize, nodesize, alignment); 531781e3bcfSOmar Sandoval if (ret) { 5323c7251f2SDavid Sterba test_err( 533d75f773cSSakari Ailus "%ps failed with extents, sectorsize=%u, nodesize=%u, alignment=%u", 534781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 535781e3bcfSOmar Sandoval test_ret = ret; 536781e3bcfSOmar Sandoval } 537781e3bcfSOmar Sandoval 538781e3bcfSOmar Sandoval ret = run_test(test_func, 1, sectorsize, nodesize, alignment); 539781e3bcfSOmar Sandoval if (ret) { 5403c7251f2SDavid Sterba test_err( 541d75f773cSSakari Ailus "%ps failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u", 542781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 543781e3bcfSOmar Sandoval test_ret = ret; 544781e3bcfSOmar Sandoval } 545781e3bcfSOmar Sandoval 546781e3bcfSOmar Sandoval return test_ret; 5477c55ee0cSOmar Sandoval } 5487c55ee0cSOmar Sandoval 549b9ef22deSFeifei Xu int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) 5507c55ee0cSOmar Sandoval { 5517c55ee0cSOmar Sandoval test_func_t tests[] = { 5527c55ee0cSOmar Sandoval test_empty_block_group, 5537c55ee0cSOmar Sandoval test_remove_all, 5547c55ee0cSOmar Sandoval test_remove_beginning, 5557c55ee0cSOmar Sandoval test_remove_end, 5567c55ee0cSOmar Sandoval test_remove_middle, 5577c55ee0cSOmar Sandoval test_merge_left, 5587c55ee0cSOmar Sandoval test_merge_right, 5597c55ee0cSOmar Sandoval test_merge_both, 5607c55ee0cSOmar Sandoval test_merge_none, 5617c55ee0cSOmar Sandoval }; 562781e3bcfSOmar Sandoval u32 bitmap_alignment; 563781e3bcfSOmar Sandoval int test_ret = 0; 5647c55ee0cSOmar Sandoval int i; 5657c55ee0cSOmar Sandoval 566781e3bcfSOmar Sandoval /* 567781e3bcfSOmar Sandoval * Align some operations to a page to flush out bugs in the extent 568781e3bcfSOmar Sandoval * buffer bitmap handling of highmem. 569781e3bcfSOmar Sandoval */ 570781e3bcfSOmar Sandoval bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; 571781e3bcfSOmar Sandoval 572315b76b4SDavid Sterba test_msg("running free space tree tests"); 5737c55ee0cSOmar Sandoval for (i = 0; i < ARRAY_SIZE(tests); i++) { 574781e3bcfSOmar Sandoval int ret; 575781e3bcfSOmar Sandoval 576781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 577781e3bcfSOmar Sandoval sectorsize); 578781e3bcfSOmar Sandoval if (ret) 579781e3bcfSOmar Sandoval test_ret = ret; 580781e3bcfSOmar Sandoval 581781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 582781e3bcfSOmar Sandoval bitmap_alignment); 583781e3bcfSOmar Sandoval if (ret) 584781e3bcfSOmar Sandoval test_ret = ret; 5857c55ee0cSOmar Sandoval } 5867c55ee0cSOmar Sandoval 587781e3bcfSOmar Sandoval return test_ret; 5887c55ee0cSOmar Sandoval } 589