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"
12 #include "../block-group.h"
13 #include "../accessors.h"
15 struct free_space_extent
{
20 static int __check_free_space_extents(struct btrfs_trans_handle
*trans
,
21 struct btrfs_fs_info
*fs_info
,
22 struct btrfs_block_group
*cache
,
23 struct btrfs_path
*path
,
24 const struct free_space_extent
* const extents
,
25 unsigned int num_extents
)
27 struct btrfs_free_space_info
*info
;
29 int prev_bit
= 0, bit
;
30 u64 extent_start
= 0, offset
, end
;
31 u32 flags
, extent_count
;
35 info
= search_free_space_info(trans
, cache
, path
, 0);
37 test_err("could not find free space info");
41 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
42 extent_count
= btrfs_free_space_extent_count(path
->nodes
[0], info
);
44 if (extent_count
!= num_extents
) {
45 test_err("extent count is wrong");
49 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
50 if (path
->slots
[0] != 0)
52 end
= cache
->start
+ cache
->length
;
54 while (++path
->slots
[0] < btrfs_header_nritems(path
->nodes
[0])) {
55 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
56 if (key
.type
!= BTRFS_FREE_SPACE_BITMAP_KEY
)
58 offset
= key
.objectid
;
59 while (offset
< key
.objectid
+ key
.offset
) {
60 bit
= free_space_test_bit(cache
, path
, offset
);
61 if (prev_bit
== 0 && bit
== 1) {
62 extent_start
= offset
;
63 } 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_err("free space tree is invalid");
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
,
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
, cache
, path
, 0);
120 test_err("could not find free space info");
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
, cache
, path
);
136 test_err("could not convert to extents");
140 ret
= convert_free_space_to_bitmaps(trans
, cache
, path
);
142 test_err("could not convert to bitmaps");
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
,
153 struct btrfs_path
*path
,
156 const struct free_space_extent extents
[] = {
157 {cache
->start
, cache
->length
},
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
,
167 struct btrfs_path
*path
,
170 const struct free_space_extent extents
[] = {};
173 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
177 test_err("could not remove free space");
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
,
188 struct btrfs_path
*path
,
191 const struct free_space_extent extents
[] = {
192 {cache
->start
+ alignment
, cache
->length
- alignment
},
196 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
197 cache
->start
, alignment
);
199 test_err("could not remove free space");
203 return check_free_space_extents(trans
, fs_info
, cache
, path
,
204 extents
, ARRAY_SIZE(extents
));
208 static int test_remove_end(struct btrfs_trans_handle
*trans
,
209 struct btrfs_fs_info
*fs_info
,
210 struct btrfs_block_group
*cache
,
211 struct btrfs_path
*path
,
214 const struct free_space_extent extents
[] = {
215 {cache
->start
, cache
->length
- alignment
},
219 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
220 cache
->start
+ cache
->length
- alignment
,
223 test_err("could not remove free space");
227 return check_free_space_extents(trans
, fs_info
, cache
, path
,
228 extents
, ARRAY_SIZE(extents
));
231 static int test_remove_middle(struct btrfs_trans_handle
*trans
,
232 struct btrfs_fs_info
*fs_info
,
233 struct btrfs_block_group
*cache
,
234 struct btrfs_path
*path
,
237 const struct free_space_extent extents
[] = {
238 {cache
->start
, alignment
},
239 {cache
->start
+ 2 * alignment
, cache
->length
- 2 * alignment
},
243 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
244 cache
->start
+ alignment
,
247 test_err("could not remove free space");
251 return check_free_space_extents(trans
, fs_info
, cache
, path
,
252 extents
, ARRAY_SIZE(extents
));
255 static int test_merge_left(struct btrfs_trans_handle
*trans
,
256 struct btrfs_fs_info
*fs_info
,
257 struct btrfs_block_group
*cache
,
258 struct btrfs_path
*path
,
261 const struct free_space_extent extents
[] = {
262 {cache
->start
, 2 * alignment
},
266 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
267 cache
->start
, cache
->length
);
269 test_err("could not remove free space");
273 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
276 test_err("could not add free space");
280 ret
= __add_to_free_space_tree(trans
, cache
, path
,
281 cache
->start
+ alignment
,
284 test_err("could not add free space");
288 return check_free_space_extents(trans
, fs_info
, cache
, path
,
289 extents
, ARRAY_SIZE(extents
));
292 static int test_merge_right(struct btrfs_trans_handle
*trans
,
293 struct btrfs_fs_info
*fs_info
,
294 struct btrfs_block_group
*cache
,
295 struct btrfs_path
*path
,
298 const struct free_space_extent extents
[] = {
299 {cache
->start
+ alignment
, 2 * alignment
},
303 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
304 cache
->start
, cache
->length
);
306 test_err("could not remove free space");
310 ret
= __add_to_free_space_tree(trans
, cache
, path
,
311 cache
->start
+ 2 * alignment
,
314 test_err("could not add free space");
318 ret
= __add_to_free_space_tree(trans
, cache
, path
,
319 cache
->start
+ alignment
,
322 test_err("could not add free space");
326 return check_free_space_extents(trans
, fs_info
, cache
, path
,
327 extents
, ARRAY_SIZE(extents
));
330 static int test_merge_both(struct btrfs_trans_handle
*trans
,
331 struct btrfs_fs_info
*fs_info
,
332 struct btrfs_block_group
*cache
,
333 struct btrfs_path
*path
,
336 const struct free_space_extent extents
[] = {
337 {cache
->start
, 3 * alignment
},
341 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
342 cache
->start
, cache
->length
);
344 test_err("could not remove free space");
348 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
351 test_err("could not add free space");
355 ret
= __add_to_free_space_tree(trans
, cache
, path
,
356 cache
->start
+ 2 * alignment
, alignment
);
358 test_err("could not add free space");
362 ret
= __add_to_free_space_tree(trans
, cache
, path
,
363 cache
->start
+ alignment
, alignment
);
365 test_err("could not add free space");
369 return check_free_space_extents(trans
, fs_info
, cache
, path
,
370 extents
, ARRAY_SIZE(extents
));
373 static int test_merge_none(struct btrfs_trans_handle
*trans
,
374 struct btrfs_fs_info
*fs_info
,
375 struct btrfs_block_group
*cache
,
376 struct btrfs_path
*path
,
379 const struct free_space_extent extents
[] = {
380 {cache
->start
, alignment
},
381 {cache
->start
+ 2 * alignment
, alignment
},
382 {cache
->start
+ 4 * alignment
, alignment
},
386 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
387 cache
->start
, cache
->length
);
389 test_err("could not remove free space");
393 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
396 test_err("could not add free space");
400 ret
= __add_to_free_space_tree(trans
, cache
, path
,
401 cache
->start
+ 4 * alignment
, alignment
);
403 test_err("could not add free space");
407 ret
= __add_to_free_space_tree(trans
, cache
, path
,
408 cache
->start
+ 2 * alignment
, alignment
);
410 test_err("could not add free space");
414 return check_free_space_extents(trans
, fs_info
, cache
, path
,
415 extents
, ARRAY_SIZE(extents
));
418 typedef int (*test_func_t
)(struct btrfs_trans_handle
*,
419 struct btrfs_fs_info
*,
420 struct btrfs_block_group
*,
424 static int run_test(test_func_t test_func
, int bitmaps
, u32 sectorsize
,
425 u32 nodesize
, u32 alignment
)
427 struct btrfs_fs_info
*fs_info
;
428 struct btrfs_root
*root
= NULL
;
429 struct btrfs_block_group
*cache
= NULL
;
430 struct btrfs_trans_handle trans
;
431 struct btrfs_path
*path
= NULL
;
434 fs_info
= btrfs_alloc_dummy_fs_info(nodesize
, sectorsize
);
436 test_std_err(TEST_ALLOC_FS_INFO
);
441 root
= btrfs_alloc_dummy_root(fs_info
);
443 test_std_err(TEST_ALLOC_ROOT
);
448 btrfs_set_super_compat_ro_flags(root
->fs_info
->super_copy
,
449 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE
);
450 root
->root_key
.objectid
= BTRFS_FREE_SPACE_TREE_OBJECTID
;
451 root
->root_key
.type
= BTRFS_ROOT_ITEM_KEY
;
452 root
->root_key
.offset
= 0;
453 btrfs_global_root_insert(root
);
454 root
->fs_info
->tree_root
= root
;
456 root
->node
= alloc_test_extent_buffer(root
->fs_info
, nodesize
);
457 if (IS_ERR(root
->node
)) {
458 test_std_err(TEST_ALLOC_EXTENT_BUFFER
);
459 ret
= PTR_ERR(root
->node
);
462 btrfs_set_header_level(root
->node
, 0);
463 btrfs_set_header_nritems(root
->node
, 0);
464 root
->alloc_bytenr
+= 2 * nodesize
;
466 cache
= btrfs_alloc_dummy_block_group(fs_info
, 8 * alignment
);
468 test_std_err(TEST_ALLOC_BLOCK_GROUP
);
472 cache
->bitmap_low_thresh
= 0;
473 cache
->bitmap_high_thresh
= (u32
)-1;
474 set_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE
, &cache
->runtime_flags
);
475 cache
->fs_info
= root
->fs_info
;
477 btrfs_init_dummy_trans(&trans
, root
->fs_info
);
479 path
= btrfs_alloc_path();
481 test_std_err(TEST_ALLOC_ROOT
);
486 ret
= add_block_group_free_space(&trans
, cache
);
488 test_err("could not add block group free space");
493 ret
= convert_free_space_to_bitmaps(&trans
, cache
, path
);
495 test_err("could not convert block group to bitmaps");
500 ret
= test_func(&trans
, root
->fs_info
, cache
, path
, alignment
);
504 ret
= remove_block_group_free_space(&trans
, cache
);
506 test_err("could not remove block group free space");
510 if (btrfs_header_nritems(root
->node
) != 0) {
511 test_err("free space tree has leftover items");
518 btrfs_free_path(path
);
519 btrfs_free_dummy_block_group(cache
);
520 btrfs_free_dummy_root(root
);
521 btrfs_free_dummy_fs_info(fs_info
);
525 static int run_test_both_formats(test_func_t test_func
, u32 sectorsize
,
526 u32 nodesize
, u32 alignment
)
531 ret
= run_test(test_func
, 0, sectorsize
, nodesize
, alignment
);
534 "%ps failed with extents, sectorsize=%u, nodesize=%u, alignment=%u",
535 test_func
, sectorsize
, nodesize
, alignment
);
539 ret
= run_test(test_func
, 1, sectorsize
, nodesize
, alignment
);
542 "%ps failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u",
543 test_func
, sectorsize
, nodesize
, alignment
);
550 int btrfs_test_free_space_tree(u32 sectorsize
, u32 nodesize
)
552 test_func_t tests
[] = {
553 test_empty_block_group
,
555 test_remove_beginning
,
563 u32 bitmap_alignment
;
568 * Align some operations to a page to flush out bugs in the extent
569 * buffer bitmap handling of highmem.
571 bitmap_alignment
= BTRFS_FREE_SPACE_BITMAP_BITS
* PAGE_SIZE
;
573 test_msg("running free space tree tests");
574 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
577 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,
582 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,