free-space-tree-tests.c 16 KB

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