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 int insert_normal_tree_ref(struct btrfs_root
*root
, u64 bytenr
,
27 u64 num_bytes
, u64 parent
, u64 root_objectid
)
29 struct btrfs_trans_handle trans
;
30 struct btrfs_extent_item
*item
;
31 struct btrfs_extent_inline_ref
*iref
;
32 struct btrfs_tree_block_info
*block_info
;
33 struct btrfs_path
*path
;
34 struct extent_buffer
*leaf
;
36 u32 size
= sizeof(*item
) + sizeof(*iref
) + sizeof(*block_info
);
39 btrfs_init_dummy_trans(&trans
);
41 ins
.objectid
= bytenr
;
42 ins
.type
= BTRFS_EXTENT_ITEM_KEY
;
43 ins
.offset
= num_bytes
;
45 path
= btrfs_alloc_path();
47 test_msg("Couldn't allocate path\n");
51 path
->leave_spinning
= 1;
52 ret
= btrfs_insert_empty_item(&trans
, root
, path
, &ins
, size
);
54 test_msg("Couldn't insert ref %d\n", ret
);
55 btrfs_free_path(path
);
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);
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
);
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
);
75 btrfs_free_path(path
);
79 static int add_tree_ref(struct btrfs_root
*root
, u64 bytenr
, u64 num_bytes
,
80 u64 parent
, u64 root_objectid
)
82 struct btrfs_trans_handle trans
;
83 struct btrfs_extent_item
*item
;
84 struct btrfs_path
*path
;
89 btrfs_init_dummy_trans(&trans
);
91 key
.objectid
= bytenr
;
92 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
93 key
.offset
= num_bytes
;
95 path
= btrfs_alloc_path();
97 test_msg("Couldn't allocate path\n");
101 path
->leave_spinning
= 1;
102 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, 0, 1);
104 test_msg("Couldn't find extent ref\n");
105 btrfs_free_path(path
);
109 item
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
110 struct btrfs_extent_item
);
111 refs
= btrfs_extent_refs(path
->nodes
[0], item
);
112 btrfs_set_extent_refs(path
->nodes
[0], item
, refs
+ 1);
113 btrfs_release_path(path
);
115 key
.objectid
= bytenr
;
117 key
.type
= BTRFS_SHARED_BLOCK_REF_KEY
;
120 key
.type
= BTRFS_TREE_BLOCK_REF_KEY
;
121 key
.offset
= root_objectid
;
124 ret
= btrfs_insert_empty_item(&trans
, root
, path
, &key
, 0);
126 test_msg("Failed to insert backref\n");
127 btrfs_free_path(path
);
131 static int remove_extent_item(struct btrfs_root
*root
, u64 bytenr
,
134 struct btrfs_trans_handle trans
;
135 struct btrfs_key key
;
136 struct btrfs_path
*path
;
139 btrfs_init_dummy_trans(&trans
);
141 key
.objectid
= bytenr
;
142 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
143 key
.offset
= num_bytes
;
145 path
= btrfs_alloc_path();
147 test_msg("Couldn't allocate path\n");
150 path
->leave_spinning
= 1;
152 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, -1, 1);
154 test_msg("Didn't find our key %d\n", ret
);
155 btrfs_free_path(path
);
158 btrfs_del_item(&trans
, root
, path
);
159 btrfs_free_path(path
);
163 static int remove_extent_ref(struct btrfs_root
*root
, u64 bytenr
,
164 u64 num_bytes
, u64 parent
, u64 root_objectid
)
166 struct btrfs_trans_handle trans
;
167 struct btrfs_extent_item
*item
;
168 struct btrfs_path
*path
;
169 struct btrfs_key key
;
173 btrfs_init_dummy_trans(&trans
);
175 key
.objectid
= bytenr
;
176 key
.type
= BTRFS_EXTENT_ITEM_KEY
;
177 key
.offset
= num_bytes
;
179 path
= btrfs_alloc_path();
181 test_msg("Couldn't allocate path\n");
185 path
->leave_spinning
= 1;
186 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, 0, 1);
188 test_msg("Couldn't find extent ref\n");
189 btrfs_free_path(path
);
193 item
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
194 struct btrfs_extent_item
);
195 refs
= btrfs_extent_refs(path
->nodes
[0], item
);
196 btrfs_set_extent_refs(path
->nodes
[0], item
, refs
- 1);
197 btrfs_release_path(path
);
199 key
.objectid
= bytenr
;
201 key
.type
= BTRFS_SHARED_BLOCK_REF_KEY
;
204 key
.type
= BTRFS_TREE_BLOCK_REF_KEY
;
205 key
.offset
= root_objectid
;
208 ret
= btrfs_search_slot(&trans
, root
, &key
, path
, -1, 1);
210 test_msg("Couldn't find backref %d\n", ret
);
211 btrfs_free_path(path
);
214 btrfs_del_item(&trans
, root
, path
);
215 btrfs_free_path(path
);
219 static int test_no_shared_qgroup(struct btrfs_root
*root
)
221 struct btrfs_trans_handle trans
;
222 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
223 struct ulist
*old_roots
= NULL
;
224 struct ulist
*new_roots
= NULL
;
227 btrfs_init_dummy_trans(&trans
);
229 test_msg("Qgroup basic add\n");
230 ret
= btrfs_create_qgroup(NULL
, fs_info
, 5);
232 test_msg("Couldn't create a qgroup %d\n", ret
);
237 * Since the test trans doesn't havee the complicated delayed refs,
238 * we can only call btrfs_qgroup_account_extent() directly to test
241 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
243 ulist_free(old_roots
);
244 test_msg("Couldn't find old roots: %d\n", ret
);
248 ret
= insert_normal_tree_ref(root
, 4096, 4096, 0, 5);
252 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
254 ulist_free(old_roots
);
255 ulist_free(new_roots
);
256 test_msg("Couldn't find old roots: %d\n", ret
);
260 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
261 old_roots
, new_roots
);
263 test_msg("Couldn't account space for a qgroup %d\n", ret
);
267 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
268 test_msg("Qgroup counts didn't match expected values\n");
274 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
276 ulist_free(old_roots
);
277 test_msg("Couldn't find old roots: %d\n", ret
);
281 ret
= remove_extent_item(root
, 4096, 4096);
285 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
287 ulist_free(old_roots
);
288 ulist_free(new_roots
);
289 test_msg("Couldn't find old roots: %d\n", ret
);
293 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
294 old_roots
, new_roots
);
296 test_msg("Couldn't account space for a qgroup %d\n", ret
);
300 if (btrfs_verify_qgroup_counts(fs_info
, 5, 0, 0)) {
301 test_msg("Qgroup counts didn't match expected values\n");
309 * Add a ref for two different roots to make sure the shared value comes out
310 * right, also remove one of the roots and make sure the exclusive count is
313 static int test_multiple_refs(struct btrfs_root
*root
)
315 struct btrfs_trans_handle trans
;
316 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
317 struct ulist
*old_roots
= NULL
;
318 struct ulist
*new_roots
= NULL
;
321 btrfs_init_dummy_trans(&trans
);
323 test_msg("Qgroup multiple refs test\n");
325 /* We have 5 created already from the previous test */
326 ret
= btrfs_create_qgroup(NULL
, fs_info
, 256);
328 test_msg("Couldn't create a qgroup %d\n", ret
);
332 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
334 ulist_free(old_roots
);
335 test_msg("Couldn't find old roots: %d\n", ret
);
339 ret
= insert_normal_tree_ref(root
, 4096, 4096, 0, 5);
343 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
345 ulist_free(old_roots
);
346 ulist_free(new_roots
);
347 test_msg("Couldn't find old roots: %d\n", ret
);
351 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
352 old_roots
, new_roots
);
354 test_msg("Couldn't account space for a qgroup %d\n", ret
);
358 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
359 test_msg("Qgroup counts didn't match expected values\n");
363 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
365 ulist_free(old_roots
);
366 test_msg("Couldn't find old roots: %d\n", ret
);
370 ret
= add_tree_ref(root
, 4096, 4096, 0, 256);
374 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
376 ulist_free(old_roots
);
377 ulist_free(new_roots
);
378 test_msg("Couldn't find old roots: %d\n", ret
);
382 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
383 old_roots
, new_roots
);
385 test_msg("Couldn't account space for a qgroup %d\n", ret
);
389 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 0)) {
390 test_msg("Qgroup counts didn't match expected values\n");
394 if (btrfs_verify_qgroup_counts(fs_info
, 256, 4096, 0)) {
395 test_msg("Qgroup counts didn't match expected values\n");
399 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &old_roots
);
401 ulist_free(old_roots
);
402 test_msg("Couldn't find old roots: %d\n", ret
);
406 ret
= remove_extent_ref(root
, 4096, 4096, 0, 256);
410 ret
= btrfs_find_all_roots(&trans
, fs_info
, 4096, 0, &new_roots
);
412 ulist_free(old_roots
);
413 ulist_free(new_roots
);
414 test_msg("Couldn't find old roots: %d\n", ret
);
418 ret
= btrfs_qgroup_account_extent(&trans
, fs_info
, 4096, 4096,
419 old_roots
, new_roots
);
421 test_msg("Couldn't account space for a qgroup %d\n", ret
);
425 if (btrfs_verify_qgroup_counts(fs_info
, 256, 0, 0)) {
426 test_msg("Qgroup counts didn't match expected values\n");
430 if (btrfs_verify_qgroup_counts(fs_info
, 5, 4096, 4096)) {
431 test_msg("Qgroup counts didn't match expected values\n");
438 int btrfs_test_qgroups(void)
440 struct btrfs_root
*root
;
441 struct btrfs_root
*tmp_root
;
444 root
= btrfs_alloc_dummy_root();
446 test_msg("Couldn't allocate root\n");
447 return PTR_ERR(root
);
450 root
->fs_info
= btrfs_alloc_dummy_fs_info();
451 if (!root
->fs_info
) {
452 test_msg("Couldn't allocate dummy fs info\n");
456 /* We are using this root as our extent root */
457 root
->fs_info
->extent_root
= root
;
460 * Some of the paths we test assume we have a filled out fs_info, so we
461 * just need to add the root in there so we don't panic.
463 root
->fs_info
->tree_root
= root
;
464 root
->fs_info
->quota_root
= root
;
465 root
->fs_info
->quota_enabled
= 1;
468 * Can't use bytenr 0, some things freak out
469 * *cough*backref walking code*cough*
471 root
->node
= alloc_test_extent_buffer(root
->fs_info
, 4096);
473 test_msg("Couldn't allocate dummy buffer\n");
477 btrfs_set_header_level(root
->node
, 0);
478 btrfs_set_header_nritems(root
->node
, 0);
479 root
->alloc_bytenr
+= 8192;
481 tmp_root
= btrfs_alloc_dummy_root();
482 if (IS_ERR(tmp_root
)) {
483 test_msg("Couldn't allocate a fs root\n");
484 ret
= PTR_ERR(tmp_root
);
488 tmp_root
->root_key
.objectid
= 5;
489 root
->fs_info
->fs_root
= tmp_root
;
490 ret
= btrfs_insert_fs_root(root
->fs_info
, tmp_root
);
492 test_msg("Couldn't insert fs root %d\n", ret
);
496 tmp_root
= btrfs_alloc_dummy_root();
497 if (IS_ERR(tmp_root
)) {
498 test_msg("Couldn't allocate a fs root\n");
499 ret
= PTR_ERR(tmp_root
);
503 tmp_root
->root_key
.objectid
= 256;
504 ret
= btrfs_insert_fs_root(root
->fs_info
, tmp_root
);
506 test_msg("Couldn't insert fs root %d\n", ret
);
510 test_msg("Running qgroup tests\n");
511 ret
= test_no_shared_qgroup(root
);
514 ret
= test_multiple_refs(root
);
516 btrfs_free_dummy_root(root
);