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