1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015 Facebook. All rights reserved.
6 #include <linux/types.h>
7 #include "btrfs-tests.h"
9 #include "../disk-io.h"
10 #include "../free-space-tree.h"
11 #include "../transaction.h"
13 struct free_space_extent
{
18 static int __check_free_space_extents(struct btrfs_trans_handle
*trans
,
19 struct btrfs_fs_info
*fs_info
,
20 struct btrfs_block_group_cache
*cache
,
21 struct btrfs_path
*path
,
22 const struct free_space_extent
* const extents
,
23 unsigned int num_extents
)
25 struct btrfs_free_space_info
*info
;
27 int prev_bit
= 0, bit
;
28 u64 extent_start
= 0, offset
, end
;
29 u32 flags
, extent_count
;
33 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
35 test_msg("Could not find free space info\n");
39 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
40 extent_count
= btrfs_free_space_extent_count(path
->nodes
[0], info
);
42 if (extent_count
!= num_extents
) {
43 test_msg("Extent count is wrong\n");
47 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
48 if (path
->slots
[0] != 0)
50 end
= cache
->key
.objectid
+ cache
->key
.offset
;
52 while (++path
->slots
[0] < btrfs_header_nritems(path
->nodes
[0])) {
53 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
54 if (key
.type
!= BTRFS_FREE_SPACE_BITMAP_KEY
)
56 offset
= key
.objectid
;
57 while (offset
< key
.objectid
+ key
.offset
) {
58 bit
= free_space_test_bit(cache
, path
, offset
);
59 if (prev_bit
== 0 && bit
== 1) {
60 extent_start
= offset
;
61 } else if (prev_bit
== 1 && bit
== 0) {
64 if (i
>= num_extents
||
65 extent_start
!= extents
[i
].start
||
66 offset
- extent_start
!= extents
[i
].length
)
71 offset
+= fs_info
->sectorsize
;
75 if (i
>= num_extents
||
76 extent_start
!= extents
[i
].start
||
77 end
- extent_start
!= extents
[i
].length
)
84 if (btrfs_header_nritems(path
->nodes
[0]) != num_extents
+ 1 ||
87 for (i
= 0; i
< num_extents
; i
++) {
89 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
90 if (key
.type
!= BTRFS_FREE_SPACE_EXTENT_KEY
||
91 key
.objectid
!= extents
[i
].start
||
92 key
.offset
!= extents
[i
].length
)
99 btrfs_release_path(path
);
102 test_msg("Free space tree is invalid\n");
107 static int check_free_space_extents(struct btrfs_trans_handle
*trans
,
108 struct btrfs_fs_info
*fs_info
,
109 struct btrfs_block_group_cache
*cache
,
110 struct btrfs_path
*path
,
111 const struct free_space_extent
* const extents
,
112 unsigned int num_extents
)
114 struct btrfs_free_space_info
*info
;
118 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
120 test_msg("Could not find free space info\n");
121 btrfs_release_path(path
);
122 return PTR_ERR(info
);
124 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
125 btrfs_release_path(path
);
127 ret
= __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
132 /* Flip it to the other format and check that for good measure. */
133 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
134 ret
= convert_free_space_to_extents(trans
, fs_info
, cache
, path
);
136 test_msg("Could not convert to extents\n");
140 ret
= convert_free_space_to_bitmaps(trans
, fs_info
, cache
, path
);
142 test_msg("Could not convert to bitmaps\n");
146 return __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
150 static int test_empty_block_group(struct btrfs_trans_handle
*trans
,
151 struct btrfs_fs_info
*fs_info
,
152 struct btrfs_block_group_cache
*cache
,
153 struct btrfs_path
*path
,
156 const struct free_space_extent extents
[] = {
157 {cache
->key
.objectid
, cache
->key
.offset
},
160 return check_free_space_extents(trans
, fs_info
, cache
, path
,
161 extents
, ARRAY_SIZE(extents
));
164 static int test_remove_all(struct btrfs_trans_handle
*trans
,
165 struct btrfs_fs_info
*fs_info
,
166 struct btrfs_block_group_cache
*cache
,
167 struct btrfs_path
*path
,
170 const struct free_space_extent extents
[] = {};
173 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
177 test_msg("Could not remove free space\n");
181 return check_free_space_extents(trans
, fs_info
, cache
, path
,
182 extents
, ARRAY_SIZE(extents
));
185 static int test_remove_beginning(struct btrfs_trans_handle
*trans
,
186 struct btrfs_fs_info
*fs_info
,
187 struct btrfs_block_group_cache
*cache
,
188 struct btrfs_path
*path
,
191 const struct free_space_extent extents
[] = {
192 {cache
->key
.objectid
+ alignment
,
193 cache
->key
.offset
- alignment
},
197 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
198 cache
->key
.objectid
, alignment
);
200 test_msg("Could not remove free space\n");
204 return check_free_space_extents(trans
, fs_info
, cache
, path
,
205 extents
, ARRAY_SIZE(extents
));
209 static int test_remove_end(struct btrfs_trans_handle
*trans
,
210 struct btrfs_fs_info
*fs_info
,
211 struct btrfs_block_group_cache
*cache
,
212 struct btrfs_path
*path
,
215 const struct free_space_extent extents
[] = {
216 {cache
->key
.objectid
, cache
->key
.offset
- alignment
},
220 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
221 cache
->key
.objectid
+
222 cache
->key
.offset
- alignment
,
225 test_msg("Could not remove free space\n");
229 return check_free_space_extents(trans
, fs_info
, cache
, path
,
230 extents
, ARRAY_SIZE(extents
));
233 static int test_remove_middle(struct btrfs_trans_handle
*trans
,
234 struct btrfs_fs_info
*fs_info
,
235 struct btrfs_block_group_cache
*cache
,
236 struct btrfs_path
*path
,
239 const struct free_space_extent extents
[] = {
240 {cache
->key
.objectid
, alignment
},
241 {cache
->key
.objectid
+ 2 * alignment
,
242 cache
->key
.offset
- 2 * alignment
},
246 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
247 cache
->key
.objectid
+ alignment
,
250 test_msg("Could not remove free space\n");
254 return check_free_space_extents(trans
, fs_info
, cache
, path
,
255 extents
, ARRAY_SIZE(extents
));
258 static int test_merge_left(struct btrfs_trans_handle
*trans
,
259 struct btrfs_fs_info
*fs_info
,
260 struct btrfs_block_group_cache
*cache
,
261 struct btrfs_path
*path
,
264 const struct free_space_extent extents
[] = {
265 {cache
->key
.objectid
, 2 * alignment
},
269 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
273 test_msg("Could not remove free space\n");
277 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
278 cache
->key
.objectid
, alignment
);
280 test_msg("Could not add free space\n");
284 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
285 cache
->key
.objectid
+ alignment
,
288 test_msg("Could not add free space\n");
292 return check_free_space_extents(trans
, fs_info
, cache
, path
,
293 extents
, ARRAY_SIZE(extents
));
296 static int test_merge_right(struct btrfs_trans_handle
*trans
,
297 struct btrfs_fs_info
*fs_info
,
298 struct btrfs_block_group_cache
*cache
,
299 struct btrfs_path
*path
,
302 const struct free_space_extent extents
[] = {
303 {cache
->key
.objectid
+ alignment
, 2 * alignment
},
307 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
311 test_msg("Could not remove free space\n");
315 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
316 cache
->key
.objectid
+ 2 * alignment
,
319 test_msg("Could not add free space\n");
323 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
324 cache
->key
.objectid
+ alignment
,
327 test_msg("Could not add free space\n");
331 return check_free_space_extents(trans
, fs_info
, cache
, path
,
332 extents
, ARRAY_SIZE(extents
));
335 static int test_merge_both(struct btrfs_trans_handle
*trans
,
336 struct btrfs_fs_info
*fs_info
,
337 struct btrfs_block_group_cache
*cache
,
338 struct btrfs_path
*path
,
341 const struct free_space_extent extents
[] = {
342 {cache
->key
.objectid
, 3 * alignment
},
346 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
350 test_msg("Could not remove free space\n");
354 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
355 cache
->key
.objectid
, alignment
);
357 test_msg("Could not add free space\n");
361 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
362 cache
->key
.objectid
+ 2 * alignment
,
365 test_msg("Could not add free space\n");
369 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
370 cache
->key
.objectid
+ alignment
,
373 test_msg("Could not add free space\n");
377 return check_free_space_extents(trans
, fs_info
, cache
, path
,
378 extents
, ARRAY_SIZE(extents
));
381 static int test_merge_none(struct btrfs_trans_handle
*trans
,
382 struct btrfs_fs_info
*fs_info
,
383 struct btrfs_block_group_cache
*cache
,
384 struct btrfs_path
*path
,
387 const struct free_space_extent extents
[] = {
388 {cache
->key
.objectid
, alignment
},
389 {cache
->key
.objectid
+ 2 * alignment
, alignment
},
390 {cache
->key
.objectid
+ 4 * alignment
, alignment
},
394 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
398 test_msg("Could not remove free space\n");
402 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
403 cache
->key
.objectid
, alignment
);
405 test_msg("Could not add free space\n");
409 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
410 cache
->key
.objectid
+ 4 * alignment
,
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
+ 2 * alignment
,
421 test_msg("Could not add free space\n");
425 return check_free_space_extents(trans
, fs_info
, cache
, path
,
426 extents
, ARRAY_SIZE(extents
));
429 typedef int (*test_func_t
)(struct btrfs_trans_handle
*,
430 struct btrfs_fs_info
*,
431 struct btrfs_block_group_cache
*,
435 static int run_test(test_func_t test_func
, int bitmaps
, u32 sectorsize
,
436 u32 nodesize
, u32 alignment
)
438 struct btrfs_fs_info
*fs_info
;
439 struct btrfs_root
*root
= NULL
;
440 struct btrfs_block_group_cache
*cache
= NULL
;
441 struct btrfs_trans_handle trans
;
442 struct btrfs_path
*path
= NULL
;
445 fs_info
= btrfs_alloc_dummy_fs_info(nodesize
, sectorsize
);
447 test_msg("Couldn't allocate dummy fs info\n");
452 root
= btrfs_alloc_dummy_root(fs_info
);
454 test_msg("Couldn't allocate dummy root\n");
459 btrfs_set_super_compat_ro_flags(root
->fs_info
->super_copy
,
460 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE
);
461 root
->fs_info
->free_space_root
= root
;
462 root
->fs_info
->tree_root
= root
;
464 root
->node
= alloc_test_extent_buffer(root
->fs_info
, nodesize
);
466 test_msg("Couldn't allocate dummy buffer\n");
470 btrfs_set_header_level(root
->node
, 0);
471 btrfs_set_header_nritems(root
->node
, 0);
472 root
->alloc_bytenr
+= 2 * nodesize
;
474 cache
= btrfs_alloc_dummy_block_group(fs_info
, 8 * alignment
);
476 test_msg("Couldn't allocate dummy block group cache\n");
480 cache
->bitmap_low_thresh
= 0;
481 cache
->bitmap_high_thresh
= (u32
)-1;
482 cache
->needs_free_space
= 1;
483 cache
->fs_info
= root
->fs_info
;
485 btrfs_init_dummy_trans(&trans
);
487 path
= btrfs_alloc_path();
489 test_msg("Couldn't allocate path\n");
494 ret
= add_block_group_free_space(&trans
, root
->fs_info
, cache
);
496 test_msg("Could not add block group free space\n");
501 ret
= convert_free_space_to_bitmaps(&trans
, root
->fs_info
,
504 test_msg("Could not convert block group to bitmaps\n");
509 ret
= test_func(&trans
, root
->fs_info
, cache
, path
, alignment
);
513 ret
= remove_block_group_free_space(&trans
, root
->fs_info
, cache
);
515 test_msg("Could not remove block group free space\n");
519 if (btrfs_header_nritems(root
->node
) != 0) {
520 test_msg("Free space tree has leftover items\n");
527 btrfs_free_path(path
);
528 btrfs_free_dummy_block_group(cache
);
529 btrfs_free_dummy_root(root
);
530 btrfs_free_dummy_fs_info(fs_info
);
534 static int run_test_both_formats(test_func_t test_func
, u32 sectorsize
,
535 u32 nodesize
, u32 alignment
)
540 ret
= run_test(test_func
, 0, sectorsize
, nodesize
, alignment
);
542 test_msg("%pf failed with extents, sectorsize=%u, nodesize=%u, alignment=%u\n",
543 test_func
, sectorsize
, nodesize
, alignment
);
547 ret
= run_test(test_func
, 1, sectorsize
, nodesize
, alignment
);
549 test_msg("%pf failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u\n",
550 test_func
, sectorsize
, nodesize
, alignment
);
557 int btrfs_test_free_space_tree(u32 sectorsize
, u32 nodesize
)
559 test_func_t tests
[] = {
560 test_empty_block_group
,
562 test_remove_beginning
,
570 u32 bitmap_alignment
;
575 * Align some operations to a page to flush out bugs in the extent
576 * buffer bitmap handling of highmem.
578 bitmap_alignment
= BTRFS_FREE_SPACE_BITMAP_BITS
* PAGE_SIZE
;
580 test_msg("Running free space tree tests\n");
581 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
584 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,
589 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,