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