2 * Copyright (C) 2015 Facebook. All rights reserved.
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.
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.
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.
19 #include "btrfs-tests.h"
21 #include "../disk-io.h"
22 #include "../free-space-tree.h"
23 #include "../transaction.h"
25 struct free_space_extent
{
30 * The test cases align their operations to this in order to hit some of the
31 * edge cases in the bitmap code.
33 #define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * 4096)
35 static int __check_free_space_extents(struct btrfs_trans_handle
*trans
,
36 struct btrfs_fs_info
*fs_info
,
37 struct btrfs_block_group_cache
*cache
,
38 struct btrfs_path
*path
,
39 struct free_space_extent
*extents
,
40 unsigned int num_extents
)
42 struct btrfs_free_space_info
*info
;
44 int prev_bit
= 0, bit
;
45 u64 extent_start
= 0, offset
, end
;
46 u32 flags
, extent_count
;
50 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
52 test_msg("Could not find free space info\n");
56 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
57 extent_count
= btrfs_free_space_extent_count(path
->nodes
[0], info
);
59 if (extent_count
!= num_extents
) {
60 test_msg("Extent count is wrong\n");
64 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
65 if (path
->slots
[0] != 0)
67 end
= cache
->key
.objectid
+ cache
->key
.offset
;
69 while (++path
->slots
[0] < btrfs_header_nritems(path
->nodes
[0])) {
70 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
71 if (key
.type
!= BTRFS_FREE_SPACE_BITMAP_KEY
)
73 offset
= key
.objectid
;
74 while (offset
< key
.objectid
+ key
.offset
) {
75 bit
= free_space_test_bit(cache
, path
, offset
);
76 if (prev_bit
== 0 && bit
== 1) {
77 extent_start
= offset
;
78 } else if (prev_bit
== 1 && bit
== 0) {
81 if (i
>= num_extents
||
82 extent_start
!= extents
[i
].start
||
83 offset
- extent_start
!= extents
[i
].length
)
88 offset
+= cache
->sectorsize
;
92 if (i
>= num_extents
||
93 extent_start
!= extents
[i
].start
||
94 end
- extent_start
!= extents
[i
].length
)
101 if (btrfs_header_nritems(path
->nodes
[0]) != num_extents
+ 1 ||
104 for (i
= 0; i
< num_extents
; i
++) {
106 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
107 if (key
.type
!= BTRFS_FREE_SPACE_EXTENT_KEY
||
108 key
.objectid
!= extents
[i
].start
||
109 key
.offset
!= extents
[i
].length
)
116 btrfs_release_path(path
);
119 test_msg("Free space tree is invalid\n");
124 static int check_free_space_extents(struct btrfs_trans_handle
*trans
,
125 struct btrfs_fs_info
*fs_info
,
126 struct btrfs_block_group_cache
*cache
,
127 struct btrfs_path
*path
,
128 struct free_space_extent
*extents
,
129 unsigned int num_extents
)
131 struct btrfs_free_space_info
*info
;
135 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
137 test_msg("Could not find free space info\n");
138 btrfs_release_path(path
);
139 return PTR_ERR(info
);
141 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
142 btrfs_release_path(path
);
144 ret
= __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
149 /* Flip it to the other format and check that for good measure. */
150 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
151 ret
= convert_free_space_to_extents(trans
, fs_info
, cache
, path
);
153 test_msg("Could not convert to extents\n");
157 ret
= convert_free_space_to_bitmaps(trans
, fs_info
, cache
, path
);
159 test_msg("Could not convert to bitmaps\n");
163 return __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
167 static int test_empty_block_group(struct btrfs_trans_handle
*trans
,
168 struct btrfs_fs_info
*fs_info
,
169 struct btrfs_block_group_cache
*cache
,
170 struct btrfs_path
*path
)
172 struct free_space_extent extents
[] = {
173 {cache
->key
.objectid
, cache
->key
.offset
},
176 return check_free_space_extents(trans
, fs_info
, cache
, path
,
177 extents
, ARRAY_SIZE(extents
));
180 static int test_remove_all(struct btrfs_trans_handle
*trans
,
181 struct btrfs_fs_info
*fs_info
,
182 struct btrfs_block_group_cache
*cache
,
183 struct btrfs_path
*path
)
185 struct free_space_extent extents
[] = {};
188 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
192 test_msg("Could not remove free space\n");
196 return check_free_space_extents(trans
, fs_info
, cache
, path
,
197 extents
, ARRAY_SIZE(extents
));
200 static int test_remove_beginning(struct btrfs_trans_handle
*trans
,
201 struct btrfs_fs_info
*fs_info
,
202 struct btrfs_block_group_cache
*cache
,
203 struct btrfs_path
*path
)
205 struct free_space_extent extents
[] = {
206 {cache
->key
.objectid
+ BITMAP_RANGE
,
207 cache
->key
.offset
- BITMAP_RANGE
},
211 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
212 cache
->key
.objectid
, BITMAP_RANGE
);
214 test_msg("Could not remove free space\n");
218 return check_free_space_extents(trans
, fs_info
, cache
, path
,
219 extents
, ARRAY_SIZE(extents
));
223 static int test_remove_end(struct btrfs_trans_handle
*trans
,
224 struct btrfs_fs_info
*fs_info
,
225 struct btrfs_block_group_cache
*cache
,
226 struct btrfs_path
*path
)
228 struct free_space_extent extents
[] = {
229 {cache
->key
.objectid
, cache
->key
.offset
- BITMAP_RANGE
},
233 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
234 cache
->key
.objectid
+
235 cache
->key
.offset
- BITMAP_RANGE
,
238 test_msg("Could not remove free space\n");
242 return check_free_space_extents(trans
, fs_info
, cache
, path
,
243 extents
, ARRAY_SIZE(extents
));
246 static int test_remove_middle(struct btrfs_trans_handle
*trans
,
247 struct btrfs_fs_info
*fs_info
,
248 struct btrfs_block_group_cache
*cache
,
249 struct btrfs_path
*path
)
251 struct free_space_extent extents
[] = {
252 {cache
->key
.objectid
, BITMAP_RANGE
},
253 {cache
->key
.objectid
+ 2 * BITMAP_RANGE
,
254 cache
->key
.offset
- 2 * BITMAP_RANGE
},
258 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
259 cache
->key
.objectid
+ BITMAP_RANGE
,
262 test_msg("Could not remove free space\n");
266 return check_free_space_extents(trans
, fs_info
, cache
, path
,
267 extents
, ARRAY_SIZE(extents
));
270 static int test_merge_left(struct btrfs_trans_handle
*trans
,
271 struct btrfs_fs_info
*fs_info
,
272 struct btrfs_block_group_cache
*cache
,
273 struct btrfs_path
*path
)
275 struct free_space_extent extents
[] = {
276 {cache
->key
.objectid
, 2 * BITMAP_RANGE
},
280 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
284 test_msg("Could not remove free space\n");
288 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
289 cache
->key
.objectid
, BITMAP_RANGE
);
291 test_msg("Could not add free space\n");
295 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
296 cache
->key
.objectid
+ BITMAP_RANGE
,
299 test_msg("Could not add free space\n");
303 return check_free_space_extents(trans
, fs_info
, cache
, path
,
304 extents
, ARRAY_SIZE(extents
));
307 static int test_merge_right(struct btrfs_trans_handle
*trans
,
308 struct btrfs_fs_info
*fs_info
,
309 struct btrfs_block_group_cache
*cache
,
310 struct btrfs_path
*path
)
312 struct free_space_extent extents
[] = {
313 {cache
->key
.objectid
+ BITMAP_RANGE
, 2 * BITMAP_RANGE
},
317 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
321 test_msg("Could not remove free space\n");
325 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
326 cache
->key
.objectid
+ 2 * BITMAP_RANGE
,
329 test_msg("Could not add free space\n");
333 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
334 cache
->key
.objectid
+ BITMAP_RANGE
,
337 test_msg("Could not add free space\n");
341 return check_free_space_extents(trans
, fs_info
, cache
, path
,
342 extents
, ARRAY_SIZE(extents
));
345 static int test_merge_both(struct btrfs_trans_handle
*trans
,
346 struct btrfs_fs_info
*fs_info
,
347 struct btrfs_block_group_cache
*cache
,
348 struct btrfs_path
*path
)
350 struct free_space_extent extents
[] = {
351 {cache
->key
.objectid
, 3 * BITMAP_RANGE
},
355 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
359 test_msg("Could not remove free space\n");
363 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
364 cache
->key
.objectid
, BITMAP_RANGE
);
366 test_msg("Could not add free space\n");
370 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
371 cache
->key
.objectid
+ 2 * BITMAP_RANGE
,
374 test_msg("Could not add free space\n");
378 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
379 cache
->key
.objectid
+ BITMAP_RANGE
,
382 test_msg("Could not add free space\n");
386 return check_free_space_extents(trans
, fs_info
, cache
, path
,
387 extents
, ARRAY_SIZE(extents
));
390 static int test_merge_none(struct btrfs_trans_handle
*trans
,
391 struct btrfs_fs_info
*fs_info
,
392 struct btrfs_block_group_cache
*cache
,
393 struct btrfs_path
*path
)
395 struct free_space_extent extents
[] = {
396 {cache
->key
.objectid
, BITMAP_RANGE
},
397 {cache
->key
.objectid
+ 2 * BITMAP_RANGE
, BITMAP_RANGE
},
398 {cache
->key
.objectid
+ 4 * BITMAP_RANGE
, BITMAP_RANGE
},
402 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
406 test_msg("Could not remove free space\n");
410 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
411 cache
->key
.objectid
, BITMAP_RANGE
);
413 test_msg("Could not add free space\n");
417 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
418 cache
->key
.objectid
+ 4 * BITMAP_RANGE
,
421 test_msg("Could not add free space\n");
425 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
426 cache
->key
.objectid
+ 2 * BITMAP_RANGE
,
429 test_msg("Could not add free space\n");
433 return check_free_space_extents(trans
, fs_info
, cache
, path
,
434 extents
, ARRAY_SIZE(extents
));
437 typedef int (*test_func_t
)(struct btrfs_trans_handle
*,
438 struct btrfs_fs_info
*,
439 struct btrfs_block_group_cache
*,
440 struct btrfs_path
*);
442 static int run_test(test_func_t test_func
, int bitmaps
)
444 struct btrfs_root
*root
= NULL
;
445 struct btrfs_block_group_cache
*cache
= NULL
;
446 struct btrfs_trans_handle trans
;
447 struct btrfs_path
*path
= NULL
;
450 root
= btrfs_alloc_dummy_root();
452 test_msg("Couldn't allocate dummy root\n");
457 root
->fs_info
= btrfs_alloc_dummy_fs_info();
458 if (!root
->fs_info
) {
459 test_msg("Couldn't allocate dummy fs info\n");
464 btrfs_set_super_compat_ro_flags(root
->fs_info
->super_copy
,
465 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE
);
466 root
->fs_info
->free_space_root
= root
;
467 root
->fs_info
->tree_root
= root
;
469 root
->node
= alloc_test_extent_buffer(root
->fs_info
, 4096);
471 test_msg("Couldn't allocate dummy buffer\n");
475 btrfs_set_header_level(root
->node
, 0);
476 btrfs_set_header_nritems(root
->node
, 0);
477 root
->alloc_bytenr
+= 8192;
479 cache
= btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE
);
481 test_msg("Couldn't allocate dummy block group cache\n");
485 cache
->bitmap_low_thresh
= 0;
486 cache
->bitmap_high_thresh
= (u32
)-1;
487 cache
->needs_free_space
= 1;
488 cache
->fs_info
= root
->fs_info
;
490 btrfs_init_dummy_trans(&trans
);
492 path
= btrfs_alloc_path();
494 test_msg("Couldn't allocate path\n");
498 ret
= add_block_group_free_space(&trans
, root
->fs_info
, cache
);
500 test_msg("Could not add block group free space\n");
505 ret
= convert_free_space_to_bitmaps(&trans
, root
->fs_info
,
508 test_msg("Could not convert block group to bitmaps\n");
513 ret
= test_func(&trans
, root
->fs_info
, cache
, path
);
517 ret
= remove_block_group_free_space(&trans
, root
->fs_info
, cache
);
519 test_msg("Could not remove block group free space\n");
523 if (btrfs_header_nritems(root
->node
) != 0) {
524 test_msg("Free space tree has leftover items\n");
531 btrfs_free_path(path
);
532 btrfs_free_dummy_block_group(cache
);
533 btrfs_free_dummy_root(root
);
537 static int run_test_both_formats(test_func_t test_func
)
541 ret
= run_test(test_func
, 0);
544 return run_test(test_func
, 1);
547 int btrfs_test_free_space_tree(void)
549 test_func_t tests
[] = {
550 test_empty_block_group
,
552 test_remove_beginning
,
562 test_msg("Running free space tree tests\n");
563 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
564 int ret
= run_test_both_formats(tests
[i
]);
566 test_msg("%pf failed\n", tests
[i
]);