Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / fs / btrfs / tests / free-space-tree-tests.c
1 /*
2  * Copyright (C) 2015 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 "../disk-io.h"
23 #include "../free-space-tree.h"
24 #include "../transaction.h"
25
26 struct free_space_extent {
27         u64 start, length;
28 };
29
30 /*
31  * The test cases align their operations to this in order to hit some of the
32  * edge cases in the bitmap code.
33  */
34 #define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE)
35
36 static int __check_free_space_extents(struct btrfs_trans_handle *trans,
37                                       struct btrfs_fs_info *fs_info,
38                                       struct btrfs_block_group_cache *cache,
39                                       struct btrfs_path *path,
40                                       struct free_space_extent *extents,
41                                       unsigned int num_extents)
42 {
43         struct btrfs_free_space_info *info;
44         struct btrfs_key key;
45         int prev_bit = 0, bit;
46         u64 extent_start = 0, offset, end;
47         u32 flags, extent_count;
48         unsigned int i;
49         int ret;
50
51         info = search_free_space_info(trans, fs_info, cache, path, 0);
52         if (IS_ERR(info)) {
53                 test_msg("Could not find free space info\n");
54                 ret = PTR_ERR(info);
55                 goto out;
56         }
57         flags = btrfs_free_space_flags(path->nodes[0], info);
58         extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
59
60         if (extent_count != num_extents) {
61                 test_msg("Extent count is wrong\n");
62                 ret = -EINVAL;
63                 goto out;
64         }
65         if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
66                 if (path->slots[0] != 0)
67                         goto invalid;
68                 end = cache->key.objectid + cache->key.offset;
69                 i = 0;
70                 while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
71                         btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
72                         if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY)
73                                 goto invalid;
74                         offset = key.objectid;
75                         while (offset < key.objectid + key.offset) {
76                                 bit = free_space_test_bit(cache, path, offset);
77                                 if (prev_bit == 0 && bit == 1) {
78                                         extent_start = offset;
79                                 } else if (prev_bit == 1 && bit == 0) {
80                                         if (i >= num_extents)
81                                                 goto invalid;
82                                         if (i >= num_extents ||
83                                             extent_start != extents[i].start ||
84                                             offset - extent_start != extents[i].length)
85                                                 goto invalid;
86                                         i++;
87                                 }
88                                 prev_bit = bit;
89                                 offset += cache->sectorsize;
90                         }
91                 }
92                 if (prev_bit == 1) {
93                         if (i >= num_extents ||
94                             extent_start != extents[i].start ||
95                             end - extent_start != extents[i].length)
96                                 goto invalid;
97                         i++;
98                 }
99                 if (i != num_extents)
100                         goto invalid;
101         } else {
102                 if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 ||
103                     path->slots[0] != 0)
104                         goto invalid;
105                 for (i = 0; i < num_extents; i++) {
106                         path->slots[0]++;
107                         btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
108                         if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY ||
109                             key.objectid != extents[i].start ||
110                             key.offset != extents[i].length)
111                                 goto invalid;
112                 }
113         }
114
115         ret = 0;
116 out:
117         btrfs_release_path(path);
118         return ret;
119 invalid:
120         test_msg("Free space tree is invalid\n");
121         ret = -EINVAL;
122         goto out;
123 }
124
125 static int check_free_space_extents(struct btrfs_trans_handle *trans,
126                                     struct btrfs_fs_info *fs_info,
127                                     struct btrfs_block_group_cache *cache,
128                                     struct btrfs_path *path,
129                                     struct free_space_extent *extents,
130                                     unsigned int num_extents)
131 {
132         struct btrfs_free_space_info *info;
133         u32 flags;
134         int ret;
135
136         info = search_free_space_info(trans, fs_info, cache, path, 0);
137         if (IS_ERR(info)) {
138                 test_msg("Could not find free space info\n");
139                 btrfs_release_path(path);
140                 return PTR_ERR(info);
141         }
142         flags = btrfs_free_space_flags(path->nodes[0], info);
143         btrfs_release_path(path);
144
145         ret = __check_free_space_extents(trans, fs_info, cache, path, extents,
146                                          num_extents);
147         if (ret)
148                 return ret;
149
150         /* Flip it to the other format and check that for good measure. */
151         if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
152                 ret = convert_free_space_to_extents(trans, fs_info, cache, path);
153                 if (ret) {
154                         test_msg("Could not convert to extents\n");
155                         return ret;
156                 }
157         } else {
158                 ret = convert_free_space_to_bitmaps(trans, fs_info, cache, path);
159                 if (ret) {
160                         test_msg("Could not convert to bitmaps\n");
161                         return ret;
162                 }
163         }
164         return __check_free_space_extents(trans, fs_info, cache, path, extents,
165                                           num_extents);
166 }
167
168 static int test_empty_block_group(struct btrfs_trans_handle *trans,
169                                   struct btrfs_fs_info *fs_info,
170                                   struct btrfs_block_group_cache *cache,
171                                   struct btrfs_path *path)
172 {
173         struct free_space_extent extents[] = {
174                 {cache->key.objectid, cache->key.offset},
175         };
176
177         return check_free_space_extents(trans, fs_info, cache, path,
178                                         extents, ARRAY_SIZE(extents));
179 }
180
181 static int test_remove_all(struct btrfs_trans_handle *trans,
182                            struct btrfs_fs_info *fs_info,
183                            struct btrfs_block_group_cache *cache,
184                            struct btrfs_path *path)
185 {
186         struct free_space_extent extents[] = {};
187         int ret;
188
189         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
190                                             cache->key.objectid,
191                                             cache->key.offset);
192         if (ret) {
193                 test_msg("Could not remove free space\n");
194                 return ret;
195         }
196
197         return check_free_space_extents(trans, fs_info, cache, path,
198                                         extents, ARRAY_SIZE(extents));
199 }
200
201 static int test_remove_beginning(struct btrfs_trans_handle *trans,
202                                  struct btrfs_fs_info *fs_info,
203                                  struct btrfs_block_group_cache *cache,
204                                  struct btrfs_path *path)
205 {
206         struct free_space_extent extents[] = {
207                 {cache->key.objectid + BITMAP_RANGE,
208                         cache->key.offset - BITMAP_RANGE},
209         };
210         int ret;
211
212         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
213                                             cache->key.objectid, BITMAP_RANGE);
214         if (ret) {
215                 test_msg("Could not remove free space\n");
216                 return ret;
217         }
218
219         return check_free_space_extents(trans, fs_info, cache, path,
220                                         extents, ARRAY_SIZE(extents));
221
222 }
223
224 static int test_remove_end(struct btrfs_trans_handle *trans,
225                            struct btrfs_fs_info *fs_info,
226                            struct btrfs_block_group_cache *cache,
227                            struct btrfs_path *path)
228 {
229         struct free_space_extent extents[] = {
230                 {cache->key.objectid, cache->key.offset - BITMAP_RANGE},
231         };
232         int ret;
233
234         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
235                                             cache->key.objectid +
236                                             cache->key.offset - BITMAP_RANGE,
237                                             BITMAP_RANGE);
238         if (ret) {
239                 test_msg("Could not remove free space\n");
240                 return ret;
241         }
242
243         return check_free_space_extents(trans, fs_info, cache, path,
244                                         extents, ARRAY_SIZE(extents));
245 }
246
247 static int test_remove_middle(struct btrfs_trans_handle *trans,
248                               struct btrfs_fs_info *fs_info,
249                               struct btrfs_block_group_cache *cache,
250                               struct btrfs_path *path)
251 {
252         struct free_space_extent extents[] = {
253                 {cache->key.objectid, BITMAP_RANGE},
254                 {cache->key.objectid + 2 * BITMAP_RANGE,
255                         cache->key.offset - 2 * BITMAP_RANGE},
256         };
257         int ret;
258
259         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
260                                             cache->key.objectid + BITMAP_RANGE,
261                                             BITMAP_RANGE);
262         if (ret) {
263                 test_msg("Could not remove free space\n");
264                 return ret;
265         }
266
267         return check_free_space_extents(trans, fs_info, cache, path,
268                                         extents, ARRAY_SIZE(extents));
269 }
270
271 static int test_merge_left(struct btrfs_trans_handle *trans,
272                            struct btrfs_fs_info *fs_info,
273                            struct btrfs_block_group_cache *cache,
274                            struct btrfs_path *path)
275 {
276         struct free_space_extent extents[] = {
277                 {cache->key.objectid, 2 * BITMAP_RANGE},
278         };
279         int ret;
280
281         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
282                                             cache->key.objectid,
283                                             cache->key.offset);
284         if (ret) {
285                 test_msg("Could not remove free space\n");
286                 return ret;
287         }
288
289         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
290                                        cache->key.objectid, BITMAP_RANGE);
291         if (ret) {
292                 test_msg("Could not add free space\n");
293                 return ret;
294         }
295
296         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
297                                        cache->key.objectid + BITMAP_RANGE,
298                                        BITMAP_RANGE);
299         if (ret) {
300                 test_msg("Could not add free space\n");
301                 return ret;
302         }
303
304         return check_free_space_extents(trans, fs_info, cache, path,
305                                         extents, ARRAY_SIZE(extents));
306 }
307
308 static int test_merge_right(struct btrfs_trans_handle *trans,
309                            struct btrfs_fs_info *fs_info,
310                            struct btrfs_block_group_cache *cache,
311                            struct btrfs_path *path)
312 {
313         struct free_space_extent extents[] = {
314                 {cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE},
315         };
316         int ret;
317
318         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
319                                             cache->key.objectid,
320                                             cache->key.offset);
321         if (ret) {
322                 test_msg("Could not remove free space\n");
323                 return ret;
324         }
325
326         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
327                                        cache->key.objectid + 2 * BITMAP_RANGE,
328                                        BITMAP_RANGE);
329         if (ret) {
330                 test_msg("Could not add free space\n");
331                 return ret;
332         }
333
334         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
335                                        cache->key.objectid + BITMAP_RANGE,
336                                        BITMAP_RANGE);
337         if (ret) {
338                 test_msg("Could not add free space\n");
339                 return ret;
340         }
341
342         return check_free_space_extents(trans, fs_info, cache, path,
343                                         extents, ARRAY_SIZE(extents));
344 }
345
346 static int test_merge_both(struct btrfs_trans_handle *trans,
347                            struct btrfs_fs_info *fs_info,
348                            struct btrfs_block_group_cache *cache,
349                            struct btrfs_path *path)
350 {
351         struct free_space_extent extents[] = {
352                 {cache->key.objectid, 3 * BITMAP_RANGE},
353         };
354         int ret;
355
356         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
357                                             cache->key.objectid,
358                                             cache->key.offset);
359         if (ret) {
360                 test_msg("Could not remove free space\n");
361                 return ret;
362         }
363
364         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
365                                        cache->key.objectid, BITMAP_RANGE);
366         if (ret) {
367                 test_msg("Could not add free space\n");
368                 return ret;
369         }
370
371         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
372                                        cache->key.objectid + 2 * BITMAP_RANGE,
373                                        BITMAP_RANGE);
374         if (ret) {
375                 test_msg("Could not add free space\n");
376                 return ret;
377         }
378
379         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
380                                        cache->key.objectid + BITMAP_RANGE,
381                                        BITMAP_RANGE);
382         if (ret) {
383                 test_msg("Could not add free space\n");
384                 return ret;
385         }
386
387         return check_free_space_extents(trans, fs_info, cache, path,
388                                         extents, ARRAY_SIZE(extents));
389 }
390
391 static int test_merge_none(struct btrfs_trans_handle *trans,
392                            struct btrfs_fs_info *fs_info,
393                            struct btrfs_block_group_cache *cache,
394                            struct btrfs_path *path)
395 {
396         struct free_space_extent extents[] = {
397                 {cache->key.objectid, BITMAP_RANGE},
398                 {cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE},
399                 {cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE},
400         };
401         int ret;
402
403         ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
404                                             cache->key.objectid,
405                                             cache->key.offset);
406         if (ret) {
407                 test_msg("Could not remove free space\n");
408                 return ret;
409         }
410
411         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
412                                        cache->key.objectid, BITMAP_RANGE);
413         if (ret) {
414                 test_msg("Could not add free space\n");
415                 return ret;
416         }
417
418         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
419                                        cache->key.objectid + 4 * BITMAP_RANGE,
420                                        BITMAP_RANGE);
421         if (ret) {
422                 test_msg("Could not add free space\n");
423                 return ret;
424         }
425
426         ret = __add_to_free_space_tree(trans, fs_info, cache, path,
427                                        cache->key.objectid + 2 * BITMAP_RANGE,
428                                        BITMAP_RANGE);
429         if (ret) {
430                 test_msg("Could not add free space\n");
431                 return ret;
432         }
433
434         return check_free_space_extents(trans, fs_info, cache, path,
435                                         extents, ARRAY_SIZE(extents));
436 }
437
438 typedef int (*test_func_t)(struct btrfs_trans_handle *,
439                            struct btrfs_fs_info *,
440                            struct btrfs_block_group_cache *,
441                            struct btrfs_path *);
442
443 static int run_test(test_func_t test_func, int bitmaps,
444                 u32 sectorsize, u32 nodesize)
445 {
446         struct btrfs_fs_info *fs_info;
447         struct btrfs_root *root = NULL;
448         struct btrfs_block_group_cache *cache = NULL;
449         struct btrfs_trans_handle trans;
450         struct btrfs_path *path = NULL;
451         int ret;
452
453         fs_info = btrfs_alloc_dummy_fs_info();
454         if (!fs_info) {
455                 test_msg("Couldn't allocate dummy fs info\n");
456                 ret = -ENOMEM;
457                 goto out;
458         }
459
460         root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
461         if (IS_ERR(root)) {
462                 test_msg("Couldn't allocate dummy root\n");
463                 ret = PTR_ERR(root);
464                 goto out;
465         }
466
467         btrfs_set_super_compat_ro_flags(root->fs_info->super_copy,
468                                         BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE);
469         root->fs_info->free_space_root = root;
470         root->fs_info->tree_root = root;
471
472         root->node = alloc_test_extent_buffer(root->fs_info,
473                 nodesize, nodesize);
474         if (!root->node) {
475                 test_msg("Couldn't allocate dummy buffer\n");
476                 ret = -ENOMEM;
477                 goto out;
478         }
479         btrfs_set_header_level(root->node, 0);
480         btrfs_set_header_nritems(root->node, 0);
481         root->alloc_bytenr += 2 * nodesize;
482
483         cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE, sectorsize);
484         if (!cache) {
485                 test_msg("Couldn't allocate dummy block group cache\n");
486                 ret = -ENOMEM;
487                 goto out;
488         }
489         cache->bitmap_low_thresh = 0;
490         cache->bitmap_high_thresh = (u32)-1;
491         cache->needs_free_space = 1;
492         cache->fs_info = root->fs_info;
493
494         btrfs_init_dummy_trans(&trans);
495
496         path = btrfs_alloc_path();
497         if (!path) {
498                 test_msg("Couldn't allocate path\n");
499                 return -ENOMEM;
500         }
501
502         ret = add_block_group_free_space(&trans, root->fs_info, cache);
503         if (ret) {
504                 test_msg("Could not add block group free space\n");
505                 goto out;
506         }
507
508         if (bitmaps) {
509                 ret = convert_free_space_to_bitmaps(&trans, root->fs_info,
510                                                     cache, path);
511                 if (ret) {
512                         test_msg("Could not convert block group to bitmaps\n");
513                         goto out;
514                 }
515         }
516
517         ret = test_func(&trans, root->fs_info, cache, path);
518         if (ret)
519                 goto out;
520
521         ret = remove_block_group_free_space(&trans, root->fs_info, cache);
522         if (ret) {
523                 test_msg("Could not remove block group free space\n");
524                 goto out;
525         }
526
527         if (btrfs_header_nritems(root->node) != 0) {
528                 test_msg("Free space tree has leftover items\n");
529                 ret = -EINVAL;
530                 goto out;
531         }
532
533         ret = 0;
534 out:
535         btrfs_free_path(path);
536         btrfs_free_dummy_block_group(cache);
537         btrfs_free_dummy_root(root);
538         btrfs_free_dummy_fs_info(fs_info);
539         return ret;
540 }
541
542 static int run_test_both_formats(test_func_t test_func,
543         u32 sectorsize, u32 nodesize)
544 {
545         int ret;
546
547         ret = run_test(test_func, 0, sectorsize, nodesize);
548         if (ret)
549                 return ret;
550         return run_test(test_func, 1, sectorsize, nodesize);
551 }
552
553 int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize)
554 {
555         test_func_t tests[] = {
556                 test_empty_block_group,
557                 test_remove_all,
558                 test_remove_beginning,
559                 test_remove_end,
560                 test_remove_middle,
561                 test_merge_left,
562                 test_merge_right,
563                 test_merge_both,
564                 test_merge_none,
565         };
566         int i;
567
568         test_msg("Running free space tree tests\n");
569         for (i = 0; i < ARRAY_SIZE(tests); i++) {
570                 int ret = run_test_both_formats(tests[i], sectorsize,
571                         nodesize);
572                 if (ret) {
573                         test_msg("%pf : sectorsize %u failed\n",
574                                 tests[i], sectorsize);
575                         return ret;
576                 }
577         }
578
579         return 0;
580 }