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"
14 struct free_space_extent
{
19 static int __check_free_space_extents(struct btrfs_trans_handle
*trans
,
20 struct btrfs_fs_info
*fs_info
,
21 struct btrfs_block_group
*cache
,
22 struct btrfs_path
*path
,
23 const struct free_space_extent
* const extents
,
24 unsigned int num_extents
)
26 struct btrfs_free_space_info
*info
;
28 int prev_bit
= 0, bit
;
29 u64 extent_start
= 0, offset
, end
;
30 u32 flags
, extent_count
;
34 info
= search_free_space_info(trans
, cache
, path
, 0);
36 test_err("could not find free space info");
40 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
41 extent_count
= btrfs_free_space_extent_count(path
->nodes
[0], info
);
43 if (extent_count
!= num_extents
) {
44 test_err("extent count is wrong");
48 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
49 if (path
->slots
[0] != 0)
51 end
= cache
->start
+ cache
->length
;
53 while (++path
->slots
[0] < btrfs_header_nritems(path
->nodes
[0])) {
54 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
55 if (key
.type
!= BTRFS_FREE_SPACE_BITMAP_KEY
)
57 offset
= key
.objectid
;
58 while (offset
< key
.objectid
+ key
.offset
) {
59 bit
= free_space_test_bit(cache
, path
, offset
);
60 if (prev_bit
== 0 && bit
== 1) {
61 extent_start
= offset
;
62 } else if (prev_bit
== 1 && bit
== 0) {
63 if (i
>= num_extents
||
64 extent_start
!= extents
[i
].start
||
65 offset
- extent_start
!= extents
[i
].length
)
70 offset
+= fs_info
->sectorsize
;
74 if (i
>= num_extents
||
75 extent_start
!= extents
[i
].start
||
76 end
- extent_start
!= extents
[i
].length
)
83 if (btrfs_header_nritems(path
->nodes
[0]) != num_extents
+ 1 ||
86 for (i
= 0; i
< num_extents
; i
++) {
88 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
89 if (key
.type
!= BTRFS_FREE_SPACE_EXTENT_KEY
||
90 key
.objectid
!= extents
[i
].start
||
91 key
.offset
!= extents
[i
].length
)
98 btrfs_release_path(path
);
101 test_err("free space tree is invalid");
106 static int check_free_space_extents(struct btrfs_trans_handle
*trans
,
107 struct btrfs_fs_info
*fs_info
,
108 struct btrfs_block_group
*cache
,
109 struct btrfs_path
*path
,
110 const struct free_space_extent
* const extents
,
111 unsigned int num_extents
)
113 struct btrfs_free_space_info
*info
;
117 info
= search_free_space_info(trans
, cache
, path
, 0);
119 test_err("could not find free space info");
120 btrfs_release_path(path
);
121 return PTR_ERR(info
);
123 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
124 btrfs_release_path(path
);
126 ret
= __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
131 /* Flip it to the other format and check that for good measure. */
132 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
133 ret
= convert_free_space_to_extents(trans
, cache
, path
);
135 test_err("could not convert to extents");
139 ret
= convert_free_space_to_bitmaps(trans
, cache
, path
);
141 test_err("could not convert to bitmaps");
145 return __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
149 static int test_empty_block_group(struct btrfs_trans_handle
*trans
,
150 struct btrfs_fs_info
*fs_info
,
151 struct btrfs_block_group
*cache
,
152 struct btrfs_path
*path
,
155 const struct free_space_extent extents
[] = {
156 {cache
->start
, cache
->length
},
159 return check_free_space_extents(trans
, fs_info
, cache
, path
,
160 extents
, ARRAY_SIZE(extents
));
163 static int test_remove_all(struct btrfs_trans_handle
*trans
,
164 struct btrfs_fs_info
*fs_info
,
165 struct btrfs_block_group
*cache
,
166 struct btrfs_path
*path
,
169 const struct free_space_extent extents
[] = {};
172 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
176 test_err("could not remove free space");
180 return check_free_space_extents(trans
, fs_info
, cache
, path
,
181 extents
, ARRAY_SIZE(extents
));
184 static int test_remove_beginning(struct btrfs_trans_handle
*trans
,
185 struct btrfs_fs_info
*fs_info
,
186 struct btrfs_block_group
*cache
,
187 struct btrfs_path
*path
,
190 const struct free_space_extent extents
[] = {
191 {cache
->start
+ alignment
, cache
->length
- alignment
},
195 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
196 cache
->start
, alignment
);
198 test_err("could not remove free space");
202 return check_free_space_extents(trans
, fs_info
, cache
, path
,
203 extents
, ARRAY_SIZE(extents
));
207 static int test_remove_end(struct btrfs_trans_handle
*trans
,
208 struct btrfs_fs_info
*fs_info
,
209 struct btrfs_block_group
*cache
,
210 struct btrfs_path
*path
,
213 const struct free_space_extent extents
[] = {
214 {cache
->start
, cache
->length
- alignment
},
218 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
219 cache
->start
+ cache
->length
- alignment
,
222 test_err("could not remove free space");
226 return check_free_space_extents(trans
, fs_info
, cache
, path
,
227 extents
, ARRAY_SIZE(extents
));
230 static int test_remove_middle(struct btrfs_trans_handle
*trans
,
231 struct btrfs_fs_info
*fs_info
,
232 struct btrfs_block_group
*cache
,
233 struct btrfs_path
*path
,
236 const struct free_space_extent extents
[] = {
237 {cache
->start
, alignment
},
238 {cache
->start
+ 2 * alignment
, cache
->length
- 2 * alignment
},
242 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
243 cache
->start
+ alignment
,
246 test_err("could not remove free space");
250 return check_free_space_extents(trans
, fs_info
, cache
, path
,
251 extents
, ARRAY_SIZE(extents
));
254 static int test_merge_left(struct btrfs_trans_handle
*trans
,
255 struct btrfs_fs_info
*fs_info
,
256 struct btrfs_block_group
*cache
,
257 struct btrfs_path
*path
,
260 const struct free_space_extent extents
[] = {
261 {cache
->start
, 2 * alignment
},
265 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
266 cache
->start
, cache
->length
);
268 test_err("could not remove free space");
272 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
275 test_err("could not add free space");
279 ret
= __add_to_free_space_tree(trans
, cache
, path
,
280 cache
->start
+ alignment
,
283 test_err("could not add free space");
287 return check_free_space_extents(trans
, fs_info
, cache
, path
,
288 extents
, ARRAY_SIZE(extents
));
291 static int test_merge_right(struct btrfs_trans_handle
*trans
,
292 struct btrfs_fs_info
*fs_info
,
293 struct btrfs_block_group
*cache
,
294 struct btrfs_path
*path
,
297 const struct free_space_extent extents
[] = {
298 {cache
->start
+ alignment
, 2 * alignment
},
302 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
303 cache
->start
, cache
->length
);
305 test_err("could not remove free space");
309 ret
= __add_to_free_space_tree(trans
, cache
, path
,
310 cache
->start
+ 2 * alignment
,
313 test_err("could not add free space");
317 ret
= __add_to_free_space_tree(trans
, cache
, path
,
318 cache
->start
+ alignment
,
321 test_err("could not add free space");
325 return check_free_space_extents(trans
, fs_info
, cache
, path
,
326 extents
, ARRAY_SIZE(extents
));
329 static int test_merge_both(struct btrfs_trans_handle
*trans
,
330 struct btrfs_fs_info
*fs_info
,
331 struct btrfs_block_group
*cache
,
332 struct btrfs_path
*path
,
335 const struct free_space_extent extents
[] = {
336 {cache
->start
, 3 * alignment
},
340 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
341 cache
->start
, cache
->length
);
343 test_err("could not remove free space");
347 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
350 test_err("could not add free space");
354 ret
= __add_to_free_space_tree(trans
, cache
, path
,
355 cache
->start
+ 2 * alignment
, alignment
);
357 test_err("could not add free space");
361 ret
= __add_to_free_space_tree(trans
, cache
, path
,
362 cache
->start
+ alignment
, alignment
);
364 test_err("could not add free space");
368 return check_free_space_extents(trans
, fs_info
, cache
, path
,
369 extents
, ARRAY_SIZE(extents
));
372 static int test_merge_none(struct btrfs_trans_handle
*trans
,
373 struct btrfs_fs_info
*fs_info
,
374 struct btrfs_block_group
*cache
,
375 struct btrfs_path
*path
,
378 const struct free_space_extent extents
[] = {
379 {cache
->start
, alignment
},
380 {cache
->start
+ 2 * alignment
, alignment
},
381 {cache
->start
+ 4 * alignment
, alignment
},
385 ret
= __remove_from_free_space_tree(trans
, cache
, path
,
386 cache
->start
, cache
->length
);
388 test_err("could not remove free space");
392 ret
= __add_to_free_space_tree(trans
, cache
, path
, cache
->start
,
395 test_err("could not add free space");
399 ret
= __add_to_free_space_tree(trans
, cache
, path
,
400 cache
->start
+ 4 * alignment
, alignment
);
402 test_err("could not add free space");
406 ret
= __add_to_free_space_tree(trans
, cache
, path
,
407 cache
->start
+ 2 * alignment
, alignment
);
409 test_err("could not add free space");
413 return check_free_space_extents(trans
, fs_info
, cache
, path
,
414 extents
, ARRAY_SIZE(extents
));
417 typedef int (*test_func_t
)(struct btrfs_trans_handle
*,
418 struct btrfs_fs_info
*,
419 struct btrfs_block_group
*,
423 static int run_test(test_func_t test_func
, int bitmaps
, u32 sectorsize
,
424 u32 nodesize
, u32 alignment
)
426 struct btrfs_fs_info
*fs_info
;
427 struct btrfs_root
*root
= NULL
;
428 struct btrfs_block_group
*cache
= NULL
;
429 struct btrfs_trans_handle trans
;
430 struct btrfs_path
*path
= NULL
;
433 fs_info
= btrfs_alloc_dummy_fs_info(nodesize
, sectorsize
);
435 test_std_err(TEST_ALLOC_FS_INFO
);
440 root
= btrfs_alloc_dummy_root(fs_info
);
442 test_std_err(TEST_ALLOC_ROOT
);
447 btrfs_set_super_compat_ro_flags(root
->fs_info
->super_copy
,
448 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE
);
449 root
->fs_info
->free_space_root
= root
;
450 root
->fs_info
->tree_root
= root
;
452 root
->node
= alloc_test_extent_buffer(root
->fs_info
, nodesize
);
453 if (IS_ERR(root
->node
)) {
454 test_std_err(TEST_ALLOC_EXTENT_BUFFER
);
455 ret
= PTR_ERR(root
->node
);
458 btrfs_set_header_level(root
->node
, 0);
459 btrfs_set_header_nritems(root
->node
, 0);
460 root
->alloc_bytenr
+= 2 * nodesize
;
462 cache
= btrfs_alloc_dummy_block_group(fs_info
, 8 * alignment
);
464 test_std_err(TEST_ALLOC_BLOCK_GROUP
);
468 cache
->bitmap_low_thresh
= 0;
469 cache
->bitmap_high_thresh
= (u32
)-1;
470 cache
->needs_free_space
= 1;
471 cache
->fs_info
= root
->fs_info
;
473 btrfs_init_dummy_trans(&trans
, root
->fs_info
);
475 path
= btrfs_alloc_path();
477 test_std_err(TEST_ALLOC_ROOT
);
482 ret
= add_block_group_free_space(&trans
, cache
);
484 test_err("could not add block group free space");
489 ret
= convert_free_space_to_bitmaps(&trans
, cache
, path
);
491 test_err("could not convert block group to bitmaps");
496 ret
= test_func(&trans
, root
->fs_info
, cache
, path
, alignment
);
500 ret
= remove_block_group_free_space(&trans
, cache
);
502 test_err("could not remove block group free space");
506 if (btrfs_header_nritems(root
->node
) != 0) {
507 test_err("free space tree has leftover items");
514 btrfs_free_path(path
);
515 btrfs_free_dummy_block_group(cache
);
516 btrfs_free_dummy_root(root
);
517 btrfs_free_dummy_fs_info(fs_info
);
521 static int run_test_both_formats(test_func_t test_func
, u32 sectorsize
,
522 u32 nodesize
, u32 alignment
)
527 ret
= run_test(test_func
, 0, sectorsize
, nodesize
, alignment
);
530 "%ps failed with extents, sectorsize=%u, nodesize=%u, alignment=%u",
531 test_func
, sectorsize
, nodesize
, alignment
);
535 ret
= run_test(test_func
, 1, sectorsize
, nodesize
, alignment
);
538 "%ps failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u",
539 test_func
, sectorsize
, nodesize
, alignment
);
546 int btrfs_test_free_space_tree(u32 sectorsize
, u32 nodesize
)
548 test_func_t tests
[] = {
549 test_empty_block_group
,
551 test_remove_beginning
,
559 u32 bitmap_alignment
;
564 * Align some operations to a page to flush out bugs in the extent
565 * buffer bitmap handling of highmem.
567 bitmap_alignment
= BTRFS_FREE_SPACE_BITMAP_BITS
* PAGE_SIZE
;
569 test_msg("running free space tree tests");
570 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
573 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,
578 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,