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.
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
28 #include <uuid/uuid.h>
35 #include "kerncompat.h"
42 push_im(gdImagePtr im
, char *name
, char *dir
)
50 snprintf(fullname
, sizeof(fullname
), "%s/%s", dir
, name
);
51 pngout
= fopen(fullname
, "w");
53 printf("unable to create file %s\n", fullname
);
57 gdImagePng(im
, pngout
);
66 switch (flags
& (BTRFS_BLOCK_GROUP_SYSTEM
| BTRFS_BLOCK_GROUP_DATA
|
67 BTRFS_BLOCK_GROUP_METADATA
)) {
68 case BTRFS_BLOCK_GROUP_SYSTEM
:
70 case BTRFS_BLOCK_GROUP_DATA
:
72 case BTRFS_BLOCK_GROUP_METADATA
:
74 case BTRFS_BLOCK_GROUP_DATA
| BTRFS_BLOCK_GROUP_METADATA
:
82 print_bg(FILE *html
, char *name
, u64 start
, u64 len
, u64 used
, u64 flags
,
85 double frag
= (double)areas
/ (len
/ 4096) * 2;
87 fprintf(html
, "<p>%s chunk starts at %lld, size is %s, %.2f%% used, "
88 "%.2f%% fragmented</p>\n", chunk_type(flags
), start
,
89 pretty_size(len
), 100.0 * used
/ len
, 100.0 * frag
);
90 fprintf(html
, "<img src=\"%s\" border=\"1\" />\n", name
);
107 get_color(struct btrfs_extent_item
*item
, int len
)
113 struct btrfs_extent_inline_ref
*ref
;
115 refs
= btrfs_stack_extent_refs(item
);
116 flags
= btrfs_stack_extent_flags(item
);
118 if (flags
& BTRFS_EXTENT_FLAG_DATA
)
121 /* this must be an fs tree */
125 ref
= (void *)item
+ sizeof(struct btrfs_extent_item
) +
126 sizeof(struct btrfs_tree_block_info
);
127 type
= btrfs_stack_extent_inline_ref_type(ref
);
128 offset
= btrfs_stack_extent_inline_ref_offset(ref
);
131 case BTRFS_EXTENT_DATA_REF_KEY
:
133 case BTRFS_SHARED_BLOCK_REF_KEY
:
134 case BTRFS_SHARED_DATA_REF_KEY
:
136 case BTRFS_TREE_BLOCK_REF_KEY
:
139 return COLOR_UNKNOWN
;
143 case BTRFS_ROOT_TREE_OBJECTID
:
145 case BTRFS_EXTENT_TREE_OBJECTID
:
147 case BTRFS_CHUNK_TREE_OBJECTID
:
149 case BTRFS_DEV_TREE_OBJECTID
:
151 case BTRFS_FS_TREE_OBJECTID
:
153 case BTRFS_CSUM_TREE_OBJECTID
:
155 case BTRFS_DATA_RELOC_TREE_OBJECTID
:
159 return COLOR_UNKNOWN
;
163 init_colors(gdImagePtr im
, int *colors
)
165 colors
[COLOR_ROOT
] = gdImageColorAllocate(im
, 255, 0, 0);
166 colors
[COLOR_EXTENT
] = gdImageColorAllocate(im
, 0, 255, 0);
167 colors
[COLOR_CHUNK
] = gdImageColorAllocate(im
, 255, 0, 0);
168 colors
[COLOR_DEV
] = gdImageColorAllocate(im
, 255, 0, 0);
169 colors
[COLOR_FS
] = gdImageColorAllocate(im
, 0, 0, 0);
170 colors
[COLOR_CSUM
] = gdImageColorAllocate(im
, 0, 0, 255);
171 colors
[COLOR_RELOC
] = gdImageColorAllocate(im
, 128, 128, 128);
172 colors
[COLOR_DATA
] = gdImageColorAllocate(im
, 100, 0, 0);
173 colors
[COLOR_UNKNOWN
] = gdImageColorAllocate(im
, 50, 50, 50);
177 list_fragments(int fd
, u64 flags
, char *dir
)
180 struct btrfs_ioctl_search_args args
;
181 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
183 struct btrfs_ioctl_search_header
*sh
;
184 unsigned long off
= 0;
191 u64 saved_extent
= 0;
199 int colors
[COLOR_MAX
];
201 gdImagePtr im
= NULL
;
205 snprintf(name
, sizeof(name
), "%s/index.html", dir
);
206 html
= fopen(name
, "w");
208 printf("unable to create %s\n", name
);
212 fprintf(html
, "<html><header>\n");
213 fprintf(html
, "<title>Btrfs Block Group Allocation Map</title>\n");
214 fprintf(html
, "<style type=\"text/css\">\n");
215 fprintf(html
, "img {margin-left: 1em; margin-bottom: 2em;}\n");
216 fprintf(html
, "</style>\n");
217 fprintf(html
, "</header><body>\n");
219 memset(&args
, 0, sizeof(args
));
224 sk
->max_objectid
= (u64
)-1;
225 sk
->max_offset
= (u64
)-1;
226 sk
->max_transid
= (u64
)-1;
228 /* just a big number, doesn't matter much */
232 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
234 fprintf(stderr
, "ERROR: can't perform the search\n");
237 /* the ioctl returns the number of item it found in nr_items */
238 if (sk
->nr_items
== 0)
242 for (i
= 0; i
< sk
->nr_items
; i
++) {
245 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
248 if (sh
->type
== BTRFS_BLOCK_GROUP_ITEM_KEY
) {
249 struct btrfs_block_group_item
*bg
;
252 push_im(im
, name
, dir
);
255 print_bg(html
, name
, bgstart
, bglen
,
256 bgused
, bgflags
, areas
);
261 bg
= (struct btrfs_block_group_item
*)
263 bgflags
= btrfs_block_group_flags(bg
);
264 bgused
= btrfs_block_group_used(bg
);
266 printf("found block group %lld len %lld "
267 "flags %lld\n", sh
->objectid
,
268 sh
->offset
, bgflags
);
269 if (!(bgflags
& flags
)) {
270 /* skip this block group */
271 sk
->min_objectid
= sh
->objectid
+
277 im
= gdImageCreate(width
,
278 (sh
->offset
/ 4096 + 799) / width
);
280 black
= gdImageColorAllocate(im
, 0, 0, 0);
282 for (j
= 0; j
< ARRAY_SIZE(colors
); ++j
)
285 init_colors(im
, colors
);
286 bgstart
= sh
->objectid
;
288 bgend
= bgstart
+ bglen
;
290 snprintf(name
, sizeof(name
), "bg%d.png", bgnum
);
294 px
= (saved_extent
- bgstart
) / 4096;
295 for (j
= 0; j
< saved_len
/ 4096; ++j
) {
296 int x
= (px
+ j
) % width
;
297 int y
= (px
+ j
) / width
;
298 gdImageSetPixel(im
, x
, y
,
301 last_end
+= saved_len
;
306 if (im
&& sh
->type
== BTRFS_EXTENT_ITEM_KEY
) {
308 struct btrfs_extent_item
*item
;
310 item
= (struct btrfs_extent_item
*)
314 c
= colors
[get_color(item
, sh
->len
)];
317 if (sh
->objectid
> bgend
) {
318 printf("WARN: extent %lld is without "
319 "block group\n", sh
->objectid
);
322 if (sh
->objectid
== bgend
) {
323 saved_extent
= sh
->objectid
;
324 saved_len
= sh
->offset
;
328 px
= (sh
->objectid
- bgstart
) / 4096;
329 for (j
= 0; j
< sh
->offset
/ 4096; ++j
) {
330 int x
= (px
+ j
) % width
;
331 int y
= (px
+ j
) / width
;
332 gdImageSetPixel(im
, x
, y
, c
);
334 if (sh
->objectid
!= last_end
)
336 last_end
= sh
->objectid
+ sh
->offset
;
342 * record the mins in sk so we can make sure the
343 * next search doesn't repeat this root
345 sk
->min_objectid
= sh
->objectid
;
346 sk
->min_type
= sh
->type
;
347 sk
->min_offset
= sh
->offset
;
351 /* increment by one */
352 if (++sk
->min_offset
== 0)
353 if (++sk
->min_type
== 0)
354 if (++sk
->min_objectid
== 0)
359 push_im(im
, name
, dir
);
360 print_bg(html
, name
, bgstart
, bglen
, bgused
, bgflags
, areas
);
364 fprintf(html
, "<p>");
365 fprintf(html
, "data - dark red, ");
366 fprintf(html
, "fs tree - black, ");
367 fprintf(html
, "extent tree - green, ");
368 fprintf(html
, "csum tree - blue, ");
369 fprintf(html
, "reloc tree - grey, ");
370 fprintf(html
, "other trees - red, ");
371 fprintf(html
, "unknown tree - dark grey");
372 fprintf(html
, "</p>");
374 fprintf(html
, "</body></html>\n");
385 printf("usage: btrfs-fragments [options] <path>\n");
386 printf(" -c use color\n");
387 printf(" -d print data chunks\n");
388 printf(" -m print metadata chunks\n");
389 printf(" -s print system chunks\n");
390 printf(" (default is data+metadata)\n");
391 printf(" -o <dir> output directory, default is html\n");
395 int main(int argc
, char **argv
)
402 DIR *dirstream
= NULL
;
405 int c
= getopt(argc
, argv
, "cmso:h");
413 flags
|= BTRFS_BLOCK_GROUP_DATA
;
416 flags
|= BTRFS_BLOCK_GROUP_METADATA
;
419 flags
|= BTRFS_BLOCK_GROUP_SYSTEM
;
431 if (check_argc_min(argc
- optind
, 1)) {
436 path
= argv
[optind
++];
438 fd
= btrfs_open_dir(path
, &dirstream
, 1);
443 flags
= BTRFS_BLOCK_GROUP_DATA
| BTRFS_BLOCK_GROUP_METADATA
;
445 ret
= list_fragments(fd
, flags
, dir
);
446 close_file_or_dir(fd
, dirstream
);