2 * Copyright (C) 2013 Facebook. All rights reserved.
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.
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.
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.
19 #include "btrfs-tests.h"
21 #include "../transaction.h"
22 #include "../disk-io.h"
23 #include "../qgroup.h"
24 #include "../backref.h"
26 static void init_dummy_trans(struct btrfs_trans_handle
*trans
)
28 memset(trans
, 0, sizeof(*trans
));
30 INIT_LIST_HEAD(&trans
->qgroup_ref_list
);
31 trans
->type
= __TRANS_DUMMY
;
34 static int insert_normal_tree_ref(struct btrfs_root
*root
, u64 bytenr
,
35 u64 num_bytes
, u64 parent
, u64 root_objectid
)
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
;
44 u32 size
= sizeof(*item
) + sizeof(*iref
) + sizeof(*block_info
);
47 init_dummy_trans(&trans
);
49 ins
.objectid
= bytenr
;
50 ins
.type
= BTRFS_EXTENT_ITEM_KEY
;
51 ins
.offset
= num_bytes
;
53 path
= btrfs_alloc_path();
55 test_msg("Couldn't allocate path\n");
59 path
->leave_spinning
= 1;
60 ret
= btrfs_insert_empty_item(&trans
, root
, path
, &ins
, size
);
62 test_msg("Couldn't insert ref %d\n", ret
);
63 btrfs_free_path(path
);
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
, 0);
74 iref
= (struct btrfs_extent_inline_ref
*)(block_info
+ 1);
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
);
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
);
83 btrfs_free_path(path
);
87 static int add_tree_ref(struct btrfs_root
*root
, u64 bytenr
, u64 num_bytes
,
88 u64 parent
, u64 root_objectid
)
90 struct btrfs_trans_handle trans
;
91 struct btrfs_extent_item
*item
;
92 struct btrfs_path
*path
;
97 init_dummy_trans(&trans
);
99 key
.objectid
= bytenr
;
100 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
101 key
.offset
= num_bytes
;
103 path
= btrfs_alloc_path();
105 test_msg("Couldn't allocate path\n");
109 path
->leave_spinning
= 1;
110 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, 0, 1);
112 test_msg("Couldn't find extent ref\n");
113 btrfs_free_path(path
);
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
);
123 key
.objectid
= bytenr
;
125 key
.type
= BTRFS_SHARED_BLOCK_REF_KEY
;
128 key
.type
= BTRFS_TREE_BLOCK_REF_KEY
;
129 key
.offset
= root_objectid
;
132 ret
= btrfs_insert_empty_item(&trans
, root
, path
, &key
, 0);
134 test_msg("Failed to insert backref\n");
135 btrfs_free_path(path
);
139 static int remove_extent_item(struct btrfs_root
*root
, u64 bytenr
,
142 struct btrfs_trans_handle trans
;
143 struct btrfs_key key
;
144 struct btrfs_path
*path
;
147 init_dummy_trans(&trans
);
149 key
.objectid
= bytenr
;
150 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
151 key
.offset
= num_bytes
;
153 path
= btrfs_alloc_path();
155 test_msg("Couldn't allocate path\n");
158 path
->leave_spinning
= 1;
160 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, -1, 1);
162 test_msg("Didn't find our key %d\n", ret
);
163 btrfs_free_path(path
);
166 btrfs_del_item(&trans
, root
, path
);
167 btrfs_free_path(path
);
171 static int remove_extent_ref(struct btrfs_root
*root
, u64 bytenr
,
172 u64 num_bytes
, u64 parent
, u64 root_objectid
)
174 struct btrfs_trans_handle trans
;
175 struct btrfs_extent_item
*item
;
176 struct btrfs_path
*path
;
177 struct btrfs_key key
;
181 init_dummy_trans(&trans
);
183 key
.objectid
= bytenr
;
184 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
185 key
.offset
= num_bytes
;
187 path
= btrfs_alloc_path();
189 test_msg("Couldn't allocate path\n");
193 path
->leave_spinning
= 1;
194 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, 0, 1);
196 test_msg("Couldn't find extent ref\n");
197 btrfs_free_path(path
);
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
);
207 key
.objectid
= bytenr
;
209 key
.type
= BTRFS_SHARED_BLOCK_REF_KEY
;
212 key
.type
= BTRFS_TREE_BLOCK_REF_KEY
;
213 key
.offset
= root_objectid
;
216 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, -1, 1);
218 test_msg("Couldn't find backref %d\n", ret
);
219 btrfs_free_path(path
);
222 btrfs_del_item(&trans
, root
, path
);
223 btrfs_free_path(path
);
227 static int test_no_shared_qgroup(struct btrfs_root
*root
)
229 struct btrfs_trans_handle trans
;
230 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
231 struct ulist
*old_roots
= NULL
;
232 struct ulist
*new_roots
= NULL
;
235 init_dummy_trans(&trans
);
237 test_msg("Qgroup basic add\n");
238 ret
= btrfs_create_qgroup(NULL
, fs_info
, 5);
240 test_msg("Couldn't create a qgroup %d\n", ret
);
245 * Since the test trans doesn't havee the complicated delayed refs,
246 * we can only call btrfs_qgroup_account_extent() directly to test
249 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
251 ulist_free(old_roots
);
252 test_msg("Couldn't find old roots: %d\n", ret
);
256 ret
= insert_normal_tree_ref(root
, 4096, 4096, 0, 5);
260 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
262 ulist_free(old_roots
);
263 ulist_free(new_roots
);
264 test_msg("Couldn't find old roots: %d\n", ret
);
268 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
269 old_roots
, new_roots
);
271 test_msg("Couldn't account space for a qgroup %d\n", ret
);
275 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
276 test_msg("Qgroup counts didn't match expected values\n");
282 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
284 ulist_free(old_roots
);
285 test_msg("Couldn't find old roots: %d\n", ret
);
289 ret
= remove_extent_item(root
, 4096, 4096);
293 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
295 ulist_free(old_roots
);
296 ulist_free(new_roots
);
297 test_msg("Couldn't find old roots: %d\n", ret
);
301 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
302 old_roots
, new_roots
);
304 test_msg("Couldn't account space for a qgroup %d\n", ret
);
308 if (btrfs_verify_qgroup_counts(fs_info
, 5, 0, 0)) {
309 test_msg("Qgroup counts didn't match expected values\n");
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
321 static int test_multiple_refs(struct btrfs_root
*root
)
323 struct btrfs_trans_handle trans
;
324 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
325 struct ulist
*old_roots
= NULL
;
326 struct ulist
*new_roots
= NULL
;
329 init_dummy_trans(&trans
);
331 test_msg("Qgroup multiple refs test\n");
333 /* We have 5 created already from the previous test */
334 ret
= btrfs_create_qgroup(NULL
, fs_info
, 256);
336 test_msg("Couldn't create a qgroup %d\n", ret
);
340 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
342 ulist_free(old_roots
);
343 test_msg("Couldn't find old roots: %d\n", ret
);
347 ret
= insert_normal_tree_ref(root
, 4096, 4096, 0, 5);
351 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
353 ulist_free(old_roots
);
354 ulist_free(new_roots
);
355 test_msg("Couldn't find old roots: %d\n", ret
);
359 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
360 old_roots
, new_roots
);
362 test_msg("Couldn't account space for a qgroup %d\n", ret
);
366 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
367 test_msg("Qgroup counts didn't match expected values\n");
371 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
373 ulist_free(old_roots
);
374 test_msg("Couldn't find old roots: %d\n", ret
);
378 ret
= add_tree_ref(root
, 4096, 4096, 0, 256);
382 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
384 ulist_free(old_roots
);
385 ulist_free(new_roots
);
386 test_msg("Couldn't find old roots: %d\n", ret
);
390 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
391 old_roots
, new_roots
);
393 test_msg("Couldn't account space for a qgroup %d\n", ret
);
397 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 0)) {
398 test_msg("Qgroup counts didn't match expected values\n");
402 if (btrfs_verify_qgroup_counts(fs_info
, 256, 4096, 0)) {
403 test_msg("Qgroup counts didn't match expected values\n");
407 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
409 ulist_free(old_roots
);
410 test_msg("Couldn't find old roots: %d\n", ret
);
414 ret
= remove_extent_ref(root
, 4096, 4096, 0, 256);
418 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
420 ulist_free(old_roots
);
421 ulist_free(new_roots
);
422 test_msg("Couldn't find old roots: %d\n", ret
);
426 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
427 old_roots
, new_roots
);
429 test_msg("Couldn't account space for a qgroup %d\n", ret
);
433 if (btrfs_verify_qgroup_counts(fs_info
, 256, 0, 0)) {
434 test_msg("Qgroup counts didn't match expected values\n");
438 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
439 test_msg("Qgroup counts didn't match expected values\n");
446 int btrfs_test_qgroups(void)
448 struct btrfs_root
*root
;
449 struct btrfs_root
*tmp_root
;
452 root
= btrfs_alloc_dummy_root();
454 test_msg("Couldn't allocate root\n");
455 return PTR_ERR(root
);
458 root
->fs_info
= btrfs_alloc_dummy_fs_info();
459 if (!root
->fs_info
) {
460 test_msg("Couldn't allocate dummy fs info\n");
464 /* We are using this root as our extent root */
465 root
->fs_info
->extent_root
= root
;
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.
471 root
->fs_info
->tree_root
= root
;
472 root
->fs_info
->quota_root
= root
;
473 root
->fs_info
->quota_enabled
= 1;
476 * Can't use bytenr 0, some things freak out
477 * *cough*backref walking code*cough*
479 root
->node
= alloc_test_extent_buffer(root
->fs_info
, 4096);
480 if (IS_ERR(root
->node
)) {
481 test_msg("Couldn't allocate dummy buffer\n");
482 ret
= PTR_ERR(root
->node
);
485 btrfs_set_header_level(root
->node
, 0);
486 btrfs_set_header_nritems(root
->node
, 0);
487 root
->alloc_bytenr
+= 8192;
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
);
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
);
500 test_msg("Couldn't insert fs root %d\n", ret
);
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
);
511 tmp_root
->root_key
.objectid
= 256;
512 ret
= btrfs_insert_fs_root(root
->fs_info
, tmp_root
);
514 test_msg("Couldn't insert fs root %d\n", ret
);
518 test_msg("Running qgroup tests\n");
519 ret
= test_no_shared_qgroup(root
);
522 ret
= test_multiple_refs(root
);
524 btrfs_free_dummy_root(root
);