2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
29 #include <uuid/uuid.h>
36 #include "kerncompat.h"
43 push_im(gdImagePtr im
, char *name
, char *dir
)
51 snprintf(fullname
, sizeof(fullname
), "%s/%s", dir
, name
);
52 pngout
= fopen(fullname
, "w");
54 printf("unable to create file %s\n", fullname
);
58 gdImagePng(im
, pngout
);
67 switch (flags
& (BTRFS_BLOCK_GROUP_SYSTEM
| BTRFS_BLOCK_GROUP_DATA
|
68 BTRFS_BLOCK_GROUP_METADATA
)) {
69 case BTRFS_BLOCK_GROUP_SYSTEM
:
71 case BTRFS_BLOCK_GROUP_DATA
:
73 case BTRFS_BLOCK_GROUP_METADATA
:
75 case BTRFS_BLOCK_GROUP_DATA
| BTRFS_BLOCK_GROUP_METADATA
:
83 print_bg(FILE *html
, char *name
, u64 start
, u64 len
, u64 used
, u64 flags
,
86 double frag
= (double)areas
/ (len
/ 4096) * 2;
88 fprintf(html
, "<p>%s chunk starts at %lld, size is %s, %.2f%% used, "
89 "%.2f%% fragmented</p>\n", chunk_type(flags
), start
,
90 pretty_size(len
), 100.0 * used
/ len
, 100.0 * frag
);
91 fprintf(html
, "<img src=\"%s\" border=\"1\" />\n", name
);
108 get_color(struct btrfs_extent_item
*item
, int len
)
114 struct btrfs_extent_inline_ref
*ref
;
116 refs
= btrfs_stack_extent_refs(item
);
117 flags
= btrfs_stack_extent_flags(item
);
119 if (flags
& BTRFS_EXTENT_FLAG_DATA
)
122 /* this must be an fs tree */
126 ref
= (void *)item
+ sizeof(struct btrfs_extent_item
) +
127 sizeof(struct btrfs_tree_block_info
);
128 type
= btrfs_stack_extent_inline_ref_type(ref
);
129 offset
= btrfs_stack_extent_inline_ref_offset(ref
);
132 case BTRFS_EXTENT_DATA_REF_KEY
:
134 case BTRFS_SHARED_BLOCK_REF_KEY
:
135 case BTRFS_SHARED_DATA_REF_KEY
:
137 case BTRFS_TREE_BLOCK_REF_KEY
:
140 return COLOR_UNKNOWN
;
144 case BTRFS_ROOT_TREE_OBJECTID
:
146 case BTRFS_EXTENT_TREE_OBJECTID
:
148 case BTRFS_CHUNK_TREE_OBJECTID
:
150 case BTRFS_DEV_TREE_OBJECTID
:
152 case BTRFS_FS_TREE_OBJECTID
:
154 case BTRFS_CSUM_TREE_OBJECTID
:
156 case BTRFS_DATA_RELOC_TREE_OBJECTID
:
160 return COLOR_UNKNOWN
;
164 init_colors(gdImagePtr im
, int *colors
)
166 colors
[COLOR_ROOT
] = gdImageColorAllocate(im
, 255, 0, 0);
167 colors
[COLOR_EXTENT
] = gdImageColorAllocate(im
, 0, 255, 0);
168 colors
[COLOR_CHUNK
] = gdImageColorAllocate(im
, 255, 0, 0);
169 colors
[COLOR_DEV
] = gdImageColorAllocate(im
, 255, 0, 0);
170 colors
[COLOR_FS
] = gdImageColorAllocate(im
, 0, 0, 0);
171 colors
[COLOR_CSUM
] = gdImageColorAllocate(im
, 0, 0, 255);
172 colors
[COLOR_RELOC
] = gdImageColorAllocate(im
, 128, 128, 128);
173 colors
[COLOR_DATA
] = gdImageColorAllocate(im
, 100, 0, 0);
174 colors
[COLOR_UNKNOWN
] = gdImageColorAllocate(im
, 50, 50, 50);
178 list_fragments(int fd
, u64 flags
, char *dir
)
181 struct btrfs_ioctl_search_args args
;
182 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
184 struct btrfs_ioctl_search_header
*sh
;
185 unsigned long off
= 0;
192 u64 saved_extent
= 0;
200 int colors
[COLOR_MAX
];
202 gdImagePtr im
= NULL
;
206 snprintf(name
, sizeof(name
), "%s/index.html", dir
);
207 html
= fopen(name
, "w");
209 printf("unable to create %s\n", name
);
213 fprintf(html
, "<html><header>\n");
214 fprintf(html
, "<title>Btrfs Block Group Allocation Map</title>\n");
215 fprintf(html
, "<style type=\"text/css\">\n");
216 fprintf(html
, "img {margin-left: 1em; margin-bottom: 2em;}\n");
217 fprintf(html
, "</style>\n");
218 fprintf(html
, "</header><body>\n");
220 memset(&args
, 0, sizeof(args
));
225 sk
->max_objectid
= (u64
)-1;
226 sk
->max_offset
= (u64
)-1;
227 sk
->max_transid
= (u64
)-1;
229 /* just a big number, doesn't matter much */
233 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
235 fprintf(stderr
, "ERROR: can't perform the search\n");
238 /* the ioctl returns the number of item it found in nr_items */
239 if (sk
->nr_items
== 0)
243 for (i
= 0; i
< sk
->nr_items
; i
++) {
246 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
249 if (sh
->type
== BTRFS_BLOCK_GROUP_ITEM_KEY
) {
250 struct btrfs_block_group_item
*bg
;
253 push_im(im
, name
, dir
);
256 print_bg(html
, name
, bgstart
, bglen
,
257 bgused
, bgflags
, areas
);
262 bg
= (struct btrfs_block_group_item
*)
264 bgflags
= btrfs_block_group_flags(bg
);
265 bgused
= btrfs_block_group_used(bg
);
267 printf("found block group %lld len %lld "
268 "flags %lld\n", sh
->objectid
,
269 sh
->offset
, bgflags
);
270 if (!(bgflags
& flags
)) {
271 /* skip this block group */
272 sk
->min_objectid
= sh
->objectid
+
278 im
= gdImageCreate(width
,
279 (sh
->offset
/ 4096 + 799) / width
);
281 black
= gdImageColorAllocate(im
, 0, 0, 0);
283 for (j
= 0; j
< ARRAY_SIZE(colors
); ++j
)
286 init_colors(im
, colors
);
287 bgstart
= sh
->objectid
;
289 bgend
= bgstart
+ bglen
;
291 snprintf(name
, sizeof(name
), "bg%d.png", bgnum
);
295 px
= (saved_extent
- bgstart
) / 4096;
296 for (j
= 0; j
< saved_len
/ 4096; ++j
) {
297 int x
= (px
+ j
) % width
;
298 int y
= (px
+ j
) / width
;
299 gdImageSetPixel(im
, x
, y
,
302 last_end
+= saved_len
;
307 if (im
&& sh
->type
== BTRFS_EXTENT_ITEM_KEY
) {
309 struct btrfs_extent_item
*item
;
311 item
= (struct btrfs_extent_item
*)
315 c
= colors
[get_color(item
, sh
->len
)];
318 if (sh
->objectid
> bgend
) {
319 printf("WARN: extent %lld is without "
320 "block group\n", sh
->objectid
);
323 if (sh
->objectid
== bgend
) {
324 saved_extent
= sh
->objectid
;
325 saved_len
= sh
->offset
;
329 px
= (sh
->objectid
- bgstart
) / 4096;
330 for (j
= 0; j
< sh
->offset
/ 4096; ++j
) {
331 int x
= (px
+ j
) % width
;
332 int y
= (px
+ j
) / width
;
333 gdImageSetPixel(im
, x
, y
, c
);
335 if (sh
->objectid
!= last_end
)
337 last_end
= sh
->objectid
+ sh
->offset
;
343 * record the mins in sk so we can make sure the
344 * next search doesn't repeat this root
346 sk
->min_objectid
= sh
->objectid
;
347 sk
->min_type
= sh
->type
;
348 sk
->min_offset
= sh
->offset
;
352 /* increment by one */
353 if (++sk
->min_offset
== 0)
354 if (++sk
->min_type
== 0)
355 if (++sk
->min_objectid
== 0)
360 push_im(im
, name
, dir
);
361 print_bg(html
, name
, bgstart
, bglen
, bgused
, bgflags
, areas
);
365 fprintf(html
, "<p>");
366 fprintf(html
, "data - dark red, ");
367 fprintf(html
, "fs tree - black, ");
368 fprintf(html
, "extent tree - green, ");
369 fprintf(html
, "csum tree - blue, ");
370 fprintf(html
, "reloc tree - grey, ");
371 fprintf(html
, "other trees - red, ");
372 fprintf(html
, "unknown tree - dark grey");
373 fprintf(html
, "</p>");
375 fprintf(html
, "</body></html>\n");
383 printf("usage: btrfs-fragments [options] <path>\n");
384 printf(" -c use color\n");
385 printf(" -d print data chunks\n");
386 printf(" -m print metadata chunks\n");
387 printf(" -s print system chunks\n");
388 printf(" (default is data+metadata)\n");
389 printf(" -o <dir> output directory, default is html\n");
393 int main(int argc
, char **argv
)
400 DIR *dirstream
= NULL
;
403 int c
= getopt(argc
, argv
, "cmso:h");
411 flags
|= BTRFS_BLOCK_GROUP_DATA
;
414 flags
|= BTRFS_BLOCK_GROUP_METADATA
;
417 flags
|= BTRFS_BLOCK_GROUP_SYSTEM
;
429 path
= argv
[optind
++];
435 fd
= open_file_or_dir(path
, &dirstream
);
437 fprintf(stderr
, "ERROR: can't access '%s'\n", path
);
442 flags
= BTRFS_BLOCK_GROUP_DATA
| BTRFS_BLOCK_GROUP_METADATA
;
444 ret
= list_fragments(fd
, flags
, dir
);
445 close_file_or_dir(fd
, dirstream
);