blob: 846d277b190137065a6f49192c9035486aab2241 [file] [log] [blame]
Josef Bacikfaa2dbf2014-05-07 17:06:09 -04001/*
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
19#include "btrfs-tests.h"
20#include "../ctree.h"
21#include "../transaction.h"
22#include "../disk-io.h"
23#include "../qgroup.h"
Qu Wenruo442244c2015-04-16 17:18:36 +080024#include "../backref.h"
Josef Bacikfaa2dbf2014-05-07 17:06:09 -040025
26static void init_dummy_trans(struct btrfs_trans_handle *trans)
27{
28 memset(trans, 0, sizeof(*trans));
29 trans->transid = 1;
30 INIT_LIST_HEAD(&trans->qgroup_ref_list);
31 trans->type = __TRANS_DUMMY;
32}
33
34static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
35 u64 num_bytes, u64 parent, u64 root_objectid)
36{
37 struct btrfs_trans_handle trans;
38 struct btrfs_extent_item *item;
39 struct btrfs_extent_inline_ref *iref;
40 struct btrfs_tree_block_info *block_info;
41 struct btrfs_path *path;
42 struct extent_buffer *leaf;
43 struct btrfs_key ins;
44 u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
45 int ret;
46
47 init_dummy_trans(&trans);
48
49 ins.objectid = bytenr;
50 ins.type = BTRFS_EXTENT_ITEM_KEY;
51 ins.offset = num_bytes;
52
53 path = btrfs_alloc_path();
54 if (!path) {
55 test_msg("Couldn't allocate path\n");
56 return -ENOMEM;
57 }
58
59 path->leave_spinning = 1;
60 ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
61 if (ret) {
62 test_msg("Couldn't insert ref %d\n", ret);
63 btrfs_free_path(path);
64 return ret;
65 }
66
67 leaf = path->nodes[0];
68 item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
69 btrfs_set_extent_refs(leaf, item, 1);
70 btrfs_set_extent_generation(leaf, item, 1);
71 btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
72 block_info = (struct btrfs_tree_block_info *)(item + 1);
73 btrfs_set_tree_block_level(leaf, block_info, 1);
74 iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
75 if (parent > 0) {
76 btrfs_set_extent_inline_ref_type(leaf, iref,
77 BTRFS_SHARED_BLOCK_REF_KEY);
78 btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
79 } else {
80 btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);
81 btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
82 }
83 btrfs_free_path(path);
84 return 0;
85}
86
87static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
88 u64 parent, u64 root_objectid)
89{
90 struct btrfs_trans_handle trans;
91 struct btrfs_extent_item *item;
92 struct btrfs_path *path;
93 struct btrfs_key key;
94 u64 refs;
95 int ret;
96
97 init_dummy_trans(&trans);
98
99 key.objectid = bytenr;
100 key.type = BTRFS_EXTENT_ITEM_KEY;
101 key.offset = num_bytes;
102
103 path = btrfs_alloc_path();
104 if (!path) {
105 test_msg("Couldn't allocate path\n");
106 return -ENOMEM;
107 }
108
109 path->leave_spinning = 1;
110 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
111 if (ret) {
112 test_msg("Couldn't find extent ref\n");
113 btrfs_free_path(path);
114 return ret;
115 }
116
117 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
118 struct btrfs_extent_item);
119 refs = btrfs_extent_refs(path->nodes[0], item);
120 btrfs_set_extent_refs(path->nodes[0], item, refs + 1);
121 btrfs_release_path(path);
122
123 key.objectid = bytenr;
124 if (parent) {
125 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
126 key.offset = parent;
127 } else {
128 key.type = BTRFS_TREE_BLOCK_REF_KEY;
129 key.offset = root_objectid;
130 }
131
132 ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);
133 if (ret)
134 test_msg("Failed to insert backref\n");
135 btrfs_free_path(path);
136 return ret;
137}
138
139static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
140 u64 num_bytes)
141{
142 struct btrfs_trans_handle trans;
143 struct btrfs_key key;
144 struct btrfs_path *path;
145 int ret;
146
147 init_dummy_trans(&trans);
148
149 key.objectid = bytenr;
150 key.type = BTRFS_EXTENT_ITEM_KEY;
151 key.offset = num_bytes;
152
153 path = btrfs_alloc_path();
154 if (!path) {
155 test_msg("Couldn't allocate path\n");
156 return -ENOMEM;
157 }
158 path->leave_spinning = 1;
159
160 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
161 if (ret) {
162 test_msg("Didn't find our key %d\n", ret);
163 btrfs_free_path(path);
164 return ret;
165 }
166 btrfs_del_item(&trans, root, path);
167 btrfs_free_path(path);
168 return 0;
169}
170
171static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
172 u64 num_bytes, u64 parent, u64 root_objectid)
173{
174 struct btrfs_trans_handle trans;
175 struct btrfs_extent_item *item;
176 struct btrfs_path *path;
177 struct btrfs_key key;
178 u64 refs;
179 int ret;
180
181 init_dummy_trans(&trans);
182
183 key.objectid = bytenr;
184 key.type = BTRFS_EXTENT_ITEM_KEY;
185 key.offset = num_bytes;
186
187 path = btrfs_alloc_path();
188 if (!path) {
189 test_msg("Couldn't allocate path\n");
190 return -ENOMEM;
191 }
192
193 path->leave_spinning = 1;
194 ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
195 if (ret) {
196 test_msg("Couldn't find extent ref\n");
197 btrfs_free_path(path);
198 return ret;
199 }
200
201 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
202 struct btrfs_extent_item);
203 refs = btrfs_extent_refs(path->nodes[0], item);
204 btrfs_set_extent_refs(path->nodes[0], item, refs - 1);
205 btrfs_release_path(path);
206
207 key.objectid = bytenr;
208 if (parent) {
209 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
210 key.offset = parent;
211 } else {
212 key.type = BTRFS_TREE_BLOCK_REF_KEY;
213 key.offset = root_objectid;
214 }
215
216 ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
217 if (ret) {
218 test_msg("Couldn't find backref %d\n", ret);
219 btrfs_free_path(path);
220 return ret;
221 }
222 btrfs_del_item(&trans, root, path);
223 btrfs_free_path(path);
224 return ret;
225}
226
227static int test_no_shared_qgroup(struct btrfs_root *root)
228{
229 struct btrfs_trans_handle trans;
230 struct btrfs_fs_info *fs_info = root->fs_info;
Qu Wenruo442244c2015-04-16 17:18:36 +0800231 struct ulist *old_roots = NULL;
232 struct ulist *new_roots = NULL;
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400233 int ret;
234
235 init_dummy_trans(&trans);
236
237 test_msg("Qgroup basic add\n");
Dongsheng Yang4087cf22015-01-18 10:59:23 -0500238 ret = btrfs_create_qgroup(NULL, fs_info, 5);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400239 if (ret) {
240 test_msg("Couldn't create a qgroup %d\n", ret);
241 return ret;
242 }
243
Qu Wenruo442244c2015-04-16 17:18:36 +0800244 /*
245 * Since the test trans doesn't havee the complicated delayed refs,
246 * we can only call btrfs_qgroup_account_extent() directly to test
247 * quota.
248 */
249 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400250 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800251 ulist_free(old_roots);
252 test_msg("Couldn't find old roots: %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400253 return ret;
254 }
255
256 ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
257 if (ret)
258 return ret;
259
Qu Wenruo442244c2015-04-16 17:18:36 +0800260 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400261 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800262 ulist_free(old_roots);
263 ulist_free(new_roots);
264 test_msg("Couldn't find old roots: %d\n", ret);
265 return ret;
266 }
267
268 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
269 old_roots, new_roots);
270 if (ret) {
271 test_msg("Couldn't account space for a qgroup %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400272 return ret;
273 }
274
275 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
276 test_msg("Qgroup counts didn't match expected values\n");
277 return -EINVAL;
278 }
Qu Wenruo442244c2015-04-16 17:18:36 +0800279 old_roots = NULL;
280 new_roots = NULL;
281
282 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
283 if (ret) {
284 ulist_free(old_roots);
285 test_msg("Couldn't find old roots: %d\n", ret);
286 return ret;
287 }
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400288
289 ret = remove_extent_item(root, 4096, 4096);
290 if (ret)
291 return -EINVAL;
292
Qu Wenruo442244c2015-04-16 17:18:36 +0800293 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400294 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800295 ulist_free(old_roots);
296 ulist_free(new_roots);
297 test_msg("Couldn't find old roots: %d\n", ret);
298 return ret;
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400299 }
300
Qu Wenruo442244c2015-04-16 17:18:36 +0800301 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
302 old_roots, new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400303 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800304 test_msg("Couldn't account space for a qgroup %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400305 return -EINVAL;
306 }
307
308 if (btrfs_verify_qgroup_counts(fs_info, 5, 0, 0)) {
309 test_msg("Qgroup counts didn't match expected values\n");
310 return -EINVAL;
311 }
312
313 return 0;
314}
315
316/*
317 * Add a ref for two different roots to make sure the shared value comes out
318 * right, also remove one of the roots and make sure the exclusive count is
319 * adjusted properly.
320 */
321static int test_multiple_refs(struct btrfs_root *root)
322{
323 struct btrfs_trans_handle trans;
324 struct btrfs_fs_info *fs_info = root->fs_info;
Qu Wenruo442244c2015-04-16 17:18:36 +0800325 struct ulist *old_roots = NULL;
326 struct ulist *new_roots = NULL;
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400327 int ret;
328
329 init_dummy_trans(&trans);
330
331 test_msg("Qgroup multiple refs test\n");
332
333 /* We have 5 created already from the previous test */
Dongsheng Yang4087cf22015-01-18 10:59:23 -0500334 ret = btrfs_create_qgroup(NULL, fs_info, 256);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400335 if (ret) {
336 test_msg("Couldn't create a qgroup %d\n", ret);
337 return ret;
338 }
339
Qu Wenruo442244c2015-04-16 17:18:36 +0800340 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
341 if (ret) {
342 ulist_free(old_roots);
343 test_msg("Couldn't find old roots: %d\n", ret);
344 return ret;
345 }
346
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400347 ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
348 if (ret)
349 return ret;
350
Qu Wenruo442244c2015-04-16 17:18:36 +0800351 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400352 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800353 ulist_free(old_roots);
354 ulist_free(new_roots);
355 test_msg("Couldn't find old roots: %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400356 return ret;
357 }
358
Qu Wenruo442244c2015-04-16 17:18:36 +0800359 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
360 old_roots, new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400361 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800362 test_msg("Couldn't account space for a qgroup %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400363 return ret;
364 }
365
366 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
367 test_msg("Qgroup counts didn't match expected values\n");
368 return -EINVAL;
369 }
370
Qu Wenruo442244c2015-04-16 17:18:36 +0800371 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
372 if (ret) {
373 ulist_free(old_roots);
374 test_msg("Couldn't find old roots: %d\n", ret);
375 return ret;
376 }
377
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400378 ret = add_tree_ref(root, 4096, 4096, 0, 256);
379 if (ret)
380 return ret;
381
Qu Wenruo442244c2015-04-16 17:18:36 +0800382 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400383 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800384 ulist_free(old_roots);
385 ulist_free(new_roots);
386 test_msg("Couldn't find old roots: %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400387 return ret;
388 }
389
Qu Wenruo442244c2015-04-16 17:18:36 +0800390 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
391 old_roots, new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400392 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800393 test_msg("Couldn't account space for a qgroup %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400394 return ret;
395 }
396
397 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 0)) {
398 test_msg("Qgroup counts didn't match expected values\n");
399 return -EINVAL;
400 }
401
402 if (btrfs_verify_qgroup_counts(fs_info, 256, 4096, 0)) {
403 test_msg("Qgroup counts didn't match expected values\n");
404 return -EINVAL;
405 }
406
Qu Wenruo442244c2015-04-16 17:18:36 +0800407 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
408 if (ret) {
409 ulist_free(old_roots);
410 test_msg("Couldn't find old roots: %d\n", ret);
411 return ret;
412 }
413
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400414 ret = remove_extent_ref(root, 4096, 4096, 0, 256);
415 if (ret)
416 return ret;
417
Qu Wenruo442244c2015-04-16 17:18:36 +0800418 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400419 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800420 ulist_free(old_roots);
421 ulist_free(new_roots);
422 test_msg("Couldn't find old roots: %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400423 return ret;
424 }
425
Qu Wenruo442244c2015-04-16 17:18:36 +0800426 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
427 old_roots, new_roots);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400428 if (ret) {
Qu Wenruo442244c2015-04-16 17:18:36 +0800429 test_msg("Couldn't account space for a qgroup %d\n", ret);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400430 return ret;
431 }
432
433 if (btrfs_verify_qgroup_counts(fs_info, 256, 0, 0)) {
434 test_msg("Qgroup counts didn't match expected values\n");
435 return -EINVAL;
436 }
437
438 if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
439 test_msg("Qgroup counts didn't match expected values\n");
440 return -EINVAL;
441 }
442
443 return 0;
444}
445
446int btrfs_test_qgroups(void)
447{
448 struct btrfs_root *root;
449 struct btrfs_root *tmp_root;
450 int ret = 0;
451
452 root = btrfs_alloc_dummy_root();
453 if (IS_ERR(root)) {
454 test_msg("Couldn't allocate root\n");
455 return PTR_ERR(root);
456 }
457
458 root->fs_info = btrfs_alloc_dummy_fs_info();
459 if (!root->fs_info) {
460 test_msg("Couldn't allocate dummy fs info\n");
461 ret = -ENOMEM;
462 goto out;
463 }
David Sterba3f556f72014-06-15 03:20:26 +0200464 /* We are using this root as our extent root */
465 root->fs_info->extent_root = root;
466
467 /*
468 * Some of the paths we test assume we have a filled out fs_info, so we
469 * just need to add the root in there so we don't panic.
470 */
471 root->fs_info->tree_root = root;
472 root->fs_info->quota_root = root;
473 root->fs_info->quota_enabled = 1;
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400474
475 /*
476 * Can't use bytenr 0, some things freak out
477 * *cough*backref walking code*cough*
478 */
David Sterbace3e6982014-06-15 03:00:04 +0200479 root->node = alloc_test_extent_buffer(root->fs_info, 4096);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400480 if (!root->node) {
481 test_msg("Couldn't allocate dummy buffer\n");
482 ret = -ENOMEM;
483 goto out;
484 }
Filipe Mananab050f9f2014-06-12 02:47:37 +0100485 btrfs_set_header_level(root->node, 0);
486 btrfs_set_header_nritems(root->node, 0);
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400487 root->alloc_bytenr += 8192;
488
489 tmp_root = btrfs_alloc_dummy_root();
490 if (IS_ERR(tmp_root)) {
491 test_msg("Couldn't allocate a fs root\n");
492 ret = PTR_ERR(tmp_root);
493 goto out;
494 }
495
496 tmp_root->root_key.objectid = 5;
497 root->fs_info->fs_root = tmp_root;
498 ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
499 if (ret) {
500 test_msg("Couldn't insert fs root %d\n", ret);
501 goto out;
502 }
503
504 tmp_root = btrfs_alloc_dummy_root();
505 if (IS_ERR(tmp_root)) {
506 test_msg("Couldn't allocate a fs root\n");
507 ret = PTR_ERR(tmp_root);
508 goto out;
509 }
510
511 tmp_root->root_key.objectid = 256;
512 ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
513 if (ret) {
514 test_msg("Couldn't insert fs root %d\n", ret);
515 goto out;
516 }
517
Josef Bacikfaa2dbf2014-05-07 17:06:09 -0400518 test_msg("Running qgroup tests\n");
519 ret = test_no_shared_qgroup(root);
520 if (ret)
521 goto out;
522 ret = test_multiple_refs(root);
523out:
524 btrfs_free_dummy_root(root);
525 return ret;
526}