17c55ee0cSOmar Sandoval /* 27c55ee0cSOmar Sandoval * Copyright (C) 2015 Facebook. All rights reserved. 37c55ee0cSOmar Sandoval * 47c55ee0cSOmar Sandoval * This program is free software; you can redistribute it and/or 57c55ee0cSOmar Sandoval * modify it under the terms of the GNU General Public 67c55ee0cSOmar Sandoval * License v2 as published by the Free Software Foundation. 77c55ee0cSOmar Sandoval * 87c55ee0cSOmar Sandoval * This program is distributed in the hope that it will be useful, 97c55ee0cSOmar Sandoval * but WITHOUT ANY WARRANTY; without even the implied warranty of 107c55ee0cSOmar Sandoval * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 117c55ee0cSOmar Sandoval * General Public License for more details. 127c55ee0cSOmar Sandoval * 137c55ee0cSOmar Sandoval * You should have received a copy of the GNU General Public 147c55ee0cSOmar Sandoval * License along with this program; if not, write to the 157c55ee0cSOmar Sandoval * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 167c55ee0cSOmar Sandoval * Boston, MA 021110-1307, USA. 177c55ee0cSOmar Sandoval */ 187c55ee0cSOmar Sandoval 19b9ef22deSFeifei Xu #include <linux/types.h> 207c55ee0cSOmar Sandoval #include "btrfs-tests.h" 217c55ee0cSOmar Sandoval #include "../ctree.h" 227c55ee0cSOmar Sandoval #include "../disk-io.h" 237c55ee0cSOmar Sandoval #include "../free-space-tree.h" 247c55ee0cSOmar Sandoval #include "../transaction.h" 257c55ee0cSOmar Sandoval 267c55ee0cSOmar Sandoval struct free_space_extent { 277c55ee0cSOmar Sandoval u64 start, length; 287c55ee0cSOmar Sandoval }; 297c55ee0cSOmar Sandoval 307c55ee0cSOmar Sandoval static int __check_free_space_extents(struct btrfs_trans_handle *trans, 317c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 327c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 337c55ee0cSOmar Sandoval struct btrfs_path *path, 347c55ee0cSOmar Sandoval struct free_space_extent *extents, 357c55ee0cSOmar Sandoval unsigned int num_extents) 367c55ee0cSOmar Sandoval { 377c55ee0cSOmar Sandoval struct btrfs_free_space_info *info; 387c55ee0cSOmar Sandoval struct btrfs_key key; 397c55ee0cSOmar Sandoval int prev_bit = 0, bit; 407c55ee0cSOmar Sandoval u64 extent_start = 0, offset, end; 417c55ee0cSOmar Sandoval u32 flags, extent_count; 427c55ee0cSOmar Sandoval unsigned int i; 437c55ee0cSOmar Sandoval int ret; 447c55ee0cSOmar Sandoval 457c55ee0cSOmar Sandoval info = search_free_space_info(trans, fs_info, cache, path, 0); 467c55ee0cSOmar Sandoval if (IS_ERR(info)) { 477c55ee0cSOmar Sandoval test_msg("Could not find free space info\n"); 487c55ee0cSOmar Sandoval ret = PTR_ERR(info); 497c55ee0cSOmar Sandoval goto out; 507c55ee0cSOmar Sandoval } 517c55ee0cSOmar Sandoval flags = btrfs_free_space_flags(path->nodes[0], info); 527c55ee0cSOmar Sandoval extent_count = btrfs_free_space_extent_count(path->nodes[0], info); 537c55ee0cSOmar Sandoval 547c55ee0cSOmar Sandoval if (extent_count != num_extents) { 557c55ee0cSOmar Sandoval test_msg("Extent count is wrong\n"); 567c55ee0cSOmar Sandoval ret = -EINVAL; 577c55ee0cSOmar Sandoval goto out; 587c55ee0cSOmar Sandoval } 597c55ee0cSOmar Sandoval if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 607c55ee0cSOmar Sandoval if (path->slots[0] != 0) 617c55ee0cSOmar Sandoval goto invalid; 627c55ee0cSOmar Sandoval end = cache->key.objectid + cache->key.offset; 637c55ee0cSOmar Sandoval i = 0; 647c55ee0cSOmar Sandoval while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) { 657c55ee0cSOmar Sandoval btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 667c55ee0cSOmar Sandoval if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY) 677c55ee0cSOmar Sandoval goto invalid; 687c55ee0cSOmar Sandoval offset = key.objectid; 697c55ee0cSOmar Sandoval while (offset < key.objectid + key.offset) { 707c55ee0cSOmar Sandoval bit = free_space_test_bit(cache, path, offset); 717c55ee0cSOmar Sandoval if (prev_bit == 0 && bit == 1) { 727c55ee0cSOmar Sandoval extent_start = offset; 737c55ee0cSOmar Sandoval } else if (prev_bit == 1 && bit == 0) { 747c55ee0cSOmar Sandoval if (i >= num_extents) 757c55ee0cSOmar Sandoval goto invalid; 767c55ee0cSOmar Sandoval if (i >= num_extents || 777c55ee0cSOmar Sandoval extent_start != extents[i].start || 787c55ee0cSOmar Sandoval offset - extent_start != extents[i].length) 797c55ee0cSOmar Sandoval goto invalid; 807c55ee0cSOmar Sandoval i++; 817c55ee0cSOmar Sandoval } 827c55ee0cSOmar Sandoval prev_bit = bit; 837c55ee0cSOmar Sandoval offset += cache->sectorsize; 847c55ee0cSOmar Sandoval } 857c55ee0cSOmar Sandoval } 867c55ee0cSOmar Sandoval if (prev_bit == 1) { 877c55ee0cSOmar Sandoval if (i >= num_extents || 887c55ee0cSOmar Sandoval extent_start != extents[i].start || 897c55ee0cSOmar Sandoval end - extent_start != extents[i].length) 907c55ee0cSOmar Sandoval goto invalid; 917c55ee0cSOmar Sandoval i++; 927c55ee0cSOmar Sandoval } 937c55ee0cSOmar Sandoval if (i != num_extents) 947c55ee0cSOmar Sandoval goto invalid; 957c55ee0cSOmar Sandoval } else { 967c55ee0cSOmar Sandoval if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 || 977c55ee0cSOmar Sandoval path->slots[0] != 0) 987c55ee0cSOmar Sandoval goto invalid; 997c55ee0cSOmar Sandoval for (i = 0; i < num_extents; i++) { 1007c55ee0cSOmar Sandoval path->slots[0]++; 1017c55ee0cSOmar Sandoval btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 1027c55ee0cSOmar Sandoval if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY || 1037c55ee0cSOmar Sandoval key.objectid != extents[i].start || 1047c55ee0cSOmar Sandoval key.offset != extents[i].length) 1057c55ee0cSOmar Sandoval goto invalid; 1067c55ee0cSOmar Sandoval } 1077c55ee0cSOmar Sandoval } 1087c55ee0cSOmar Sandoval 1097c55ee0cSOmar Sandoval ret = 0; 1107c55ee0cSOmar Sandoval out: 1117c55ee0cSOmar Sandoval btrfs_release_path(path); 1127c55ee0cSOmar Sandoval return ret; 1137c55ee0cSOmar Sandoval invalid: 1147c55ee0cSOmar Sandoval test_msg("Free space tree is invalid\n"); 1157c55ee0cSOmar Sandoval ret = -EINVAL; 1167c55ee0cSOmar Sandoval goto out; 1177c55ee0cSOmar Sandoval } 1187c55ee0cSOmar Sandoval 1197c55ee0cSOmar Sandoval static int check_free_space_extents(struct btrfs_trans_handle *trans, 1207c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1217c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 1227c55ee0cSOmar Sandoval struct btrfs_path *path, 1237c55ee0cSOmar Sandoval struct free_space_extent *extents, 1247c55ee0cSOmar Sandoval unsigned int num_extents) 1257c55ee0cSOmar Sandoval { 1267c55ee0cSOmar Sandoval struct btrfs_free_space_info *info; 1277c55ee0cSOmar Sandoval u32 flags; 1287c55ee0cSOmar Sandoval int ret; 1297c55ee0cSOmar Sandoval 1307c55ee0cSOmar Sandoval info = search_free_space_info(trans, fs_info, cache, path, 0); 1317c55ee0cSOmar Sandoval if (IS_ERR(info)) { 1327c55ee0cSOmar Sandoval test_msg("Could not find free space info\n"); 1337c55ee0cSOmar Sandoval btrfs_release_path(path); 1347c55ee0cSOmar Sandoval return PTR_ERR(info); 1357c55ee0cSOmar Sandoval } 1367c55ee0cSOmar Sandoval flags = btrfs_free_space_flags(path->nodes[0], info); 1377c55ee0cSOmar Sandoval btrfs_release_path(path); 1387c55ee0cSOmar Sandoval 1397c55ee0cSOmar Sandoval ret = __check_free_space_extents(trans, fs_info, cache, path, extents, 1407c55ee0cSOmar Sandoval num_extents); 1417c55ee0cSOmar Sandoval if (ret) 1427c55ee0cSOmar Sandoval return ret; 1437c55ee0cSOmar Sandoval 1447c55ee0cSOmar Sandoval /* Flip it to the other format and check that for good measure. */ 1457c55ee0cSOmar Sandoval if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 1467c55ee0cSOmar Sandoval ret = convert_free_space_to_extents(trans, fs_info, cache, path); 1477c55ee0cSOmar Sandoval if (ret) { 1487c55ee0cSOmar Sandoval test_msg("Could not convert to extents\n"); 1497c55ee0cSOmar Sandoval return ret; 1507c55ee0cSOmar Sandoval } 1517c55ee0cSOmar Sandoval } else { 1527c55ee0cSOmar Sandoval ret = convert_free_space_to_bitmaps(trans, fs_info, cache, path); 1537c55ee0cSOmar Sandoval if (ret) { 1547c55ee0cSOmar Sandoval test_msg("Could not convert to bitmaps\n"); 1557c55ee0cSOmar Sandoval return ret; 1567c55ee0cSOmar Sandoval } 1577c55ee0cSOmar Sandoval } 1587c55ee0cSOmar Sandoval return __check_free_space_extents(trans, fs_info, cache, path, extents, 1597c55ee0cSOmar Sandoval num_extents); 1607c55ee0cSOmar Sandoval } 1617c55ee0cSOmar Sandoval 1627c55ee0cSOmar Sandoval static int test_empty_block_group(struct btrfs_trans_handle *trans, 1637c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1647c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 165*781e3bcfSOmar Sandoval struct btrfs_path *path, 166*781e3bcfSOmar Sandoval u32 alignment) 1677c55ee0cSOmar Sandoval { 1687c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 1697c55ee0cSOmar Sandoval {cache->key.objectid, cache->key.offset}, 1707c55ee0cSOmar Sandoval }; 1717c55ee0cSOmar Sandoval 1727c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1737c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1747c55ee0cSOmar Sandoval } 1757c55ee0cSOmar Sandoval 1767c55ee0cSOmar Sandoval static int test_remove_all(struct btrfs_trans_handle *trans, 1777c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1787c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 179*781e3bcfSOmar Sandoval struct btrfs_path *path, 180*781e3bcfSOmar Sandoval u32 alignment) 1817c55ee0cSOmar Sandoval { 1827c55ee0cSOmar Sandoval struct free_space_extent extents[] = {}; 1837c55ee0cSOmar Sandoval int ret; 1847c55ee0cSOmar Sandoval 1857c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 1867c55ee0cSOmar Sandoval cache->key.objectid, 1877c55ee0cSOmar Sandoval cache->key.offset); 1887c55ee0cSOmar Sandoval if (ret) { 1897c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 1907c55ee0cSOmar Sandoval return ret; 1917c55ee0cSOmar Sandoval } 1927c55ee0cSOmar Sandoval 1937c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 1947c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 1957c55ee0cSOmar Sandoval } 1967c55ee0cSOmar Sandoval 1977c55ee0cSOmar Sandoval static int test_remove_beginning(struct btrfs_trans_handle *trans, 1987c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 1997c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 200*781e3bcfSOmar Sandoval struct btrfs_path *path, 201*781e3bcfSOmar Sandoval u32 alignment) 2027c55ee0cSOmar Sandoval { 2037c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 204*781e3bcfSOmar Sandoval {cache->key.objectid + alignment, 205*781e3bcfSOmar Sandoval cache->key.offset - alignment}, 2067c55ee0cSOmar Sandoval }; 2077c55ee0cSOmar Sandoval int ret; 2087c55ee0cSOmar Sandoval 2097c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 210*781e3bcfSOmar Sandoval cache->key.objectid, alignment); 2117c55ee0cSOmar Sandoval if (ret) { 2127c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 2137c55ee0cSOmar Sandoval return ret; 2147c55ee0cSOmar Sandoval } 2157c55ee0cSOmar Sandoval 2167c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2177c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2187c55ee0cSOmar Sandoval 2197c55ee0cSOmar Sandoval } 2207c55ee0cSOmar Sandoval 2217c55ee0cSOmar Sandoval static int test_remove_end(struct btrfs_trans_handle *trans, 2227c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2237c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 224*781e3bcfSOmar Sandoval struct btrfs_path *path, 225*781e3bcfSOmar Sandoval u32 alignment) 2267c55ee0cSOmar Sandoval { 2277c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 228*781e3bcfSOmar Sandoval {cache->key.objectid, cache->key.offset - alignment}, 2297c55ee0cSOmar Sandoval }; 2307c55ee0cSOmar Sandoval int ret; 2317c55ee0cSOmar Sandoval 2327c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 2337c55ee0cSOmar Sandoval cache->key.objectid + 234*781e3bcfSOmar Sandoval cache->key.offset - alignment, 235*781e3bcfSOmar Sandoval alignment); 2367c55ee0cSOmar Sandoval if (ret) { 2377c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 2387c55ee0cSOmar Sandoval return ret; 2397c55ee0cSOmar Sandoval } 2407c55ee0cSOmar Sandoval 2417c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2427c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2437c55ee0cSOmar Sandoval } 2447c55ee0cSOmar Sandoval 2457c55ee0cSOmar Sandoval static int test_remove_middle(struct btrfs_trans_handle *trans, 2467c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2477c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 248*781e3bcfSOmar Sandoval struct btrfs_path *path, 249*781e3bcfSOmar Sandoval u32 alignment) 2507c55ee0cSOmar Sandoval { 2517c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 252*781e3bcfSOmar Sandoval {cache->key.objectid, alignment}, 253*781e3bcfSOmar Sandoval {cache->key.objectid + 2 * alignment, 254*781e3bcfSOmar Sandoval cache->key.offset - 2 * alignment}, 2557c55ee0cSOmar Sandoval }; 2567c55ee0cSOmar Sandoval int ret; 2577c55ee0cSOmar Sandoval 2587c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 259*781e3bcfSOmar Sandoval cache->key.objectid + alignment, 260*781e3bcfSOmar Sandoval alignment); 2617c55ee0cSOmar Sandoval if (ret) { 2627c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 2637c55ee0cSOmar Sandoval return ret; 2647c55ee0cSOmar Sandoval } 2657c55ee0cSOmar Sandoval 2667c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 2677c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 2687c55ee0cSOmar Sandoval } 2697c55ee0cSOmar Sandoval 2707c55ee0cSOmar Sandoval static int test_merge_left(struct btrfs_trans_handle *trans, 2717c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 2727c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 273*781e3bcfSOmar Sandoval struct btrfs_path *path, 274*781e3bcfSOmar Sandoval u32 alignment) 2757c55ee0cSOmar Sandoval { 2767c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 277*781e3bcfSOmar Sandoval {cache->key.objectid, 2 * alignment}, 2787c55ee0cSOmar Sandoval }; 2797c55ee0cSOmar Sandoval int ret; 2807c55ee0cSOmar Sandoval 2817c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 2827c55ee0cSOmar Sandoval cache->key.objectid, 2837c55ee0cSOmar Sandoval cache->key.offset); 2847c55ee0cSOmar Sandoval if (ret) { 2857c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 2867c55ee0cSOmar Sandoval return ret; 2877c55ee0cSOmar Sandoval } 2887c55ee0cSOmar Sandoval 2897c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 290*781e3bcfSOmar Sandoval cache->key.objectid, alignment); 2917c55ee0cSOmar Sandoval if (ret) { 2927c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 2937c55ee0cSOmar Sandoval return ret; 2947c55ee0cSOmar Sandoval } 2957c55ee0cSOmar Sandoval 2967c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 297*781e3bcfSOmar Sandoval cache->key.objectid + alignment, 298*781e3bcfSOmar Sandoval alignment); 2997c55ee0cSOmar Sandoval if (ret) { 3007c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3017c55ee0cSOmar Sandoval return ret; 3027c55ee0cSOmar Sandoval } 3037c55ee0cSOmar Sandoval 3047c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3057c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3067c55ee0cSOmar Sandoval } 3077c55ee0cSOmar Sandoval 3087c55ee0cSOmar Sandoval static int test_merge_right(struct btrfs_trans_handle *trans, 3097c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 3107c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 311*781e3bcfSOmar Sandoval struct btrfs_path *path, 312*781e3bcfSOmar Sandoval u32 alignment) 3137c55ee0cSOmar Sandoval { 3147c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 315*781e3bcfSOmar Sandoval {cache->key.objectid + alignment, 2 * alignment}, 3167c55ee0cSOmar Sandoval }; 3177c55ee0cSOmar Sandoval int ret; 3187c55ee0cSOmar Sandoval 3197c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 3207c55ee0cSOmar Sandoval cache->key.objectid, 3217c55ee0cSOmar Sandoval cache->key.offset); 3227c55ee0cSOmar Sandoval if (ret) { 3237c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 3247c55ee0cSOmar Sandoval return ret; 3257c55ee0cSOmar Sandoval } 3267c55ee0cSOmar Sandoval 3277c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 328*781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 329*781e3bcfSOmar Sandoval alignment); 3307c55ee0cSOmar Sandoval if (ret) { 3317c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3327c55ee0cSOmar Sandoval return ret; 3337c55ee0cSOmar Sandoval } 3347c55ee0cSOmar Sandoval 3357c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 336*781e3bcfSOmar Sandoval cache->key.objectid + alignment, 337*781e3bcfSOmar Sandoval alignment); 3387c55ee0cSOmar Sandoval if (ret) { 3397c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3407c55ee0cSOmar Sandoval return ret; 3417c55ee0cSOmar Sandoval } 3427c55ee0cSOmar Sandoval 3437c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3447c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3457c55ee0cSOmar Sandoval } 3467c55ee0cSOmar Sandoval 3477c55ee0cSOmar Sandoval static int test_merge_both(struct btrfs_trans_handle *trans, 3487c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 3497c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 350*781e3bcfSOmar Sandoval struct btrfs_path *path, 351*781e3bcfSOmar Sandoval u32 alignment) 3527c55ee0cSOmar Sandoval { 3537c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 354*781e3bcfSOmar Sandoval {cache->key.objectid, 3 * alignment}, 3557c55ee0cSOmar Sandoval }; 3567c55ee0cSOmar Sandoval int ret; 3577c55ee0cSOmar Sandoval 3587c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 3597c55ee0cSOmar Sandoval cache->key.objectid, 3607c55ee0cSOmar Sandoval cache->key.offset); 3617c55ee0cSOmar Sandoval if (ret) { 3627c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 3637c55ee0cSOmar Sandoval return ret; 3647c55ee0cSOmar Sandoval } 3657c55ee0cSOmar Sandoval 3667c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 367*781e3bcfSOmar Sandoval cache->key.objectid, alignment); 3687c55ee0cSOmar Sandoval if (ret) { 3697c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3707c55ee0cSOmar Sandoval return ret; 3717c55ee0cSOmar Sandoval } 3727c55ee0cSOmar Sandoval 3737c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 374*781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 375*781e3bcfSOmar Sandoval alignment); 3767c55ee0cSOmar Sandoval if (ret) { 3777c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3787c55ee0cSOmar Sandoval return ret; 3797c55ee0cSOmar Sandoval } 3807c55ee0cSOmar Sandoval 3817c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 382*781e3bcfSOmar Sandoval cache->key.objectid + alignment, 383*781e3bcfSOmar Sandoval alignment); 3847c55ee0cSOmar Sandoval if (ret) { 3857c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 3867c55ee0cSOmar Sandoval return ret; 3877c55ee0cSOmar Sandoval } 3887c55ee0cSOmar Sandoval 3897c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 3907c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 3917c55ee0cSOmar Sandoval } 3927c55ee0cSOmar Sandoval 3937c55ee0cSOmar Sandoval static int test_merge_none(struct btrfs_trans_handle *trans, 3947c55ee0cSOmar Sandoval struct btrfs_fs_info *fs_info, 3957c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache, 396*781e3bcfSOmar Sandoval struct btrfs_path *path, 397*781e3bcfSOmar Sandoval u32 alignment) 3987c55ee0cSOmar Sandoval { 3997c55ee0cSOmar Sandoval struct free_space_extent extents[] = { 400*781e3bcfSOmar Sandoval {cache->key.objectid, alignment}, 401*781e3bcfSOmar Sandoval {cache->key.objectid + 2 * alignment, alignment}, 402*781e3bcfSOmar Sandoval {cache->key.objectid + 4 * alignment, alignment}, 4037c55ee0cSOmar Sandoval }; 4047c55ee0cSOmar Sandoval int ret; 4057c55ee0cSOmar Sandoval 4067c55ee0cSOmar Sandoval ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 4077c55ee0cSOmar Sandoval cache->key.objectid, 4087c55ee0cSOmar Sandoval cache->key.offset); 4097c55ee0cSOmar Sandoval if (ret) { 4107c55ee0cSOmar Sandoval test_msg("Could not remove free space\n"); 4117c55ee0cSOmar Sandoval return ret; 4127c55ee0cSOmar Sandoval } 4137c55ee0cSOmar Sandoval 4147c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 415*781e3bcfSOmar Sandoval cache->key.objectid, alignment); 4167c55ee0cSOmar Sandoval if (ret) { 4177c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 4187c55ee0cSOmar Sandoval return ret; 4197c55ee0cSOmar Sandoval } 4207c55ee0cSOmar Sandoval 4217c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 422*781e3bcfSOmar Sandoval cache->key.objectid + 4 * alignment, 423*781e3bcfSOmar Sandoval alignment); 4247c55ee0cSOmar Sandoval if (ret) { 4257c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 4267c55ee0cSOmar Sandoval return ret; 4277c55ee0cSOmar Sandoval } 4287c55ee0cSOmar Sandoval 4297c55ee0cSOmar Sandoval ret = __add_to_free_space_tree(trans, fs_info, cache, path, 430*781e3bcfSOmar Sandoval cache->key.objectid + 2 * alignment, 431*781e3bcfSOmar Sandoval alignment); 4327c55ee0cSOmar Sandoval if (ret) { 4337c55ee0cSOmar Sandoval test_msg("Could not add free space\n"); 4347c55ee0cSOmar Sandoval return ret; 4357c55ee0cSOmar Sandoval } 4367c55ee0cSOmar Sandoval 4377c55ee0cSOmar Sandoval return check_free_space_extents(trans, fs_info, cache, path, 4387c55ee0cSOmar Sandoval extents, ARRAY_SIZE(extents)); 4397c55ee0cSOmar Sandoval } 4407c55ee0cSOmar Sandoval 4417c55ee0cSOmar Sandoval typedef int (*test_func_t)(struct btrfs_trans_handle *, 4427c55ee0cSOmar Sandoval struct btrfs_fs_info *, 4437c55ee0cSOmar Sandoval struct btrfs_block_group_cache *, 444*781e3bcfSOmar Sandoval struct btrfs_path *, 445*781e3bcfSOmar Sandoval u32 alignment); 4467c55ee0cSOmar Sandoval 447*781e3bcfSOmar Sandoval static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, 448*781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 4497c55ee0cSOmar Sandoval { 4507c0260eeSJeff Mahoney struct btrfs_fs_info *fs_info; 4517c55ee0cSOmar Sandoval struct btrfs_root *root = NULL; 4527c55ee0cSOmar Sandoval struct btrfs_block_group_cache *cache = NULL; 4537c55ee0cSOmar Sandoval struct btrfs_trans_handle trans; 4547c55ee0cSOmar Sandoval struct btrfs_path *path = NULL; 4557c55ee0cSOmar Sandoval int ret; 4567c55ee0cSOmar Sandoval 4577c0260eeSJeff Mahoney fs_info = btrfs_alloc_dummy_fs_info(); 4587c0260eeSJeff Mahoney if (!fs_info) { 4597c0260eeSJeff Mahoney test_msg("Couldn't allocate dummy fs info\n"); 4607c0260eeSJeff Mahoney ret = -ENOMEM; 4617c55ee0cSOmar Sandoval goto out; 4627c55ee0cSOmar Sandoval } 4637c55ee0cSOmar Sandoval 4647c0260eeSJeff Mahoney root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); 4657c0260eeSJeff Mahoney if (IS_ERR(root)) { 4667c0260eeSJeff Mahoney test_msg("Couldn't allocate dummy root\n"); 4677c0260eeSJeff Mahoney ret = PTR_ERR(root); 4687c55ee0cSOmar Sandoval goto out; 4697c55ee0cSOmar Sandoval } 4707c55ee0cSOmar Sandoval 4717c55ee0cSOmar Sandoval btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, 4727c55ee0cSOmar Sandoval BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); 4737c55ee0cSOmar Sandoval root->fs_info->free_space_root = root; 4747c55ee0cSOmar Sandoval root->fs_info->tree_root = root; 4757c55ee0cSOmar Sandoval 476b9ef22deSFeifei Xu root->node = alloc_test_extent_buffer(root->fs_info, 477b9ef22deSFeifei Xu nodesize, nodesize); 4787c55ee0cSOmar Sandoval if (!root->node) { 4797c55ee0cSOmar Sandoval test_msg("Couldn't allocate dummy buffer\n"); 4807c55ee0cSOmar Sandoval ret = -ENOMEM; 4817c55ee0cSOmar Sandoval goto out; 4827c55ee0cSOmar Sandoval } 4837c55ee0cSOmar Sandoval btrfs_set_header_level(root->node, 0); 4847c55ee0cSOmar Sandoval btrfs_set_header_nritems(root->node, 0); 485b9ef22deSFeifei Xu root->alloc_bytenr += 2 * nodesize; 4867c55ee0cSOmar Sandoval 487*781e3bcfSOmar Sandoval cache = btrfs_alloc_dummy_block_group(8 * alignment, sectorsize); 4887c55ee0cSOmar Sandoval if (!cache) { 4897c55ee0cSOmar Sandoval test_msg("Couldn't allocate dummy block group cache\n"); 4907c55ee0cSOmar Sandoval ret = -ENOMEM; 4917c55ee0cSOmar Sandoval goto out; 4927c55ee0cSOmar Sandoval } 4937c55ee0cSOmar Sandoval cache->bitmap_low_thresh = 0; 4947c55ee0cSOmar Sandoval cache->bitmap_high_thresh = (u32)-1; 4957c55ee0cSOmar Sandoval cache->needs_free_space = 1; 496aa66b0bbSKinglong Mee cache->fs_info = root->fs_info; 4977c55ee0cSOmar Sandoval 4987c55ee0cSOmar Sandoval btrfs_init_dummy_trans(&trans); 4997c55ee0cSOmar Sandoval 5007c55ee0cSOmar Sandoval path = btrfs_alloc_path(); 5017c55ee0cSOmar Sandoval if (!path) { 5027c55ee0cSOmar Sandoval test_msg("Couldn't allocate path\n"); 5037c55ee0cSOmar Sandoval return -ENOMEM; 5047c55ee0cSOmar Sandoval } 5057c55ee0cSOmar Sandoval 5067c55ee0cSOmar Sandoval ret = add_block_group_free_space(&trans, root->fs_info, cache); 5077c55ee0cSOmar Sandoval if (ret) { 5087c55ee0cSOmar Sandoval test_msg("Could not add block group free space\n"); 5097c55ee0cSOmar Sandoval goto out; 5107c55ee0cSOmar Sandoval } 5117c55ee0cSOmar Sandoval 5127c55ee0cSOmar Sandoval if (bitmaps) { 5137c55ee0cSOmar Sandoval ret = convert_free_space_to_bitmaps(&trans, root->fs_info, 5147c55ee0cSOmar Sandoval cache, path); 5157c55ee0cSOmar Sandoval if (ret) { 5167c55ee0cSOmar Sandoval test_msg("Could not convert block group to bitmaps\n"); 5177c55ee0cSOmar Sandoval goto out; 5187c55ee0cSOmar Sandoval } 5197c55ee0cSOmar Sandoval } 5207c55ee0cSOmar Sandoval 521*781e3bcfSOmar Sandoval ret = test_func(&trans, root->fs_info, cache, path, alignment); 5227c55ee0cSOmar Sandoval if (ret) 5237c55ee0cSOmar Sandoval goto out; 5247c55ee0cSOmar Sandoval 5257c55ee0cSOmar Sandoval ret = remove_block_group_free_space(&trans, root->fs_info, cache); 5267c55ee0cSOmar Sandoval if (ret) { 5277c55ee0cSOmar Sandoval test_msg("Could not remove block group free space\n"); 5287c55ee0cSOmar Sandoval goto out; 5297c55ee0cSOmar Sandoval } 5307c55ee0cSOmar Sandoval 5317c55ee0cSOmar Sandoval if (btrfs_header_nritems(root->node) != 0) { 5327c55ee0cSOmar Sandoval test_msg("Free space tree has leftover items\n"); 5337c55ee0cSOmar Sandoval ret = -EINVAL; 5347c55ee0cSOmar Sandoval goto out; 5357c55ee0cSOmar Sandoval } 5367c55ee0cSOmar Sandoval 5377c55ee0cSOmar Sandoval ret = 0; 5387c55ee0cSOmar Sandoval out: 5397c55ee0cSOmar Sandoval btrfs_free_path(path); 5407c55ee0cSOmar Sandoval btrfs_free_dummy_block_group(cache); 5417c55ee0cSOmar Sandoval btrfs_free_dummy_root(root); 5427c0260eeSJeff Mahoney btrfs_free_dummy_fs_info(fs_info); 5437c55ee0cSOmar Sandoval return ret; 5447c55ee0cSOmar Sandoval } 5457c55ee0cSOmar Sandoval 546*781e3bcfSOmar Sandoval static int run_test_both_formats(test_func_t test_func, u32 sectorsize, 547*781e3bcfSOmar Sandoval u32 nodesize, u32 alignment) 5487c55ee0cSOmar Sandoval { 549*781e3bcfSOmar Sandoval int test_ret = 0; 5507c55ee0cSOmar Sandoval int ret; 5517c55ee0cSOmar Sandoval 552*781e3bcfSOmar Sandoval ret = run_test(test_func, 0, sectorsize, nodesize, alignment); 553*781e3bcfSOmar Sandoval if (ret) { 554*781e3bcfSOmar Sandoval test_msg("%pf failed with extents, sectorsize=%u, nodesize=%u, alignment=%u\n", 555*781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 556*781e3bcfSOmar Sandoval test_ret = ret; 557*781e3bcfSOmar Sandoval } 558*781e3bcfSOmar Sandoval 559*781e3bcfSOmar Sandoval ret = run_test(test_func, 1, sectorsize, nodesize, alignment); 560*781e3bcfSOmar Sandoval if (ret) { 561*781e3bcfSOmar Sandoval test_msg("%pf failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u\n", 562*781e3bcfSOmar Sandoval test_func, sectorsize, nodesize, alignment); 563*781e3bcfSOmar Sandoval test_ret = ret; 564*781e3bcfSOmar Sandoval } 565*781e3bcfSOmar Sandoval 566*781e3bcfSOmar Sandoval return test_ret; 5677c55ee0cSOmar Sandoval } 5687c55ee0cSOmar Sandoval 569b9ef22deSFeifei Xu int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) 5707c55ee0cSOmar Sandoval { 5717c55ee0cSOmar Sandoval test_func_t tests[] = { 5727c55ee0cSOmar Sandoval test_empty_block_group, 5737c55ee0cSOmar Sandoval test_remove_all, 5747c55ee0cSOmar Sandoval test_remove_beginning, 5757c55ee0cSOmar Sandoval test_remove_end, 5767c55ee0cSOmar Sandoval test_remove_middle, 5777c55ee0cSOmar Sandoval test_merge_left, 5787c55ee0cSOmar Sandoval test_merge_right, 5797c55ee0cSOmar Sandoval test_merge_both, 5807c55ee0cSOmar Sandoval test_merge_none, 5817c55ee0cSOmar Sandoval }; 582*781e3bcfSOmar Sandoval u32 bitmap_alignment; 583*781e3bcfSOmar Sandoval int test_ret = 0; 5847c55ee0cSOmar Sandoval int i; 5857c55ee0cSOmar Sandoval 586*781e3bcfSOmar Sandoval /* 587*781e3bcfSOmar Sandoval * Align some operations to a page to flush out bugs in the extent 588*781e3bcfSOmar Sandoval * buffer bitmap handling of highmem. 589*781e3bcfSOmar Sandoval */ 590*781e3bcfSOmar Sandoval bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; 591*781e3bcfSOmar Sandoval 5927c55ee0cSOmar Sandoval test_msg("Running free space tree tests\n"); 5937c55ee0cSOmar Sandoval for (i = 0; i < ARRAY_SIZE(tests); i++) { 594*781e3bcfSOmar Sandoval int ret; 595*781e3bcfSOmar Sandoval 596*781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 597*781e3bcfSOmar Sandoval sectorsize); 598*781e3bcfSOmar Sandoval if (ret) 599*781e3bcfSOmar Sandoval test_ret = ret; 600*781e3bcfSOmar Sandoval 601*781e3bcfSOmar Sandoval ret = run_test_both_formats(tests[i], sectorsize, nodesize, 602*781e3bcfSOmar Sandoval bitmap_alignment); 603*781e3bcfSOmar Sandoval if (ret) 604*781e3bcfSOmar Sandoval test_ret = ret; 6057c55ee0cSOmar Sandoval } 6067c55ee0cSOmar Sandoval 607*781e3bcfSOmar Sandoval return test_ret; 6087c55ee0cSOmar Sandoval } 609