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 <linux/types.h>
20 #include "btrfs-tests.h"
22 #include "../disk-io.h"
23 #include "../free-space-tree.h"
24 #include "../transaction.h"
26 struct free_space_extent
{
31 static int __check_free_space_extents(struct btrfs_trans_handle
*trans
,
32 struct btrfs_fs_info
*fs_info
,
33 struct btrfs_block_group_cache
*cache
,
34 struct btrfs_path
*path
,
35 const struct free_space_extent
* const extents
,
36 unsigned int num_extents
)
38 struct btrfs_free_space_info
*info
;
40 int prev_bit
= 0, bit
;
41 u64 extent_start
= 0, offset
, end
;
42 u32 flags
, extent_count
;
46 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
48 test_msg("Could not find free space info\n");
52 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
53 extent_count
= btrfs_free_space_extent_count(path
->nodes
[0], info
);
55 if (extent_count
!= num_extents
) {
56 test_msg("Extent count is wrong\n");
60 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
61 if (path
->slots
[0] != 0)
63 end
= cache
->key
.objectid
+ cache
->key
.offset
;
65 while (++path
->slots
[0] < btrfs_header_nritems(path
->nodes
[0])) {
66 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
67 if (key
.type
!= BTRFS_FREE_SPACE_BITMAP_KEY
)
69 offset
= key
.objectid
;
70 while (offset
< key
.objectid
+ key
.offset
) {
71 bit
= free_space_test_bit(cache
, path
, offset
);
72 if (prev_bit
== 0 && bit
== 1) {
73 extent_start
= offset
;
74 } else if (prev_bit
== 1 && bit
== 0) {
77 if (i
>= num_extents
||
78 extent_start
!= extents
[i
].start
||
79 offset
- extent_start
!= extents
[i
].length
)
84 offset
+= fs_info
->sectorsize
;
88 if (i
>= num_extents
||
89 extent_start
!= extents
[i
].start
||
90 end
- extent_start
!= extents
[i
].length
)
97 if (btrfs_header_nritems(path
->nodes
[0]) != num_extents
+ 1 ||
100 for (i
= 0; i
< num_extents
; i
++) {
102 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
103 if (key
.type
!= BTRFS_FREE_SPACE_EXTENT_KEY
||
104 key
.objectid
!= extents
[i
].start
||
105 key
.offset
!= extents
[i
].length
)
112 btrfs_release_path(path
);
115 test_msg("Free space tree is invalid\n");
120 static int check_free_space_extents(struct btrfs_trans_handle
*trans
,
121 struct btrfs_fs_info
*fs_info
,
122 struct btrfs_block_group_cache
*cache
,
123 struct btrfs_path
*path
,
124 const struct free_space_extent
* const extents
,
125 unsigned int num_extents
)
127 struct btrfs_free_space_info
*info
;
131 info
= search_free_space_info(trans
, fs_info
, cache
, path
, 0);
133 test_msg("Could not find free space info\n");
134 btrfs_release_path(path
);
135 return PTR_ERR(info
);
137 flags
= btrfs_free_space_flags(path
->nodes
[0], info
);
138 btrfs_release_path(path
);
140 ret
= __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
145 /* Flip it to the other format and check that for good measure. */
146 if (flags
& BTRFS_FREE_SPACE_USING_BITMAPS
) {
147 ret
= convert_free_space_to_extents(trans
, fs_info
, cache
, path
);
149 test_msg("Could not convert to extents\n");
153 ret
= convert_free_space_to_bitmaps(trans
, fs_info
, cache
, path
);
155 test_msg("Could not convert to bitmaps\n");
159 return __check_free_space_extents(trans
, fs_info
, cache
, path
, extents
,
163 static int test_empty_block_group(struct btrfs_trans_handle
*trans
,
164 struct btrfs_fs_info
*fs_info
,
165 struct btrfs_block_group_cache
*cache
,
166 struct btrfs_path
*path
,
169 const struct free_space_extent extents
[] = {
170 {cache
->key
.objectid
, cache
->key
.offset
},
173 return check_free_space_extents(trans
, fs_info
, cache
, path
,
174 extents
, ARRAY_SIZE(extents
));
177 static int test_remove_all(struct btrfs_trans_handle
*trans
,
178 struct btrfs_fs_info
*fs_info
,
179 struct btrfs_block_group_cache
*cache
,
180 struct btrfs_path
*path
,
183 const struct free_space_extent extents
[] = {};
186 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
190 test_msg("Could not remove free space\n");
194 return check_free_space_extents(trans
, fs_info
, cache
, path
,
195 extents
, ARRAY_SIZE(extents
));
198 static int test_remove_beginning(struct btrfs_trans_handle
*trans
,
199 struct btrfs_fs_info
*fs_info
,
200 struct btrfs_block_group_cache
*cache
,
201 struct btrfs_path
*path
,
204 const struct free_space_extent extents
[] = {
205 {cache
->key
.objectid
+ alignment
,
206 cache
->key
.offset
- alignment
},
210 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
211 cache
->key
.objectid
, alignment
);
213 test_msg("Could not remove free space\n");
217 return check_free_space_extents(trans
, fs_info
, cache
, path
,
218 extents
, ARRAY_SIZE(extents
));
222 static int test_remove_end(struct btrfs_trans_handle
*trans
,
223 struct btrfs_fs_info
*fs_info
,
224 struct btrfs_block_group_cache
*cache
,
225 struct btrfs_path
*path
,
228 const struct free_space_extent extents
[] = {
229 {cache
->key
.objectid
, cache
->key
.offset
- alignment
},
233 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
234 cache
->key
.objectid
+
235 cache
->key
.offset
- alignment
,
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
,
252 const struct free_space_extent extents
[] = {
253 {cache
->key
.objectid
, alignment
},
254 {cache
->key
.objectid
+ 2 * alignment
,
255 cache
->key
.offset
- 2 * alignment
},
259 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
260 cache
->key
.objectid
+ alignment
,
263 test_msg("Could not remove free space\n");
267 return check_free_space_extents(trans
, fs_info
, cache
, path
,
268 extents
, ARRAY_SIZE(extents
));
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
,
277 const struct free_space_extent extents
[] = {
278 {cache
->key
.objectid
, 2 * alignment
},
282 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
286 test_msg("Could not remove free space\n");
290 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
291 cache
->key
.objectid
, alignment
);
293 test_msg("Could not add free space\n");
297 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
298 cache
->key
.objectid
+ alignment
,
301 test_msg("Could not add free space\n");
305 return check_free_space_extents(trans
, fs_info
, cache
, path
,
306 extents
, ARRAY_SIZE(extents
));
309 static int test_merge_right(struct btrfs_trans_handle
*trans
,
310 struct btrfs_fs_info
*fs_info
,
311 struct btrfs_block_group_cache
*cache
,
312 struct btrfs_path
*path
,
315 const struct free_space_extent extents
[] = {
316 {cache
->key
.objectid
+ alignment
, 2 * alignment
},
320 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
324 test_msg("Could not remove free space\n");
328 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
329 cache
->key
.objectid
+ 2 * alignment
,
332 test_msg("Could not add free space\n");
336 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
337 cache
->key
.objectid
+ alignment
,
340 test_msg("Could not add free space\n");
344 return check_free_space_extents(trans
, fs_info
, cache
, path
,
345 extents
, ARRAY_SIZE(extents
));
348 static int test_merge_both(struct btrfs_trans_handle
*trans
,
349 struct btrfs_fs_info
*fs_info
,
350 struct btrfs_block_group_cache
*cache
,
351 struct btrfs_path
*path
,
354 const struct free_space_extent extents
[] = {
355 {cache
->key
.objectid
, 3 * alignment
},
359 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
363 test_msg("Could not remove free space\n");
367 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
368 cache
->key
.objectid
, alignment
);
370 test_msg("Could not add free space\n");
374 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
375 cache
->key
.objectid
+ 2 * alignment
,
378 test_msg("Could not add free space\n");
382 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
383 cache
->key
.objectid
+ alignment
,
386 test_msg("Could not add free space\n");
390 return check_free_space_extents(trans
, fs_info
, cache
, path
,
391 extents
, ARRAY_SIZE(extents
));
394 static int test_merge_none(struct btrfs_trans_handle
*trans
,
395 struct btrfs_fs_info
*fs_info
,
396 struct btrfs_block_group_cache
*cache
,
397 struct btrfs_path
*path
,
400 const struct free_space_extent extents
[] = {
401 {cache
->key
.objectid
, alignment
},
402 {cache
->key
.objectid
+ 2 * alignment
, alignment
},
403 {cache
->key
.objectid
+ 4 * alignment
, alignment
},
407 ret
= __remove_from_free_space_tree(trans
, fs_info
, cache
, path
,
411 test_msg("Could not remove free space\n");
415 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
416 cache
->key
.objectid
, alignment
);
418 test_msg("Could not add free space\n");
422 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
423 cache
->key
.objectid
+ 4 * alignment
,
426 test_msg("Could not add free space\n");
430 ret
= __add_to_free_space_tree(trans
, fs_info
, cache
, path
,
431 cache
->key
.objectid
+ 2 * alignment
,
434 test_msg("Could not add free space\n");
438 return check_free_space_extents(trans
, fs_info
, cache
, path
,
439 extents
, ARRAY_SIZE(extents
));
442 typedef int (*test_func_t
)(struct btrfs_trans_handle
*,
443 struct btrfs_fs_info
*,
444 struct btrfs_block_group_cache
*,
448 static int run_test(test_func_t test_func
, int bitmaps
, u32 sectorsize
,
449 u32 nodesize
, u32 alignment
)
451 struct btrfs_fs_info
*fs_info
;
452 struct btrfs_root
*root
= NULL
;
453 struct btrfs_block_group_cache
*cache
= NULL
;
454 struct btrfs_trans_handle trans
;
455 struct btrfs_path
*path
= NULL
;
458 fs_info
= btrfs_alloc_dummy_fs_info(nodesize
, sectorsize
);
460 test_msg("Couldn't allocate dummy fs info\n");
465 root
= btrfs_alloc_dummy_root(fs_info
);
467 test_msg("Couldn't allocate dummy root\n");
472 btrfs_set_super_compat_ro_flags(root
->fs_info
->super_copy
,
473 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE
);
474 root
->fs_info
->free_space_root
= root
;
475 root
->fs_info
->tree_root
= root
;
477 root
->node
= alloc_test_extent_buffer(root
->fs_info
, nodesize
);
479 test_msg("Couldn't allocate dummy buffer\n");
483 btrfs_set_header_level(root
->node
, 0);
484 btrfs_set_header_nritems(root
->node
, 0);
485 root
->alloc_bytenr
+= 2 * nodesize
;
487 cache
= btrfs_alloc_dummy_block_group(fs_info
, 8 * alignment
);
489 test_msg("Couldn't allocate dummy block group cache\n");
493 cache
->bitmap_low_thresh
= 0;
494 cache
->bitmap_high_thresh
= (u32
)-1;
495 cache
->needs_free_space
= 1;
496 cache
->fs_info
= root
->fs_info
;
498 btrfs_init_dummy_trans(&trans
);
500 path
= btrfs_alloc_path();
502 test_msg("Couldn't allocate path\n");
507 ret
= add_block_group_free_space(&trans
, root
->fs_info
, cache
);
509 test_msg("Could not add block group free space\n");
514 ret
= convert_free_space_to_bitmaps(&trans
, root
->fs_info
,
517 test_msg("Could not convert block group to bitmaps\n");
522 ret
= test_func(&trans
, root
->fs_info
, cache
, path
, alignment
);
526 ret
= remove_block_group_free_space(&trans
, root
->fs_info
, cache
);
528 test_msg("Could not remove block group free space\n");
532 if (btrfs_header_nritems(root
->node
) != 0) {
533 test_msg("Free space tree has leftover items\n");
540 btrfs_free_path(path
);
541 btrfs_free_dummy_block_group(cache
);
542 btrfs_free_dummy_root(root
);
543 btrfs_free_dummy_fs_info(fs_info
);
547 static int run_test_both_formats(test_func_t test_func
, u32 sectorsize
,
548 u32 nodesize
, u32 alignment
)
553 ret
= run_test(test_func
, 0, sectorsize
, nodesize
, alignment
);
555 test_msg("%pf failed with extents, sectorsize=%u, nodesize=%u, alignment=%u\n",
556 test_func
, sectorsize
, nodesize
, alignment
);
560 ret
= run_test(test_func
, 1, sectorsize
, nodesize
, alignment
);
562 test_msg("%pf failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u\n",
563 test_func
, sectorsize
, nodesize
, alignment
);
570 int btrfs_test_free_space_tree(u32 sectorsize
, u32 nodesize
)
572 test_func_t tests
[] = {
573 test_empty_block_group
,
575 test_remove_beginning
,
583 u32 bitmap_alignment
;
588 * Align some operations to a page to flush out bugs in the extent
589 * buffer bitmap handling of highmem.
591 bitmap_alignment
= BTRFS_FREE_SPACE_BITMAP_BITS
* PAGE_SIZE
;
593 test_msg("Running free space tree tests\n");
594 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
597 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,
602 ret
= run_test_both_formats(tests
[i
], sectorsize
, nodesize
,