ARM: multi_v7_defconfig: Enable vivid driver as a module
[cascardo/linux.git] / fs / btrfs / tests / qgroup-tests.c
1 /*
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"
24 #include "../backref.h"
25
26 static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
27                                   u64 num_bytes, u64 parent, u64 root_objectid)
28 {
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;
35         struct btrfs_key ins;
36         u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
37         int ret;
38
39         btrfs_init_dummy_trans(&trans);
40
41         ins.objectid = bytenr;
42         ins.type = BTRFS_EXTENT_ITEM_KEY;
43         ins.offset = num_bytes;
44
45         path = btrfs_alloc_path();
46         if (!path) {
47                 test_msg("Couldn't allocate path\n");
48                 return -ENOMEM;
49         }
50
51         path->leave_spinning = 1;
52         ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
53         if (ret) {
54                 test_msg("Couldn't insert ref %d\n", ret);
55                 btrfs_free_path(path);
56                 return ret;
57         }
58
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);
67         if (parent > 0) {
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);
71         } else {
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);
74         }
75         btrfs_free_path(path);
76         return 0;
77 }
78
79 static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
80                         u64 parent, u64 root_objectid)
81 {
82         struct btrfs_trans_handle trans;
83         struct btrfs_extent_item *item;
84         struct btrfs_path *path;
85         struct btrfs_key key;
86         u64 refs;
87         int ret;
88
89         btrfs_init_dummy_trans(&trans);
90
91         key.objectid = bytenr;
92         key.type = BTRFS_EXTENT_ITEM_KEY;
93         key.offset = num_bytes;
94
95         path = btrfs_alloc_path();
96         if (!path) {
97                 test_msg("Couldn't allocate path\n");
98                 return -ENOMEM;
99         }
100
101         path->leave_spinning = 1;
102         ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
103         if (ret) {
104                 test_msg("Couldn't find extent ref\n");
105                 btrfs_free_path(path);
106                 return ret;
107         }
108
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);
114
115         key.objectid = bytenr;
116         if (parent) {
117                 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
118                 key.offset = parent;
119         } else {
120                 key.type = BTRFS_TREE_BLOCK_REF_KEY;
121                 key.offset = root_objectid;
122         }
123
124         ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);
125         if (ret)
126                 test_msg("Failed to insert backref\n");
127         btrfs_free_path(path);
128         return ret;
129 }
130
131 static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
132                               u64 num_bytes)
133 {
134         struct btrfs_trans_handle trans;
135         struct btrfs_key key;
136         struct btrfs_path *path;
137         int ret;
138
139         btrfs_init_dummy_trans(&trans);
140
141         key.objectid = bytenr;
142         key.type = BTRFS_EXTENT_ITEM_KEY;
143         key.offset = num_bytes;
144
145         path = btrfs_alloc_path();
146         if (!path) {
147                 test_msg("Couldn't allocate path\n");
148                 return -ENOMEM;
149         }
150         path->leave_spinning = 1;
151
152         ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
153         if (ret) {
154                 test_msg("Didn't find our key %d\n", ret);
155                 btrfs_free_path(path);
156                 return ret;
157         }
158         btrfs_del_item(&trans, root, path);
159         btrfs_free_path(path);
160         return 0;
161 }
162
163 static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
164                              u64 num_bytes, u64 parent, u64 root_objectid)
165 {
166         struct btrfs_trans_handle trans;
167         struct btrfs_extent_item *item;
168         struct btrfs_path *path;
169         struct btrfs_key key;
170         u64 refs;
171         int ret;
172
173         btrfs_init_dummy_trans(&trans);
174
175         key.objectid = bytenr;
176         key.type = BTRFS_EXTENT_ITEM_KEY;
177         key.offset = num_bytes;
178
179         path = btrfs_alloc_path();
180         if (!path) {
181                 test_msg("Couldn't allocate path\n");
182                 return -ENOMEM;
183         }
184
185         path->leave_spinning = 1;
186         ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
187         if (ret) {
188                 test_msg("Couldn't find extent ref\n");
189                 btrfs_free_path(path);
190                 return ret;
191         }
192
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);
198
199         key.objectid = bytenr;
200         if (parent) {
201                 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
202                 key.offset = parent;
203         } else {
204                 key.type = BTRFS_TREE_BLOCK_REF_KEY;
205                 key.offset = root_objectid;
206         }
207
208         ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
209         if (ret) {
210                 test_msg("Couldn't find backref %d\n", ret);
211                 btrfs_free_path(path);
212                 return ret;
213         }
214         btrfs_del_item(&trans, root, path);
215         btrfs_free_path(path);
216         return ret;
217 }
218
219 static int test_no_shared_qgroup(struct btrfs_root *root)
220 {
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;
225         int ret;
226
227         btrfs_init_dummy_trans(&trans);
228
229         test_msg("Qgroup basic add\n");
230         ret = btrfs_create_qgroup(NULL, fs_info, 5);
231         if (ret) {
232                 test_msg("Couldn't create a qgroup %d\n", ret);
233                 return ret;
234         }
235
236         /*
237          * Since the test trans doesn't have the complicated delayed refs,
238          * we can only call btrfs_qgroup_account_extent() directly to test
239          * quota.
240          */
241         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
242         if (ret) {
243                 ulist_free(old_roots);
244                 test_msg("Couldn't find old roots: %d\n", ret);
245                 return ret;
246         }
247
248         ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
249         if (ret)
250                 return ret;
251
252         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
253         if (ret) {
254                 ulist_free(old_roots);
255                 ulist_free(new_roots);
256                 test_msg("Couldn't find old roots: %d\n", ret);
257                 return ret;
258         }
259
260         ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
261                                           old_roots, new_roots);
262         if (ret) {
263                 test_msg("Couldn't account space for a qgroup %d\n", ret);
264                 return ret;
265         }
266
267         if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
268                 test_msg("Qgroup counts didn't match expected values\n");
269                 return -EINVAL;
270         }
271         old_roots = NULL;
272         new_roots = NULL;
273
274         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
275         if (ret) {
276                 ulist_free(old_roots);
277                 test_msg("Couldn't find old roots: %d\n", ret);
278                 return ret;
279         }
280
281         ret = remove_extent_item(root, 4096, 4096);
282         if (ret)
283                 return -EINVAL;
284
285         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
286         if (ret) {
287                 ulist_free(old_roots);
288                 ulist_free(new_roots);
289                 test_msg("Couldn't find old roots: %d\n", ret);
290                 return ret;
291         }
292
293         ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
294                                           old_roots, new_roots);
295         if (ret) {
296                 test_msg("Couldn't account space for a qgroup %d\n", ret);
297                 return -EINVAL;
298         }
299
300         if (btrfs_verify_qgroup_counts(fs_info, 5, 0, 0)) {
301                 test_msg("Qgroup counts didn't match expected values\n");
302                 return -EINVAL;
303         }
304
305         return 0;
306 }
307
308 /*
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
311  * adjusted properly.
312  */
313 static int test_multiple_refs(struct btrfs_root *root)
314 {
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;
319         int ret;
320
321         btrfs_init_dummy_trans(&trans);
322
323         test_msg("Qgroup multiple refs test\n");
324
325         /* We have 5 created already from the previous test */
326         ret = btrfs_create_qgroup(NULL, fs_info, 256);
327         if (ret) {
328                 test_msg("Couldn't create a qgroup %d\n", ret);
329                 return ret;
330         }
331
332         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
333         if (ret) {
334                 ulist_free(old_roots);
335                 test_msg("Couldn't find old roots: %d\n", ret);
336                 return ret;
337         }
338
339         ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5);
340         if (ret)
341                 return ret;
342
343         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
344         if (ret) {
345                 ulist_free(old_roots);
346                 ulist_free(new_roots);
347                 test_msg("Couldn't find old roots: %d\n", ret);
348                 return ret;
349         }
350
351         ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
352                                           old_roots, new_roots);
353         if (ret) {
354                 test_msg("Couldn't account space for a qgroup %d\n", ret);
355                 return ret;
356         }
357
358         if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
359                 test_msg("Qgroup counts didn't match expected values\n");
360                 return -EINVAL;
361         }
362
363         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
364         if (ret) {
365                 ulist_free(old_roots);
366                 test_msg("Couldn't find old roots: %d\n", ret);
367                 return ret;
368         }
369
370         ret = add_tree_ref(root, 4096, 4096, 0, 256);
371         if (ret)
372                 return ret;
373
374         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
375         if (ret) {
376                 ulist_free(old_roots);
377                 ulist_free(new_roots);
378                 test_msg("Couldn't find old roots: %d\n", ret);
379                 return ret;
380         }
381
382         ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
383                                           old_roots, new_roots);
384         if (ret) {
385                 test_msg("Couldn't account space for a qgroup %d\n", ret);
386                 return ret;
387         }
388
389         if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 0)) {
390                 test_msg("Qgroup counts didn't match expected values\n");
391                 return -EINVAL;
392         }
393
394         if (btrfs_verify_qgroup_counts(fs_info, 256, 4096, 0)) {
395                 test_msg("Qgroup counts didn't match expected values\n");
396                 return -EINVAL;
397         }
398
399         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &old_roots);
400         if (ret) {
401                 ulist_free(old_roots);
402                 test_msg("Couldn't find old roots: %d\n", ret);
403                 return ret;
404         }
405
406         ret = remove_extent_ref(root, 4096, 4096, 0, 256);
407         if (ret)
408                 return ret;
409
410         ret = btrfs_find_all_roots(&trans, fs_info, 4096, 0, &new_roots);
411         if (ret) {
412                 ulist_free(old_roots);
413                 ulist_free(new_roots);
414                 test_msg("Couldn't find old roots: %d\n", ret);
415                 return ret;
416         }
417
418         ret = btrfs_qgroup_account_extent(&trans, fs_info, 4096, 4096,
419                                           old_roots, new_roots);
420         if (ret) {
421                 test_msg("Couldn't account space for a qgroup %d\n", ret);
422                 return ret;
423         }
424
425         if (btrfs_verify_qgroup_counts(fs_info, 256, 0, 0)) {
426                 test_msg("Qgroup counts didn't match expected values\n");
427                 return -EINVAL;
428         }
429
430         if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) {
431                 test_msg("Qgroup counts didn't match expected values\n");
432                 return -EINVAL;
433         }
434
435         return 0;
436 }
437
438 int btrfs_test_qgroups(void)
439 {
440         struct btrfs_root *root;
441         struct btrfs_root *tmp_root;
442         int ret = 0;
443
444         root = btrfs_alloc_dummy_root();
445         if (IS_ERR(root)) {
446                 test_msg("Couldn't allocate root\n");
447                 return PTR_ERR(root);
448         }
449
450         root->fs_info = btrfs_alloc_dummy_fs_info();
451         if (!root->fs_info) {
452                 test_msg("Couldn't allocate dummy fs info\n");
453                 ret = -ENOMEM;
454                 goto out;
455         }
456         /* We are using this root as our extent root */
457         root->fs_info->extent_root = root;
458
459         /*
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.
462          */
463         root->fs_info->tree_root = root;
464         root->fs_info->quota_root = root;
465         root->fs_info->quota_enabled = 1;
466
467         /*
468          * Can't use bytenr 0, some things freak out
469          * *cough*backref walking code*cough*
470          */
471         root->node = alloc_test_extent_buffer(root->fs_info, 4096);
472         if (!root->node) {
473                 test_msg("Couldn't allocate dummy buffer\n");
474                 ret = -ENOMEM;
475                 goto out;
476         }
477         btrfs_set_header_level(root->node, 0);
478         btrfs_set_header_nritems(root->node, 0);
479         root->alloc_bytenr += 8192;
480
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);
485                 goto out;
486         }
487
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);
491         if (ret) {
492                 test_msg("Couldn't insert fs root %d\n", ret);
493                 goto out;
494         }
495
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);
500                 goto out;
501         }
502
503         tmp_root->root_key.objectid = 256;
504         ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
505         if (ret) {
506                 test_msg("Couldn't insert fs root %d\n", ret);
507                 goto out;
508         }
509
510         test_msg("Running qgroup tests\n");
511         ret = test_no_shared_qgroup(root);
512         if (ret)
513                 goto out;
514         ret = test_multiple_refs(root);
515 out:
516         btrfs_free_dummy_root(root);
517         return ret;
518 }