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, 1);
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);
481 test_msg("Couldn't allocate dummy buffer\n");
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);