HID: hiddev: Fix slab-out-of-bounds write in hiddev_ioctl_usage()
[linux/fpc-iii.git] / fs / btrfs / tests / qgroup-tests.c
blob1efec40455f807d53fb87d178c1155501d0a1759
1 /*
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"
20 #include "../ctree.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));
29 trans->transid = 1;
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;
43 struct btrfs_key ins;
44 u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
45 int ret;
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();
54 if (!path) {
55 test_msg("Couldn't allocate path\n");
56 return -ENOMEM;
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;
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);
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);
83 btrfs_free_path(path);
84 return 0;
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;
93 struct btrfs_key key;
94 u64 refs;
95 int ret;
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();
104 if (!path) {
105 test_msg("Couldn't allocate path\n");
106 return -ENOMEM;
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;
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;
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;
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;
139 static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
140 u64 num_bytes)
142 struct btrfs_trans_handle trans;
143 struct btrfs_key key;
144 struct btrfs_path *path;
145 int ret;
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();
154 if (!path) {
155 test_msg("Couldn't allocate path\n");
156 return -ENOMEM;
158 path->leave_spinning = 1;
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;
166 btrfs_del_item(&trans, root, path);
167 btrfs_free_path(path);
168 return 0;
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;
178 u64 refs;
179 int ret;
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();
188 if (!path) {
189 test_msg("Couldn't allocate path\n");
190 return -ENOMEM;
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;
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;
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;
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;
222 btrfs_del_item(&trans, root, path);
223 btrfs_free_path(path);
224 return ret;
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;
233 int ret;
235 init_dummy_trans(&trans);
237 test_msg("Qgroup basic add\n");
238 ret = btrfs_create_qgroup(NULL, fs_info, 5);
239 if (ret) {
240 test_msg("Couldn't create a qgroup %d\n", ret);
241 return 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
247 * quota.
249 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
250 if (ret) {
251 ulist_free(old_roots);
252 test_msg("Couldn't find old roots: %d\n", ret);
253 return ret;
256 ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
257 if (ret)
258 return ret;
260 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
261 if (ret) {
262 ulist_free(old_roots);
263 ulist_free(new_roots);
264 test_msg("Couldn't find old roots: %d\n", ret);
265 return ret;
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);
272 return ret;
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;
279 old_roots = NULL;
280 new_roots = NULL;
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;
289 ret = remove_extent_item(root, 4096, 4096);
290 if (ret)
291 return -EINVAL;
293 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
294 if (ret) {
295 ulist_free(old_roots);
296 ulist_free(new_roots);
297 test_msg("Couldn't find old roots: %d\n", ret);
298 return ret;
301 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
302 old_roots, new_roots);
303 if (ret) {
304 test_msg("Couldn't account space for a qgroup %d\n", ret);
305 return -EINVAL;
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;
313 return 0;
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.
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;
327 int ret;
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);
335 if (ret) {
336 test_msg("Couldn't create a qgroup %d\n", ret);
337 return ret;
340 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;
347 ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
348 if (ret)
349 return ret;
351 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
352 if (ret) {
353 ulist_free(old_roots);
354 ulist_free(new_roots);
355 test_msg("Couldn't find old roots: %d\n", ret);
356 return ret;
359 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
360 old_roots, new_roots);
361 if (ret) {
362 test_msg("Couldn't account space for a qgroup %d\n", ret);
363 return ret;
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;
371 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;
378 ret = add_tree_ref(root, 4096, 4096, 0, 256);
379 if (ret)
380 return ret;
382 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
383 if (ret) {
384 ulist_free(old_roots);
385 ulist_free(new_roots);
386 test_msg("Couldn't find old roots: %d\n", ret);
387 return ret;
390 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
391 old_roots, new_roots);
392 if (ret) {
393 test_msg("Couldn't account space for a qgroup %d\n", ret);
394 return ret;
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;
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;
407 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;
414 ret = remove_extent_ref(root, 4096, 4096, 0, 256);
415 if (ret)
416 return ret;
418 ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
419 if (ret) {
420 ulist_free(old_roots);
421 ulist_free(new_roots);
422 test_msg("Couldn't find old roots: %d\n", ret);
423 return ret;
426 ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
427 old_roots, new_roots);
428 if (ret) {
429 test_msg("Couldn't account space for a qgroup %d\n", ret);
430 return ret;
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;
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;
443 return 0;
446 int btrfs_test_qgroups(void)
448 struct btrfs_root *root;
449 struct btrfs_root *tmp_root;
450 int ret = 0;
452 root = btrfs_alloc_dummy_root();
453 if (IS_ERR(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");
461 ret = -ENOMEM;
462 goto out;
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);
483 goto out;
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);
493 goto out;
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;
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;
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;
518 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);
523 out:
524 btrfs_free_dummy_root(root);
525 return ret;