1 #define _XOPEN_SOURCE 500
6 #include "kerncompat.h"
7 #include "radix-tree.h"
10 #include "print-tree.h"
11 #include "transaction.h"
12 #include "bit-radix.h"
14 static u64 blocks_used
= 0;
15 static u64 total_csum_bytes
= 0;
16 static u64 total_btree_blocks
= 0;
17 static u64 btree_space_waste
= 0;
19 struct extent_record
{
20 struct btrfs_disk_key parent_key
;
29 static int check_node(struct btrfs_root
*root
,
30 struct btrfs_disk_key
*parent_key
,
31 struct btrfs_node
*node
)
34 u32 nritems
= btrfs_header_nritems(&node
->header
);
36 if (nritems
== 0 || nritems
> BTRFS_NODEPTRS_PER_BLOCK(root
))
38 if (parent_key
->flags
) {
39 if (memcmp(parent_key
, &node
->ptrs
[0].key
,
40 sizeof(struct btrfs_disk_key
)))
43 for (i
= 0; nritems
> 1 && i
< nritems
- 2; i
++) {
44 struct btrfs_key cpukey
;
45 btrfs_disk_key_to_cpu(&cpukey
, &node
->ptrs
[i
+ 1].key
);
46 if (btrfs_comp_keys(&node
->ptrs
[i
].key
, &cpukey
) >= 0)
52 static int check_leaf(struct btrfs_root
*root
,
53 struct btrfs_disk_key
*parent_key
,
54 struct btrfs_leaf
*leaf
)
57 u32 nritems
= btrfs_header_nritems(&leaf
->header
);
59 if (btrfs_header_level(&leaf
->header
) != 0) {
60 fprintf(stderr
, "leaf is not a leaf %Lu\n",
61 btrfs_header_blocknr(&leaf
->header
));
64 if (btrfs_leaf_free_space(root
, leaf
) < 0) {
65 fprintf(stderr
, "leaf free space incorrect %Lu %d\n",
66 btrfs_header_blocknr(&leaf
->header
),
67 btrfs_leaf_free_space(root
, leaf
));
74 if (parent_key
->flags
) {
75 if (memcmp(parent_key
, &leaf
->items
[0].key
,
76 sizeof(struct btrfs_disk_key
))) {
77 fprintf(stderr
, "leaf parent key incorrect %Lu\n",
78 btrfs_header_blocknr(&leaf
->header
));
82 for (i
= 0; nritems
> 1 && i
< nritems
- 2; i
++) {
83 struct btrfs_key cpukey
;
84 btrfs_disk_key_to_cpu(&cpukey
, &leaf
->items
[i
+ 1].key
);
85 if (btrfs_comp_keys(&leaf
->items
[i
].key
,
88 if (btrfs_item_offset(leaf
->items
+ i
) !=
89 btrfs_item_end(leaf
->items
+ i
+ 1))
92 if (btrfs_item_offset(leaf
->items
+ i
) +
93 btrfs_item_size(leaf
->items
+ i
) !=
94 BTRFS_LEAF_DATA_SIZE(root
))
101 static int maybe_free_extent_rec(struct radix_tree_root
*extent_radix
,
102 struct extent_record
*rec
)
104 if (rec
->checked
&& rec
->extent_item_refs
== rec
->refs
&&
106 radix_tree_delete(extent_radix
, rec
->start
);
112 static int check_block(struct btrfs_root
*root
,
113 struct radix_tree_root
*extent_radix
,
114 struct btrfs_buffer
*buf
)
116 struct extent_record
*rec
;
119 rec
= radix_tree_lookup(extent_radix
, buf
->blocknr
);
122 if (btrfs_is_leaf(&buf
->node
)) {
123 ret
= check_leaf(root
, &rec
->parent_key
, &buf
->leaf
);
125 ret
= check_node(root
, &rec
->parent_key
, &buf
->node
);
129 maybe_free_extent_rec(extent_radix
, rec
);
133 static int add_extent_rec(struct radix_tree_root
*extent_radix
,
134 struct btrfs_disk_key
*parent_key
,
135 u64 ref
, u64 start
, u64 nr
, u64 owner
,
136 u32 extent_item_refs
, int inc_ref
, int set_checked
)
138 struct extent_record
*rec
;
140 rec
= radix_tree_lookup(extent_radix
, start
);
144 if (start
!= rec
->start
) {
145 fprintf(stderr
, "warning, start mismatch %Lu %Lu\n",
149 if (extent_item_refs
) {
150 if (rec
->extent_item_refs
) {
151 fprintf(stderr
, "block %Lu rec extent_item_refs %u, passed %u\n", start
, rec
->extent_item_refs
, extent_item_refs
);
153 rec
->extent_item_refs
= extent_item_refs
;
157 maybe_free_extent_rec(extent_radix
, rec
);
160 rec
= malloc(sizeof(*rec
));
162 extent_item_refs
= 0;
173 if (extent_item_refs
)
174 rec
->extent_item_refs
= extent_item_refs
;
176 rec
->extent_item_refs
= 0;
179 memcpy(&rec
->parent_key
, parent_key
, sizeof(*parent_key
));
181 memset(&rec
->parent_key
, 0, sizeof(*parent_key
));
183 ret
= radix_tree_insert(extent_radix
, start
, rec
);
191 static int add_pending(struct radix_tree_root
*pending
,
192 struct radix_tree_root
*seen
, u64 blocknr
)
194 if (test_radix_bit(seen
, blocknr
))
196 set_radix_bit(pending
, blocknr
);
197 set_radix_bit(seen
, blocknr
);
200 static int pick_next_pending(struct radix_tree_root
*pending
,
201 struct radix_tree_root
*reada
,
202 struct radix_tree_root
*nodes
,
203 u64 last
, unsigned long *bits
, int bits_nr
,
206 unsigned long node_start
= last
;
208 ret
= find_first_radix_bit(reada
, bits
, 0, 1);
216 ret
= find_first_radix_bit(nodes
, bits
, node_start
, bits_nr
);
218 ret
= find_first_radix_bit(nodes
, bits
, 0, bits_nr
);
220 if (bits_nr
- ret
> 8) {
223 ret2
= find_first_radix_bit(pending
, bits
+ ret
,
224 bits
[0], bits_nr
- ret
);
225 sequential
= bits
[0];
227 if (bits
[ret
] - sequential
> 8)
229 sequential
= bits
[ret
];
236 return find_first_radix_bit(pending
, bits
, 0, bits_nr
);
238 static struct btrfs_buffer reada_buf
;
240 static int run_next_block(struct btrfs_root
*root
,
244 struct radix_tree_root
*pending
,
245 struct radix_tree_root
*seen
,
246 struct radix_tree_root
*reada
,
247 struct radix_tree_root
*nodes
,
248 struct radix_tree_root
*extent_radix
)
250 struct btrfs_buffer
*buf
;
255 struct btrfs_leaf
*leaf
;
256 struct btrfs_node
*node
;
257 struct btrfs_disk_key
*disk_key
;
261 ret
= pick_next_pending(pending
, reada
, nodes
, *last
, bits
,
262 bits_nr
, &reada_bits
);
267 for(i
= 0; i
< ret
; i
++) {
269 set_radix_bit(reada
, bits
[i
]);
270 btrfs_map_bh_to_logical(root
, &reada_buf
, bits
[i
]);
271 offset
= reada_buf
.dev_blocknr
* root
->blocksize
;
272 last_block
= bits
[i
];
273 readahead(reada_buf
.fd
, offset
, root
->blocksize
);
278 clear_radix_bit(pending
, blocknr
);
279 clear_radix_bit(reada
, blocknr
);
280 clear_radix_bit(nodes
, blocknr
);
281 buf
= read_tree_block(root
, blocknr
);
282 nritems
= btrfs_header_nritems(&buf
->node
.header
);
283 ret
= check_block(root
, extent_radix
, buf
);
285 fprintf(stderr
, "bad block %Lu\n", blocknr
);
287 if (btrfs_is_leaf(&buf
->node
)) {
289 btree_space_waste
+= btrfs_leaf_free_space(root
, leaf
);
290 for (i
= 0; i
< nritems
; i
++) {
291 struct btrfs_file_extent_item
*fi
;
292 disk_key
= &leaf
->items
[i
].key
;
293 if (btrfs_disk_key_type(disk_key
) ==
294 BTRFS_EXTENT_ITEM_KEY
) {
295 struct btrfs_key found
;
296 struct btrfs_extent_item
*ei
;
297 btrfs_disk_key_to_cpu(&found
,
298 &leaf
->items
[i
].key
);
299 ei
= btrfs_item_ptr(leaf
, i
,
300 struct btrfs_extent_item
);
301 add_extent_rec(extent_radix
, NULL
, 0,
304 btrfs_extent_owner(ei
),
305 btrfs_extent_refs(ei
), 0, 0);
308 if (btrfs_disk_key_type(disk_key
) ==
309 BTRFS_CSUM_ITEM_KEY
) {
311 btrfs_item_size(leaf
->items
+ i
);
314 if (btrfs_disk_key_type(disk_key
) ==
315 BTRFS_BLOCK_GROUP_ITEM_KEY
) {
316 struct btrfs_block_group_item
*bi
;
317 bi
= btrfs_item_ptr(leaf
, i
,
318 struct btrfs_block_group_item
);
320 fprintf(stderr
,"block group %Lu %Lu used %Lu ",
321 btrfs_disk_key_objectid(disk_key
),
322 btrfs_disk_key_offset(disk_key
),
323 btrfs_block_group_used(bi
));
324 fprintf(stderr
, "flags %x\n", bi
->flags
);
328 if (btrfs_disk_key_type(&leaf
->items
[i
].key
) !=
329 BTRFS_EXTENT_DATA_KEY
)
331 fi
= btrfs_item_ptr(leaf
, i
,
332 struct btrfs_file_extent_item
);
333 if (btrfs_file_extent_type(fi
) !=
334 BTRFS_FILE_EXTENT_REG
)
336 if (btrfs_file_extent_disk_blocknr(fi
) == 0)
338 ret
= add_extent_rec(extent_radix
, NULL
, blocknr
,
339 btrfs_file_extent_disk_blocknr(fi
),
340 btrfs_file_extent_disk_num_blocks(fi
),
341 btrfs_disk_key_objectid(&leaf
->items
[i
].key
),
348 level
= btrfs_header_level(&node
->header
);
349 for (i
= 0; i
< nritems
; i
++) {
350 u64 ptr
= btrfs_node_blockptr(node
, i
);
351 ret
= add_extent_rec(extent_radix
,
354 btrfs_header_owner(&node
->header
),
358 add_pending(nodes
, seen
, ptr
);
360 add_pending(pending
, seen
, ptr
);
363 btree_space_waste
+= (BTRFS_NODEPTRS_PER_BLOCK(root
) -
364 nritems
) * sizeof(struct btrfs_key_ptr
);
366 btrfs_block_release(root
, buf
);
367 total_btree_blocks
++;
371 static int add_root_to_pending(struct btrfs_buffer
*buf
,
374 struct radix_tree_root
*extent_radix
,
375 struct radix_tree_root
*pending
,
376 struct radix_tree_root
*seen
,
377 struct radix_tree_root
*reada
,
378 struct radix_tree_root
*nodes
)
380 if (btrfs_header_level(&buf
->node
.header
) > 0)
381 add_pending(nodes
, seen
, buf
->blocknr
);
383 add_pending(pending
, seen
, buf
->blocknr
);
384 add_extent_rec(extent_radix
, NULL
, 0, buf
->blocknr
, 1,
385 btrfs_header_owner(&buf
->node
.header
), 0, 1, 0);
389 int check_extent_refs(struct btrfs_root
*root
,
390 struct radix_tree_root
*extent_radix
)
392 struct extent_record
*rec
[64];
398 ret
= radix_tree_gang_lookup(extent_radix
, (void **)rec
, 0,
402 for (i
= 0; i
< ret
; i
++) {
403 if (rec
[i
]->refs
!= rec
[i
]->extent_item_refs
) {
404 fprintf(stderr
, "ref mismatch on [%Lu %Lu] ",
405 rec
[i
]->start
, rec
[i
]->nr
);
406 fprintf(stderr
, "extent item %u, found %u\n",
407 rec
[i
]->extent_item_refs
,
411 radix_tree_delete(extent_radix
, rec
[i
]->start
);
418 int main(int ac
, char **av
) {
419 struct btrfs_super_block super
;
420 struct btrfs_root
*root
;
421 struct radix_tree_root extent_radix
;
422 struct radix_tree_root seen
;
423 struct radix_tree_root pending
;
424 struct radix_tree_root reada
;
425 struct radix_tree_root nodes
;
426 struct btrfs_path path
;
427 struct btrfs_key key
;
428 struct btrfs_key found_key
;
433 struct btrfs_leaf
*leaf
;
435 struct btrfs_root_item
*ri
;
440 INIT_RADIX_TREE(&extent_radix
, GFP_NOFS
);
441 init_bit_radix(&seen
);
442 init_bit_radix(&pending
);
443 init_bit_radix(&reada
);
444 init_bit_radix(&nodes
);
446 root
= open_ctree(av
[1], &super
);
448 bits_nr
= 1024 * 1024 / root
->blocksize
;
449 bits
= malloc(bits_nr
* sizeof(unsigned long));
455 add_root_to_pending(root
->fs_info
->tree_root
->node
, bits
, bits_nr
,
456 &extent_radix
, &pending
, &seen
, &reada
, &nodes
);
458 btrfs_init_path(&path
);
462 btrfs_set_key_type(&key
, BTRFS_ROOT_ITEM_KEY
);
463 ret
= btrfs_search_slot(NULL
, root
->fs_info
->tree_root
,
467 leaf
= &path
.nodes
[0]->leaf
;
468 slot
= path
.slots
[0];
469 if (slot
>= btrfs_header_nritems(&leaf
->header
)) {
470 ret
= btrfs_next_leaf(root
, &path
);
473 leaf
= &path
.nodes
[0]->leaf
;
474 slot
= path
.slots
[0];
476 btrfs_disk_key_to_cpu(&found_key
,
477 &leaf
->items
[path
.slots
[0]].key
);
478 if (btrfs_key_type(&found_key
) == BTRFS_ROOT_ITEM_KEY
) {
479 struct btrfs_buffer
*buf
;
480 ri
= btrfs_item_ptr(leaf
, path
.slots
[0],
481 struct btrfs_root_item
);
482 buf
= read_tree_block(root
->fs_info
->tree_root
,
483 btrfs_root_blocknr(ri
));
484 add_root_to_pending(buf
, bits
, bits_nr
, &extent_radix
,
485 &pending
, &seen
, &reada
, &nodes
);
486 btrfs_block_release(root
->fs_info
->tree_root
, buf
);
490 btrfs_release_path(root
, &path
);
492 ret
= run_next_block(root
, bits
, bits_nr
, &last
, &pending
,
493 &seen
, &reada
, &nodes
, &extent_radix
);
497 ret
= check_extent_refs(root
, &extent_radix
);
498 close_ctree(root
, &super
);
499 printf("found %Lu blocks used err is %d\n", blocks_used
, ret
);
500 printf("total csum bytes: %Lu\n", total_csum_bytes
);
501 printf("total tree blocks: %Lu\n", total_btree_blocks
);
502 printf("btree space waste bytes: %Lu\n", btree_space_waste
);