qgroup-tests.c 13 KB

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