qgroup-tests.c 13 KB

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