Merge branch 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
[sfrench/cifs-2.6.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 <linux/types.h>
20 #include "btrfs-tests.h"
21 #include "../ctree.h"
22 #include "../transaction.h"
23 #include "../disk-io.h"
24 #include "../qgroup.h"
25 #include "../backref.h"
26
27 static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
28                                   u64 num_bytes, u64 parent, u64 root_objectid)
29 {
30         struct btrfs_trans_handle trans;
31         struct btrfs_extent_item *item;
32         struct btrfs_extent_inline_ref *iref;
33         struct btrfs_tree_block_info *block_info;
34         struct btrfs_path *path;
35         struct extent_buffer *leaf;
36         struct btrfs_key ins;
37         u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
38         int ret;
39
40         btrfs_init_dummy_trans(&trans);
41
42         ins.objectid = bytenr;
43         ins.type = BTRFS_EXTENT_ITEM_KEY;
44         ins.offset = num_bytes;
45
46         path = btrfs_alloc_path();
47         if (!path) {
48                 test_msg("Couldn't allocate path\n");
49                 return -ENOMEM;
50         }
51
52         path->leave_spinning = 1;
53         ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
54         if (ret) {
55                 test_msg("Couldn't insert ref %d\n", ret);
56                 btrfs_free_path(path);
57                 return ret;
58         }
59
60         leaf = path->nodes[0];
61         item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
62         btrfs_set_extent_refs(leaf, item, 1);
63         btrfs_set_extent_generation(leaf, item, 1);
64         btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
65         block_info = (struct btrfs_tree_block_info *)(item + 1);
66         btrfs_set_tree_block_level(leaf, block_info, 1);
67         iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
68         if (parent > 0) {
69                 btrfs_set_extent_inline_ref_type(leaf, iref,
70                                                  BTRFS_SHARED_BLOCK_REF_KEY);
71                 btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
72         } else {
73                 btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);
74                 btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
75         }
76         btrfs_free_path(path);
77         return 0;
78 }
79
80 static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
81                         u64 parent, u64 root_objectid)
82 {
83         struct btrfs_trans_handle trans;
84         struct btrfs_extent_item *item;
85         struct btrfs_path *path;
86         struct btrfs_key key;
87         u64 refs;
88         int ret;
89
90         btrfs_init_dummy_trans(&trans);
91
92         key.objectid = bytenr;
93         key.type = BTRFS_EXTENT_ITEM_KEY;
94         key.offset = num_bytes;
95
96         path = btrfs_alloc_path();
97         if (!path) {
98                 test_msg("Couldn't allocate path\n");
99                 return -ENOMEM;
100         }
101
102         path->leave_spinning = 1;
103         ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
104         if (ret) {
105                 test_msg("Couldn't find extent ref\n");
106                 btrfs_free_path(path);
107                 return ret;
108         }
109
110         item = btrfs_item_ptr(path->nodes[0], path->slots[0],
111                               struct btrfs_extent_item);
112         refs = btrfs_extent_refs(path->nodes[0], item);
113         btrfs_set_extent_refs(path->nodes[0], item, refs + 1);
114         btrfs_release_path(path);
115
116         key.objectid = bytenr;
117         if (parent) {
118                 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
119                 key.offset = parent;
120         } else {
121                 key.type = BTRFS_TREE_BLOCK_REF_KEY;
122                 key.offset = root_objectid;
123         }
124
125         ret = btrfs_insert_empty_item(&trans, root, path, &key, 0);
126         if (ret)
127                 test_msg("Failed to insert backref\n");
128         btrfs_free_path(path);
129         return ret;
130 }
131
132 static int remove_extent_item(struct btrfs_root *root, u64 bytenr,
133                               u64 num_bytes)
134 {
135         struct btrfs_trans_handle trans;
136         struct btrfs_key key;
137         struct btrfs_path *path;
138         int ret;
139
140         btrfs_init_dummy_trans(&trans);
141
142         key.objectid = bytenr;
143         key.type = BTRFS_EXTENT_ITEM_KEY;
144         key.offset = num_bytes;
145
146         path = btrfs_alloc_path();
147         if (!path) {
148                 test_msg("Couldn't allocate path\n");
149                 return -ENOMEM;
150         }
151         path->leave_spinning = 1;
152
153         ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
154         if (ret) {
155                 test_msg("Didn't find our key %d\n", ret);
156                 btrfs_free_path(path);
157                 return ret;
158         }
159         btrfs_del_item(&trans, root, path);
160         btrfs_free_path(path);
161         return 0;
162 }
163
164 static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
165                              u64 num_bytes, u64 parent, u64 root_objectid)
166 {
167         struct btrfs_trans_handle trans;
168         struct btrfs_extent_item *item;
169         struct btrfs_path *path;
170         struct btrfs_key key;
171         u64 refs;
172         int ret;
173
174         btrfs_init_dummy_trans(&trans);
175
176         key.objectid = bytenr;
177         key.type = BTRFS_EXTENT_ITEM_KEY;
178         key.offset = num_bytes;
179
180         path = btrfs_alloc_path();
181         if (!path) {
182                 test_msg("Couldn't allocate path\n");
183                 return -ENOMEM;
184         }
185
186         path->leave_spinning = 1;
187         ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
188         if (ret) {
189                 test_msg("Couldn't find extent ref\n");
190                 btrfs_free_path(path);
191                 return ret;
192         }
193
194         item = btrfs_item_ptr(path->nodes[0], path->slots[0],
195                               struct btrfs_extent_item);
196         refs = btrfs_extent_refs(path->nodes[0], item);
197         btrfs_set_extent_refs(path->nodes[0], item, refs - 1);
198         btrfs_release_path(path);
199
200         key.objectid = bytenr;
201         if (parent) {
202                 key.type = BTRFS_SHARED_BLOCK_REF_KEY;
203                 key.offset = parent;
204         } else {
205                 key.type = BTRFS_TREE_BLOCK_REF_KEY;
206                 key.offset = root_objectid;
207         }
208
209         ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
210         if (ret) {
211                 test_msg("Couldn't find backref %d\n", ret);
212                 btrfs_free_path(path);
213                 return ret;
214         }
215         btrfs_del_item(&trans, root, path);
216         btrfs_free_path(path);
217         return ret;
218 }
219
220 static int test_no_shared_qgroup(struct btrfs_root *root,
221                 u32 sectorsize, u32 nodesize)
222 {
223         struct btrfs_trans_handle trans;
224         struct btrfs_fs_info *fs_info = root->fs_info;
225         struct ulist *old_roots = NULL;
226         struct ulist *new_roots = NULL;
227         int ret;
228
229         btrfs_init_dummy_trans(&trans);
230
231         test_msg("Qgroup basic add\n");
232         ret = btrfs_create_qgroup(NULL, fs_info, BTRFS_FS_TREE_OBJECTID);
233         if (ret) {
234                 test_msg("Couldn't create a qgroup %d\n", ret);
235                 return ret;
236         }
237
238         /*
239          * Since the test trans doesn't have the complicated delayed refs,
240          * we can only call btrfs_qgroup_account_extent() directly to test
241          * quota.
242          */
243         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots);
244         if (ret) {
245                 ulist_free(old_roots);
246                 test_msg("Couldn't find old roots: %d\n", ret);
247                 return ret;
248         }
249
250         ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
251                                 BTRFS_FS_TREE_OBJECTID);
252         if (ret)
253                 return ret;
254
255         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots);
256         if (ret) {
257                 ulist_free(old_roots);
258                 ulist_free(new_roots);
259                 test_msg("Couldn't find old roots: %d\n", ret);
260                 return ret;
261         }
262
263         ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize,
264                                           nodesize, old_roots, new_roots);
265         if (ret) {
266                 test_msg("Couldn't account space for a qgroup %d\n", ret);
267                 return ret;
268         }
269
270         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
271                                 nodesize, nodesize)) {
272                 test_msg("Qgroup counts didn't match expected values\n");
273                 return -EINVAL;
274         }
275         old_roots = NULL;
276         new_roots = NULL;
277
278         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots);
279         if (ret) {
280                 ulist_free(old_roots);
281                 test_msg("Couldn't find old roots: %d\n", ret);
282                 return ret;
283         }
284
285         ret = remove_extent_item(root, nodesize, nodesize);
286         if (ret)
287                 return -EINVAL;
288
289         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots);
290         if (ret) {
291                 ulist_free(old_roots);
292                 ulist_free(new_roots);
293                 test_msg("Couldn't find old roots: %d\n", ret);
294                 return ret;
295         }
296
297         ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize,
298                                           nodesize, old_roots, new_roots);
299         if (ret) {
300                 test_msg("Couldn't account space for a qgroup %d\n", ret);
301                 return -EINVAL;
302         }
303
304         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID, 0, 0)) {
305                 test_msg("Qgroup counts didn't match expected values\n");
306                 return -EINVAL;
307         }
308
309         return 0;
310 }
311
312 /*
313  * Add a ref for two different roots to make sure the shared value comes out
314  * right, also remove one of the roots and make sure the exclusive count is
315  * adjusted properly.
316  */
317 static int test_multiple_refs(struct btrfs_root *root,
318                 u32 sectorsize, u32 nodesize)
319 {
320         struct btrfs_trans_handle trans;
321         struct btrfs_fs_info *fs_info = root->fs_info;
322         struct ulist *old_roots = NULL;
323         struct ulist *new_roots = NULL;
324         int ret;
325
326         btrfs_init_dummy_trans(&trans);
327
328         test_msg("Qgroup multiple refs test\n");
329
330         /*
331          * We have BTRFS_FS_TREE_OBJECTID created already from the
332          * previous test.
333          */
334         ret = btrfs_create_qgroup(NULL, fs_info, BTRFS_FIRST_FREE_OBJECTID);
335         if (ret) {
336                 test_msg("Couldn't create a qgroup %d\n", ret);
337                 return ret;
338         }
339
340         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 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;
345         }
346
347         ret = insert_normal_tree_ref(root, nodesize, nodesize, 0,
348                                 BTRFS_FS_TREE_OBJECTID);
349         if (ret)
350                 return ret;
351
352         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots);
353         if (ret) {
354                 ulist_free(old_roots);
355                 ulist_free(new_roots);
356                 test_msg("Couldn't find old roots: %d\n", ret);
357                 return ret;
358         }
359
360         ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize,
361                                           nodesize, old_roots, new_roots);
362         if (ret) {
363                 test_msg("Couldn't account space for a qgroup %d\n", ret);
364                 return ret;
365         }
366
367         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
368                                        nodesize, nodesize)) {
369                 test_msg("Qgroup counts didn't match expected values\n");
370                 return -EINVAL;
371         }
372
373         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots);
374         if (ret) {
375                 ulist_free(old_roots);
376                 test_msg("Couldn't find old roots: %d\n", ret);
377                 return ret;
378         }
379
380         ret = add_tree_ref(root, nodesize, nodesize, 0,
381                         BTRFS_FIRST_FREE_OBJECTID);
382         if (ret)
383                 return ret;
384
385         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots);
386         if (ret) {
387                 ulist_free(old_roots);
388                 ulist_free(new_roots);
389                 test_msg("Couldn't find old roots: %d\n", ret);
390                 return ret;
391         }
392
393         ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize,
394                                           nodesize, old_roots, new_roots);
395         if (ret) {
396                 test_msg("Couldn't account space for a qgroup %d\n", ret);
397                 return ret;
398         }
399
400         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
401                                         nodesize, 0)) {
402                 test_msg("Qgroup counts didn't match expected values\n");
403                 return -EINVAL;
404         }
405
406         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
407                                         nodesize, 0)) {
408                 test_msg("Qgroup counts didn't match expected values\n");
409                 return -EINVAL;
410         }
411
412         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &old_roots);
413         if (ret) {
414                 ulist_free(old_roots);
415                 test_msg("Couldn't find old roots: %d\n", ret);
416                 return ret;
417         }
418
419         ret = remove_extent_ref(root, nodesize, nodesize, 0,
420                                 BTRFS_FIRST_FREE_OBJECTID);
421         if (ret)
422                 return ret;
423
424         ret = btrfs_find_all_roots(&trans, fs_info, nodesize, 0, &new_roots);
425         if (ret) {
426                 ulist_free(old_roots);
427                 ulist_free(new_roots);
428                 test_msg("Couldn't find old roots: %d\n", ret);
429                 return ret;
430         }
431
432         ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize,
433                                           nodesize, old_roots, new_roots);
434         if (ret) {
435                 test_msg("Couldn't account space for a qgroup %d\n", ret);
436                 return ret;
437         }
438
439         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FIRST_FREE_OBJECTID,
440                                         0, 0)) {
441                 test_msg("Qgroup counts didn't match expected values\n");
442                 return -EINVAL;
443         }
444
445         if (btrfs_verify_qgroup_counts(fs_info, BTRFS_FS_TREE_OBJECTID,
446                                         nodesize, nodesize)) {
447                 test_msg("Qgroup counts didn't match expected values\n");
448                 return -EINVAL;
449         }
450
451         return 0;
452 }
453
454 int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
455 {
456         struct btrfs_fs_info *fs_info = NULL;
457         struct btrfs_root *root;
458         struct btrfs_root *tmp_root;
459         int ret = 0;
460
461         fs_info = btrfs_alloc_dummy_fs_info();
462         if (!fs_info) {
463                 test_msg("Couldn't allocate dummy fs info\n");
464                 return -ENOMEM;
465         }
466
467         root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
468         if (IS_ERR(root)) {
469                 test_msg("Couldn't allocate root\n");
470                 ret = PTR_ERR(root);
471                 goto out;
472         }
473
474         /* We are using this root as our extent root */
475         root->fs_info->extent_root = root;
476
477         /*
478          * Some of the paths we test assume we have a filled out fs_info, so we
479          * just need to add the root in there so we don't panic.
480          */
481         root->fs_info->tree_root = root;
482         root->fs_info->quota_root = root;
483         root->fs_info->quota_enabled = 1;
484
485         /*
486          * Can't use bytenr 0, some things freak out
487          * *cough*backref walking code*cough*
488          */
489         root->node = alloc_test_extent_buffer(root->fs_info, nodesize,
490                                         nodesize);
491         if (!root->node) {
492                 test_msg("Couldn't allocate dummy buffer\n");
493                 ret = -ENOMEM;
494                 goto out;
495         }
496         btrfs_set_header_level(root->node, 0);
497         btrfs_set_header_nritems(root->node, 0);
498         root->alloc_bytenr += 2 * nodesize;
499
500         tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
501         if (IS_ERR(tmp_root)) {
502                 test_msg("Couldn't allocate a fs root\n");
503                 ret = PTR_ERR(tmp_root);
504                 goto out;
505         }
506
507         tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID;
508         root->fs_info->fs_root = tmp_root;
509         ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
510         if (ret) {
511                 test_msg("Couldn't insert fs root %d\n", ret);
512                 goto out;
513         }
514
515         tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
516         if (IS_ERR(tmp_root)) {
517                 test_msg("Couldn't allocate a fs root\n");
518                 ret = PTR_ERR(tmp_root);
519                 goto out;
520         }
521
522         tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID;
523         ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
524         if (ret) {
525                 test_msg("Couldn't insert fs root %d\n", ret);
526                 goto out;
527         }
528
529         test_msg("Running qgroup tests\n");
530         ret = test_no_shared_qgroup(root, sectorsize, nodesize);
531         if (ret)
532                 goto out;
533         ret = test_multiple_refs(root, sectorsize, nodesize);
534 out:
535         btrfs_free_dummy_root(root);
536         btrfs_free_dummy_fs_info(fs_info);
537         return ret;
538 }