qgroup-tests.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2013 Facebook. All rights reserved.
  4. */
  5. #include <linux/types.h>
  6. #include "btrfs-tests.h"
  7. #include "../ctree.h"
  8. #include "../transaction.h"
  9. #include "../disk-io.h"
  10. #include "../qgroup.h"
  11. #include "../backref.h"
  12. #include "../fs.h"
  13. #include "../accessors.h"
  14. static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
  15. u64 num_bytes, u64 parent, u64 root_objectid)
  16. {
  17. struct btrfs_trans_handle trans;
  18. struct btrfs_extent_item *item;
  19. struct btrfs_extent_inline_ref *iref;
  20. struct btrfs_tree_block_info *block_info;
  21. struct btrfs_path *path;
  22. struct extent_buffer *leaf;
  23. struct btrfs_key ins;
  24. u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
  25. int ret;
  26. btrfs_init_dummy_trans(&trans, NULL);
  27. ins.objectid = bytenr;
  28. ins.type = BTRFS_EXTENT_ITEM_KEY;
  29. ins.offset = num_bytes;
  30. path = btrfs_alloc_path();
  31. if (!path) {
  32. test_std_err(TEST_ALLOC_ROOT);
  33. return -ENOMEM;
  34. }
  35. ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
  36. if (ret) {
  37. test_err("couldn't insert ref %d", ret);
  38. btrfs_free_path(path);
  39. return ret;
  40. }
  41. leaf = path->nodes[0];
  42. item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
  43. btrfs_set_extent_refs(leaf, item, 1);
  44. btrfs_set_extent_generation(leaf, item, 1);
  45. btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
  46. block_info = (struct btrfs_tree_block_info *)(item + 1);
  47. btrfs_set_tree_block_level(leaf, block_info, 0);
  48. iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
  49. if (parent > 0) {
  50. btrfs_set_extent_inline_ref_type(leaf, iref,
  51. BTRFS_SHARED_BLOCK_REF_KEY);
  52. btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
  53. } else {
  54. btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);
  55. btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
  56. }
  57. btrfs_free_path(path);
  58. return 0;
  59. }
  60. static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
  61. u64 parent, u64 root_objectid)
  62. {
  63. struct btrfs_trans_handle trans;
  64. struct btrfs_extent_item *item;
  65. struct btrfs_path *path;
  66. struct btrfs_key key;
  67. u64 refs;
  68. int ret;
  69. btrfs_init_dummy_trans(&trans, NULL);
  70. key.objectid = bytenr;
  71. key.type = BTRFS_EXTENT_ITEM_KEY;
  72. key.offset = num_bytes;
  73. path = btrfs_alloc_path();
  74. if (!path) {
  75. test_std_err(TEST_ALLOC_ROOT);
  76. return -ENOMEM;
  77. }
  78. ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
  79. if (ret) {
  80. test_err("couldn't find extent ref");
  81. btrfs_free_path(path);
  82. return ret;
  83. }
  84. item = btrfs_item_ptr(path->nodes[0], path->slots[0],
  85. struct btrfs_extent_item);
  86. refs = btrfs_extent_refs(path->nodes[0], item);
  87. btrfs_set_extent_refs(path->nodes[0], item, refs + 1);
  88. btrfs_release_path(path);
  89. key.objectid = bytenr;
  90. if (parent) {
  91. key.type = BTRFS_SHARED_BLOCK_REF_KEY;
  92. key.offset = parent;
  93. } else {
  94. key.type = BTRFS_TREE_BLOCK_REF_KEY;
  95. key.offset = root_objectid;
  96. }
  97. ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);
  98. if (ret)
  99. test_err("failed to insert backref");
  100. btrfs_free_path(path);
  101. return ret;
  102. }
  103. static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
  104. u64 num_bytes)
  105. {
  106. struct btrfs_trans_handle trans;
  107. struct btrfs_key key;
  108. struct btrfs_path *path;
  109. int ret;
  110. btrfs_init_dummy_trans(&trans, NULL);
  111. key.objectid = bytenr;
  112. key.type = BTRFS_EXTENT_ITEM_KEY;
  113. key.offset = num_bytes;
  114. path = btrfs_alloc_path();
  115. if (!path) {
  116. test_std_err(TEST_ALLOC_ROOT);
  117. return -ENOMEM;
  118. }
  119. ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
  120. if (ret) {
  121. test_err("didn't find our key %d", ret);
  122. btrfs_free_path(path);
  123. return ret;
  124. }
  125. btrfs_del_item(&trans, root, path);
  126. btrfs_free_path(path);
  127. return 0;
  128. }
  129. static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
  130. u64 num_bytes, u64 parent, u64 root_objectid)
  131. {
  132. struct btrfs_trans_handle trans;
  133. struct btrfs_extent_item *item;
  134. struct btrfs_path *path;
  135. struct btrfs_key key;
  136. u64 refs;
  137. int ret;
  138. btrfs_init_dummy_trans(&trans, NULL);
  139. key.objectid = bytenr;
  140. key.type = BTRFS_EXTENT_ITEM_KEY;
  141. key.offset = num_bytes;
  142. path = btrfs_alloc_path();
  143. if (!path) {
  144. test_std_err(TEST_ALLOC_ROOT);
  145. return -ENOMEM;
  146. }
  147. ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
  148. if (ret) {
  149. test_err("couldn't find extent ref");
  150. btrfs_free_path(path);
  151. return ret;
  152. }
  153. item = btrfs_item_ptr(path->nodes[0], path->slots[0],
  154. struct btrfs_extent_item);
  155. refs = btrfs_extent_refs(path->nodes[0], item);
  156. btrfs_set_extent_refs(path->nodes[0], item, refs - 1);
  157. btrfs_release_path(path);
  158. key.objectid = bytenr;
  159. if (parent) {
  160. key.type = BTRFS_SHARED_BLOCK_REF_KEY;
  161. key.offset = parent;
  162. } else {
  163. key.type = BTRFS_TREE_BLOCK_REF_KEY;
  164. key.offset = root_objectid;
  165. }
  166. ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
  167. if (ret) {
  168. test_err("couldn't find backref %d", ret);
  169. btrfs_free_path(path);
  170. return ret;
  171. }
  172. btrfs_del_item(&trans, root, path);
  173. btrfs_free_path(path);
  174. return ret;
  175. }
  176. static int test_no_shared_qgroup(struct btrfs_root *root,
  177. u32 sectorsize, u32 nodesize)
  178. {
  179. struct btrfs_backref_walk_ctx ctx = { 0 };
  180. struct btrfs_trans_handle trans;
  181. struct btrfs_fs_info *fs_info = root->fs_info;
  182. struct ulist *old_roots = NULL;
  183. struct ulist *new_roots = NULL;
  184. int ret;
  185. btrfs_init_dummy_trans(&trans, fs_info);
  186. test_msg("running qgroup add/remove tests");
  187. ret = btrfs_create_qgroup(&trans, BTRFS_FS_TREE_OBJECTID);
  188. if (ret) {
  189. test_err("couldn't create a qgroup %d", ret);
  190. return ret;
  191. }
  192. ctx.bytenr = nodesize;
  193. ctx.trans = &trans;
  194. ctx.fs_info = fs_info;
  195. /*
  196. * Since the test trans doesn't have the complicated delayed refs,
  197. * we can only call btrfs_qgroup_account_extent() directly to test
  198. * quota.
  199. */
  200. ret = btrfs_find_all_roots(&ctx, false);
  201. if (ret) {
  202. test_err("couldn't find old roots: %d", ret);
  203. return ret;
  204. }
  205. old_roots = ctx.roots;
  206. ctx.roots = NULL;
  207. ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
  208. BTRFS_FS_TREE_OBJECTID);
  209. if (ret) {
  210. ulist_free(old_roots);
  211. return ret;
  212. }
  213. ret = btrfs_find_all_roots(&ctx, false);
  214. if (ret) {
  215. ulist_free(old_roots);
  216. test_err("couldn't find old roots: %d", ret);
  217. return ret;
  218. }
  219. new_roots = ctx.roots;
  220. ctx.roots = NULL;
  221. ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
  222. new_roots);
  223. if (ret) {
  224. test_err("couldn't account space for a qgroup %d", ret);
  225. return ret;
  226. }
  227. /* btrfs_qgroup_account_extent() always frees the ulists passed to it. */
  228. old_roots = NULL;
  229. new_roots = NULL;
  230. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
  231. nodesize, nodesize)) {
  232. test_err("qgroup counts didn't match expected values");
  233. return -EINVAL;
  234. }
  235. ret = btrfs_find_all_roots(&ctx, false);
  236. if (ret) {
  237. test_err("couldn't find old roots: %d", ret);
  238. return ret;
  239. }
  240. old_roots = ctx.roots;
  241. ctx.roots = NULL;
  242. ret = remove_extent_item(root, nodesize, nodesize);
  243. if (ret) {
  244. ulist_free(old_roots);
  245. return -EINVAL;
  246. }
  247. ret = btrfs_find_all_roots(&ctx, false);
  248. if (ret) {
  249. ulist_free(old_roots);
  250. test_err("couldn't find old roots: %d", ret);
  251. return ret;
  252. }
  253. new_roots = ctx.roots;
  254. ctx.roots = NULL;
  255. ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
  256. new_roots);
  257. if (ret) {
  258. test_err("couldn't account space for a qgroup %d", ret);
  259. return -EINVAL;
  260. }
  261. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 0, 0)) {
  262. test_err("qgroup counts didn't match expected values");
  263. return -EINVAL;
  264. }
  265. return 0;
  266. }
  267. /*
  268. * Add a ref for two different roots to make sure the shared value comes out
  269. * right, also remove one of the roots and make sure the exclusive count is
  270. * adjusted properly.
  271. */
  272. static int test_multiple_refs(struct btrfs_root *root,
  273. u32 sectorsize, u32 nodesize)
  274. {
  275. struct btrfs_backref_walk_ctx ctx = { 0 };
  276. struct btrfs_trans_handle trans;
  277. struct btrfs_fs_info *fs_info = root->fs_info;
  278. struct ulist *old_roots = NULL;
  279. struct ulist *new_roots = NULL;
  280. int ret;
  281. btrfs_init_dummy_trans(&trans, fs_info);
  282. test_msg("running qgroup multiple refs test");
  283. /*
  284. * We have BTRFS_FS_TREE_OBJECTID created already from the
  285. * previous test.
  286. */
  287. ret = btrfs_create_qgroup(&trans, BTRFS_FIRST_FREE_OBJECTID);
  288. if (ret) {
  289. test_err("couldn't create a qgroup %d", ret);
  290. return ret;
  291. }
  292. ctx.bytenr = nodesize;
  293. ctx.trans = &trans;
  294. ctx.fs_info = fs_info;
  295. ret = btrfs_find_all_roots(&ctx, false);
  296. if (ret) {
  297. test_err("couldn't find old roots: %d", ret);
  298. return ret;
  299. }
  300. old_roots = ctx.roots;
  301. ctx.roots = NULL;
  302. ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
  303. BTRFS_FS_TREE_OBJECTID);
  304. if (ret) {
  305. ulist_free(old_roots);
  306. return ret;
  307. }
  308. ret = btrfs_find_all_roots(&ctx, false);
  309. if (ret) {
  310. ulist_free(old_roots);
  311. test_err("couldn't find old roots: %d", ret);
  312. return ret;
  313. }
  314. new_roots = ctx.roots;
  315. ctx.roots = NULL;
  316. ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
  317. new_roots);
  318. if (ret) {
  319. test_err("couldn't account space for a qgroup %d", ret);
  320. return ret;
  321. }
  322. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
  323. nodesize, nodesize)) {
  324. test_err("qgroup counts didn't match expected values");
  325. return -EINVAL;
  326. }
  327. ret = btrfs_find_all_roots(&ctx, false);
  328. if (ret) {
  329. test_err("couldn't find old roots: %d", ret);
  330. return ret;
  331. }
  332. old_roots = ctx.roots;
  333. ctx.roots = NULL;
  334. ret = add_tree_ref(root, nodesize, nodesize, 0,
  335. BTRFS_FIRST_FREE_OBJECTID);
  336. if (ret) {
  337. ulist_free(old_roots);
  338. return ret;
  339. }
  340. ret = btrfs_find_all_roots(&ctx, false);
  341. if (ret) {
  342. ulist_free(old_roots);
  343. test_err("couldn't find old roots: %d", ret);
  344. return ret;
  345. }
  346. new_roots = ctx.roots;
  347. ctx.roots = NULL;
  348. ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
  349. new_roots);
  350. if (ret) {
  351. test_err("couldn't account space for a qgroup %d", ret);
  352. return ret;
  353. }
  354. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
  355. nodesize, 0)) {
  356. test_err("qgroup counts didn't match expected values");
  357. return -EINVAL;
  358. }
  359. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
  360. nodesize, 0)) {
  361. test_err("qgroup counts didn't match expected values");
  362. return -EINVAL;
  363. }
  364. ret = btrfs_find_all_roots(&ctx, false);
  365. if (ret) {
  366. test_err("couldn't find old roots: %d", ret);
  367. return ret;
  368. }
  369. old_roots = ctx.roots;
  370. ctx.roots = NULL;
  371. ret = remove_extent_ref(root, nodesize, nodesize, 0,
  372. BTRFS_FIRST_FREE_OBJECTID);
  373. if (ret) {
  374. ulist_free(old_roots);
  375. return ret;
  376. }
  377. ret = btrfs_find_all_roots(&ctx, false);
  378. if (ret) {
  379. ulist_free(old_roots);
  380. test_err("couldn't find old roots: %d", ret);
  381. return ret;
  382. }
  383. new_roots = ctx.roots;
  384. ctx.roots = NULL;
  385. ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots,
  386. new_roots);
  387. if (ret) {
  388. test_err("couldn't account space for a qgroup %d", ret);
  389. return ret;
  390. }
  391. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
  392. 0, 0)) {
  393. test_err("qgroup counts didn't match expected values");
  394. return -EINVAL;
  395. }
  396. if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
  397. nodesize, nodesize)) {
  398. test_err("qgroup counts didn't match expected values");
  399. return -EINVAL;
  400. }
  401. return 0;
  402. }
  403. int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
  404. {
  405. struct btrfs_fs_info *fs_info = NULL;
  406. struct btrfs_root *root;
  407. struct btrfs_root *tmp_root;
  408. int ret = 0;
  409. fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
  410. if (!fs_info) {
  411. test_std_err(TEST_ALLOC_FS_INFO);
  412. return -ENOMEM;
  413. }
  414. root = btrfs_alloc_dummy_root(fs_info);
  415. if (IS_ERR(root)) {
  416. test_std_err(TEST_ALLOC_ROOT);
  417. ret = PTR_ERR(root);
  418. goto out;
  419. }
  420. /* We are using this root as our extent root */
  421. root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID;
  422. root->root_key.type = BTRFS_ROOT_ITEM_KEY;
  423. root->root_key.offset = 0;
  424. btrfs_global_root_insert(root);
  425. /*
  426. * Some of the paths we test assume we have a filled out fs_info, so we
  427. * just need to add the root in there so we don't panic.
  428. */
  429. root->fs_info->tree_root = root;
  430. root->fs_info->quota_root = root;
  431. set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
  432. /*
  433. * Can't use bytenr 0, some things freak out
  434. * *cough*backref walking code*cough*
  435. */
  436. root->node = alloc_test_extent_buffer(root->fs_info, nodesize);
  437. if (IS_ERR(root->node)) {
  438. test_err("couldn't allocate dummy buffer");
  439. ret = PTR_ERR(root->node);
  440. goto out;
  441. }
  442. btrfs_set_header_level(root->node, 0);
  443. btrfs_set_header_nritems(root->node, 0);
  444. root->alloc_bytenr += 2 * nodesize;
  445. tmp_root = btrfs_alloc_dummy_root(fs_info);
  446. if (IS_ERR(tmp_root)) {
  447. test_std_err(TEST_ALLOC_ROOT);
  448. ret = PTR_ERR(tmp_root);
  449. goto out;
  450. }
  451. tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID;
  452. root->fs_info->fs_root = tmp_root;
  453. ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
  454. if (ret) {
  455. test_err("couldn't insert fs root %d", ret);
  456. goto out;
  457. }
  458. btrfs_put_root(tmp_root);
  459. tmp_root = btrfs_alloc_dummy_root(fs_info);
  460. if (IS_ERR(tmp_root)) {
  461. test_std_err(TEST_ALLOC_ROOT);
  462. ret = PTR_ERR(tmp_root);
  463. goto out;
  464. }
  465. tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID;
  466. ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
  467. if (ret) {
  468. test_err("couldn't insert fs root %d", ret);
  469. goto out;
  470. }
  471. btrfs_put_root(tmp_root);
  472. test_msg("running qgroup tests");
  473. ret = test_no_shared_qgroup(root, sectorsize, nodesize);
  474. if (ret)
  475. goto out;
  476. ret = test_multiple_refs(root, sectorsize, nodesize);
  477. out:
  478. btrfs_free_dummy_root(root);
  479. btrfs_free_dummy_fs_info(fs_info);
  480. return ret;
  481. }