1 /* 2 * Copyright (C) 2015 Facebook. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 #include <linux/types.h> 20 #include "btrfs-tests.h" 21 #include "../ctree.h" 22 #include "../disk-io.h" 23 #include "../free-space-tree.h" 24 #include "../transaction.h" 25 26 struct free_space_extent { 27 u64 start, length; 28 }; 29 30 /* 31 * The test cases align their operations to this in order to hit some of the 32 * edge cases in the bitmap code. 33 */ 34 #define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE) 35 36 static int __check_free_space_extents(struct btrfs_trans_handle *trans, 37 struct btrfs_fs_info *fs_info, 38 struct btrfs_block_group_cache *cache, 39 struct btrfs_path *path, 40 struct free_space_extent *extents, 41 unsigned int num_extents) 42 { 43 struct btrfs_free_space_info *info; 44 struct btrfs_key key; 45 int prev_bit = 0, bit; 46 u64 extent_start = 0, offset, end; 47 u32 flags, extent_count; 48 unsigned int i; 49 int ret; 50 51 info = search_free_space_info(trans, fs_info, cache, path, 0); 52 if (IS_ERR(info)) { 53 test_msg("Could not find free space info\n"); 54 ret = PTR_ERR(info); 55 goto out; 56 } 57 flags = btrfs_free_space_flags(path->nodes[0], info); 58 extent_count = btrfs_free_space_extent_count(path->nodes[0], info); 59 60 if (extent_count != num_extents) { 61 test_msg("Extent count is wrong\n"); 62 ret = -EINVAL; 63 goto out; 64 } 65 if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 66 if (path->slots[0] != 0) 67 goto invalid; 68 end = cache->key.objectid + cache->key.offset; 69 i = 0; 70 while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) { 71 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 72 if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY) 73 goto invalid; 74 offset = key.objectid; 75 while (offset < key.objectid + key.offset) { 76 bit = free_space_test_bit(cache, path, offset); 77 if (prev_bit == 0 && bit == 1) { 78 extent_start = offset; 79 } else if (prev_bit == 1 && bit == 0) { 80 if (i >= num_extents) 81 goto invalid; 82 if (i >= num_extents || 83 extent_start != extents[i].start || 84 offset - extent_start != extents[i].length) 85 goto invalid; 86 i++; 87 } 88 prev_bit = bit; 89 offset += cache->sectorsize; 90 } 91 } 92 if (prev_bit == 1) { 93 if (i >= num_extents || 94 extent_start != extents[i].start || 95 end - extent_start != extents[i].length) 96 goto invalid; 97 i++; 98 } 99 if (i != num_extents) 100 goto invalid; 101 } else { 102 if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 || 103 path->slots[0] != 0) 104 goto invalid; 105 for (i = 0; i < num_extents; i++) { 106 path->slots[0]++; 107 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); 108 if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY || 109 key.objectid != extents[i].start || 110 key.offset != extents[i].length) 111 goto invalid; 112 } 113 } 114 115 ret = 0; 116 out: 117 btrfs_release_path(path); 118 return ret; 119 invalid: 120 test_msg("Free space tree is invalid\n"); 121 ret = -EINVAL; 122 goto out; 123 } 124 125 static int check_free_space_extents(struct btrfs_trans_handle *trans, 126 struct btrfs_fs_info *fs_info, 127 struct btrfs_block_group_cache *cache, 128 struct btrfs_path *path, 129 struct free_space_extent *extents, 130 unsigned int num_extents) 131 { 132 struct btrfs_free_space_info *info; 133 u32 flags; 134 int ret; 135 136 info = search_free_space_info(trans, fs_info, cache, path, 0); 137 if (IS_ERR(info)) { 138 test_msg("Could not find free space info\n"); 139 btrfs_release_path(path); 140 return PTR_ERR(info); 141 } 142 flags = btrfs_free_space_flags(path->nodes[0], info); 143 btrfs_release_path(path); 144 145 ret = __check_free_space_extents(trans, fs_info, cache, path, extents, 146 num_extents); 147 if (ret) 148 return ret; 149 150 /* Flip it to the other format and check that for good measure. */ 151 if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { 152 ret = convert_free_space_to_extents(trans, fs_info, cache, path); 153 if (ret) { 154 test_msg("Could not convert to extents\n"); 155 return ret; 156 } 157 } else { 158 ret = convert_free_space_to_bitmaps(trans, fs_info, cache, path); 159 if (ret) { 160 test_msg("Could not convert to bitmaps\n"); 161 return ret; 162 } 163 } 164 return __check_free_space_extents(trans, fs_info, cache, path, extents, 165 num_extents); 166 } 167 168 static int test_empty_block_group(struct btrfs_trans_handle *trans, 169 struct btrfs_fs_info *fs_info, 170 struct btrfs_block_group_cache *cache, 171 struct btrfs_path *path) 172 { 173 struct free_space_extent extents[] = { 174 {cache->key.objectid, cache->key.offset}, 175 }; 176 177 return check_free_space_extents(trans, fs_info, cache, path, 178 extents, ARRAY_SIZE(extents)); 179 } 180 181 static int test_remove_all(struct btrfs_trans_handle *trans, 182 struct btrfs_fs_info *fs_info, 183 struct btrfs_block_group_cache *cache, 184 struct btrfs_path *path) 185 { 186 struct free_space_extent extents[] = {}; 187 int ret; 188 189 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 190 cache->key.objectid, 191 cache->key.offset); 192 if (ret) { 193 test_msg("Could not remove free space\n"); 194 return ret; 195 } 196 197 return check_free_space_extents(trans, fs_info, cache, path, 198 extents, ARRAY_SIZE(extents)); 199 } 200 201 static int test_remove_beginning(struct btrfs_trans_handle *trans, 202 struct btrfs_fs_info *fs_info, 203 struct btrfs_block_group_cache *cache, 204 struct btrfs_path *path) 205 { 206 struct free_space_extent extents[] = { 207 {cache->key.objectid + BITMAP_RANGE, 208 cache->key.offset - BITMAP_RANGE}, 209 }; 210 int ret; 211 212 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 213 cache->key.objectid, BITMAP_RANGE); 214 if (ret) { 215 test_msg("Could not remove free space\n"); 216 return ret; 217 } 218 219 return check_free_space_extents(trans, fs_info, cache, path, 220 extents, ARRAY_SIZE(extents)); 221 222 } 223 224 static int test_remove_end(struct btrfs_trans_handle *trans, 225 struct btrfs_fs_info *fs_info, 226 struct btrfs_block_group_cache *cache, 227 struct btrfs_path *path) 228 { 229 struct free_space_extent extents[] = { 230 {cache->key.objectid, cache->key.offset - BITMAP_RANGE}, 231 }; 232 int ret; 233 234 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 235 cache->key.objectid + 236 cache->key.offset - BITMAP_RANGE, 237 BITMAP_RANGE); 238 if (ret) { 239 test_msg("Could not remove free space\n"); 240 return ret; 241 } 242 243 return check_free_space_extents(trans, fs_info, cache, path, 244 extents, ARRAY_SIZE(extents)); 245 } 246 247 static int test_remove_middle(struct btrfs_trans_handle *trans, 248 struct btrfs_fs_info *fs_info, 249 struct btrfs_block_group_cache *cache, 250 struct btrfs_path *path) 251 { 252 struct free_space_extent extents[] = { 253 {cache->key.objectid, BITMAP_RANGE}, 254 {cache->key.objectid + 2 * BITMAP_RANGE, 255 cache->key.offset - 2 * BITMAP_RANGE}, 256 }; 257 int ret; 258 259 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 260 cache->key.objectid + BITMAP_RANGE, 261 BITMAP_RANGE); 262 if (ret) { 263 test_msg("Could not remove free space\n"); 264 return ret; 265 } 266 267 return check_free_space_extents(trans, fs_info, cache, path, 268 extents, ARRAY_SIZE(extents)); 269 } 270 271 static int test_merge_left(struct btrfs_trans_handle *trans, 272 struct btrfs_fs_info *fs_info, 273 struct btrfs_block_group_cache *cache, 274 struct btrfs_path *path) 275 { 276 struct free_space_extent extents[] = { 277 {cache->key.objectid, 2 * BITMAP_RANGE}, 278 }; 279 int ret; 280 281 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 282 cache->key.objectid, 283 cache->key.offset); 284 if (ret) { 285 test_msg("Could not remove free space\n"); 286 return ret; 287 } 288 289 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 290 cache->key.objectid, BITMAP_RANGE); 291 if (ret) { 292 test_msg("Could not add free space\n"); 293 return ret; 294 } 295 296 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 297 cache->key.objectid + BITMAP_RANGE, 298 BITMAP_RANGE); 299 if (ret) { 300 test_msg("Could not add free space\n"); 301 return ret; 302 } 303 304 return check_free_space_extents(trans, fs_info, cache, path, 305 extents, ARRAY_SIZE(extents)); 306 } 307 308 static int test_merge_right(struct btrfs_trans_handle *trans, 309 struct btrfs_fs_info *fs_info, 310 struct btrfs_block_group_cache *cache, 311 struct btrfs_path *path) 312 { 313 struct free_space_extent extents[] = { 314 {cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE}, 315 }; 316 int ret; 317 318 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 319 cache->key.objectid, 320 cache->key.offset); 321 if (ret) { 322 test_msg("Could not remove free space\n"); 323 return ret; 324 } 325 326 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 327 cache->key.objectid + 2 * BITMAP_RANGE, 328 BITMAP_RANGE); 329 if (ret) { 330 test_msg("Could not add free space\n"); 331 return ret; 332 } 333 334 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 335 cache->key.objectid + BITMAP_RANGE, 336 BITMAP_RANGE); 337 if (ret) { 338 test_msg("Could not add free space\n"); 339 return ret; 340 } 341 342 return check_free_space_extents(trans, fs_info, cache, path, 343 extents, ARRAY_SIZE(extents)); 344 } 345 346 static int test_merge_both(struct btrfs_trans_handle *trans, 347 struct btrfs_fs_info *fs_info, 348 struct btrfs_block_group_cache *cache, 349 struct btrfs_path *path) 350 { 351 struct free_space_extent extents[] = { 352 {cache->key.objectid, 3 * BITMAP_RANGE}, 353 }; 354 int ret; 355 356 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 357 cache->key.objectid, 358 cache->key.offset); 359 if (ret) { 360 test_msg("Could not remove free space\n"); 361 return ret; 362 } 363 364 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 365 cache->key.objectid, BITMAP_RANGE); 366 if (ret) { 367 test_msg("Could not add free space\n"); 368 return ret; 369 } 370 371 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 372 cache->key.objectid + 2 * BITMAP_RANGE, 373 BITMAP_RANGE); 374 if (ret) { 375 test_msg("Could not add free space\n"); 376 return ret; 377 } 378 379 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 380 cache->key.objectid + BITMAP_RANGE, 381 BITMAP_RANGE); 382 if (ret) { 383 test_msg("Could not add free space\n"); 384 return ret; 385 } 386 387 return check_free_space_extents(trans, fs_info, cache, path, 388 extents, ARRAY_SIZE(extents)); 389 } 390 391 static int test_merge_none(struct btrfs_trans_handle *trans, 392 struct btrfs_fs_info *fs_info, 393 struct btrfs_block_group_cache *cache, 394 struct btrfs_path *path) 395 { 396 struct free_space_extent extents[] = { 397 {cache->key.objectid, BITMAP_RANGE}, 398 {cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE}, 399 {cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE}, 400 }; 401 int ret; 402 403 ret = __remove_from_free_space_tree(trans, fs_info, cache, path, 404 cache->key.objectid, 405 cache->key.offset); 406 if (ret) { 407 test_msg("Could not remove free space\n"); 408 return ret; 409 } 410 411 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 412 cache->key.objectid, BITMAP_RANGE); 413 if (ret) { 414 test_msg("Could not add free space\n"); 415 return ret; 416 } 417 418 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 419 cache->key.objectid + 4 * BITMAP_RANGE, 420 BITMAP_RANGE); 421 if (ret) { 422 test_msg("Could not add free space\n"); 423 return ret; 424 } 425 426 ret = __add_to_free_space_tree(trans, fs_info, cache, path, 427 cache->key.objectid + 2 * BITMAP_RANGE, 428 BITMAP_RANGE); 429 if (ret) { 430 test_msg("Could not add free space\n"); 431 return ret; 432 } 433 434 return check_free_space_extents(trans, fs_info, cache, path, 435 extents, ARRAY_SIZE(extents)); 436 } 437 438 typedef int (*test_func_t)(struct btrfs_trans_handle *, 439 struct btrfs_fs_info *, 440 struct btrfs_block_group_cache *, 441 struct btrfs_path *); 442 443 static int run_test(test_func_t test_func, int bitmaps, 444 u32 sectorsize, u32 nodesize) 445 { 446 struct btrfs_fs_info *fs_info; 447 struct btrfs_root *root = NULL; 448 struct btrfs_block_group_cache *cache = NULL; 449 struct btrfs_trans_handle trans; 450 struct btrfs_path *path = NULL; 451 int ret; 452 453 fs_info = btrfs_alloc_dummy_fs_info(); 454 if (!fs_info) { 455 test_msg("Couldn't allocate dummy fs info\n"); 456 ret = -ENOMEM; 457 goto out; 458 } 459 460 root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize); 461 if (IS_ERR(root)) { 462 test_msg("Couldn't allocate dummy root\n"); 463 ret = PTR_ERR(root); 464 goto out; 465 } 466 467 btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, 468 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); 469 root->fs_info->free_space_root = root; 470 root->fs_info->tree_root = root; 471 472 root->node = alloc_test_extent_buffer(root->fs_info, 473 nodesize, nodesize); 474 if (!root->node) { 475 test_msg("Couldn't allocate dummy buffer\n"); 476 ret = -ENOMEM; 477 goto out; 478 } 479 btrfs_set_header_level(root->node, 0); 480 btrfs_set_header_nritems(root->node, 0); 481 root->alloc_bytenr += 2 * nodesize; 482 483 cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE, sectorsize); 484 if (!cache) { 485 test_msg("Couldn't allocate dummy block group cache\n"); 486 ret = -ENOMEM; 487 goto out; 488 } 489 cache->bitmap_low_thresh = 0; 490 cache->bitmap_high_thresh = (u32)-1; 491 cache->needs_free_space = 1; 492 cache->fs_info = root->fs_info; 493 494 btrfs_init_dummy_trans(&trans); 495 496 path = btrfs_alloc_path(); 497 if (!path) { 498 test_msg("Couldn't allocate path\n"); 499 return -ENOMEM; 500 } 501 502 ret = add_block_group_free_space(&trans, root->fs_info, cache); 503 if (ret) { 504 test_msg("Could not add block group free space\n"); 505 goto out; 506 } 507 508 if (bitmaps) { 509 ret = convert_free_space_to_bitmaps(&trans, root->fs_info, 510 cache, path); 511 if (ret) { 512 test_msg("Could not convert block group to bitmaps\n"); 513 goto out; 514 } 515 } 516 517 ret = test_func(&trans, root->fs_info, cache, path); 518 if (ret) 519 goto out; 520 521 ret = remove_block_group_free_space(&trans, root->fs_info, cache); 522 if (ret) { 523 test_msg("Could not remove block group free space\n"); 524 goto out; 525 } 526 527 if (btrfs_header_nritems(root->node) != 0) { 528 test_msg("Free space tree has leftover items\n"); 529 ret = -EINVAL; 530 goto out; 531 } 532 533 ret = 0; 534 out: 535 btrfs_free_path(path); 536 btrfs_free_dummy_block_group(cache); 537 btrfs_free_dummy_root(root); 538 btrfs_free_dummy_fs_info(fs_info); 539 return ret; 540 } 541 542 static int run_test_both_formats(test_func_t test_func, 543 u32 sectorsize, u32 nodesize) 544 { 545 int ret; 546 547 ret = run_test(test_func, 0, sectorsize, nodesize); 548 if (ret) 549 return ret; 550 return run_test(test_func, 1, sectorsize, nodesize); 551 } 552 553 int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) 554 { 555 test_func_t tests[] = { 556 test_empty_block_group, 557 test_remove_all, 558 test_remove_beginning, 559 test_remove_end, 560 test_remove_middle, 561 test_merge_left, 562 test_merge_right, 563 test_merge_both, 564 test_merge_none, 565 }; 566 int i; 567 568 test_msg("Running free space tree tests\n"); 569 for (i = 0; i < ARRAY_SIZE(tests); i++) { 570 int ret = run_test_both_formats(tests[i], sectorsize, 571 nodesize); 572 if (ret) { 573 test_msg("%pf : sectorsize %u failed\n", 574 tests[i], sectorsize); 575 return ret; 576 } 577 } 578 579 return 0; 580 } 581