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
));
221 sk
->tree_id
= BTRFS_EXTENT_TREE_OBJECTID
;
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 (btrfs_search_header_type(sh
)
249 == 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 "
269 btrfs_search_header_objectid(sh
),
270 btrfs_search_header_offset(sh
),
272 if (!(bgflags
& flags
)) {
273 /* skip this block group */
275 btrfs_search_header_objectid(sh
) +
276 btrfs_search_header_offset(sh
);
281 im
= gdImageCreate(width
,
282 (btrfs_search_header_offset(sh
)
283 / 4096 + 799) / width
);
285 black
= gdImageColorAllocate(im
, 0, 0, 0);
287 for (j
= 0; j
< ARRAY_SIZE(colors
); ++j
)
290 init_colors(im
, colors
);
291 bgstart
= btrfs_search_header_objectid(sh
);
292 bglen
= btrfs_search_header_offset(sh
);
293 bgend
= bgstart
+ bglen
;
295 snprintf(name
, sizeof(name
), "bg%d.png", bgnum
);
299 px
= (saved_extent
- bgstart
) / 4096;
300 for (j
= 0; j
< saved_len
/ 4096; ++j
) {
301 int x
= (px
+ j
) % width
;
302 int y
= (px
+ j
) / width
;
303 gdImageSetPixel(im
, x
, y
,
306 last_end
+= saved_len
;
311 if (im
&& btrfs_search_header_type(sh
)
312 == BTRFS_EXTENT_ITEM_KEY
) {
314 struct btrfs_extent_item
*item
;
316 item
= (struct btrfs_extent_item
*)
320 c
= colors
[get_color(item
,
321 btrfs_search_header_len(sh
))];
324 if (btrfs_search_header_objectid(sh
) > bgend
) {
325 printf("WARN: extent %lld is without "
327 btrfs_search_header_objectid(sh
));
330 if (btrfs_search_header_objectid(sh
) == bgend
) {
332 btrfs_search_header_objectid(sh
);
334 btrfs_search_header_offset(sh
);
338 px
= (btrfs_search_header_objectid(sh
)
341 j
< btrfs_search_header_offset(sh
) / 4096;
343 int x
= (px
+ j
) % width
;
344 int y
= (px
+ j
) / width
;
345 gdImageSetPixel(im
, x
, y
, c
);
347 if (btrfs_search_header_objectid(sh
) != last_end
)
349 last_end
= btrfs_search_header_objectid(sh
)
350 + btrfs_search_header_offset(sh
);
353 off
+= btrfs_search_header_len(sh
);
356 * record the mins in sk so we can make sure the
357 * next search doesn't repeat this root
359 sk
->min_objectid
= btrfs_search_header_objectid(sh
);
360 sk
->min_type
= btrfs_search_header_type(sh
);
361 sk
->min_offset
= btrfs_search_header_offset(sh
);
365 /* increment by one */
366 if (++sk
->min_offset
== 0)
367 if (++sk
->min_type
== 0)
368 if (++sk
->min_objectid
== 0)
373 push_im(im
, name
, dir
);
374 print_bg(html
, name
, bgstart
, bglen
, bgused
, bgflags
, areas
);
378 fprintf(html
, "<p>");
379 fprintf(html
, "data - dark red, ");
380 fprintf(html
, "fs tree - black, ");
381 fprintf(html
, "extent tree - green, ");
382 fprintf(html
, "csum tree - blue, ");
383 fprintf(html
, "reloc tree - grey, ");
384 fprintf(html
, "other trees - red, ");
385 fprintf(html
, "unknown tree - dark grey");
386 fprintf(html
, "</p>");
388 fprintf(html
, "</body></html>\n");
396 void fragments_usage(void)
398 printf("usage: btrfs-fragments [options] <path>\n");
399 printf(" -c use color\n");
400 printf(" -d print data chunks\n");
401 printf(" -m print metadata chunks\n");
402 printf(" -s print system chunks\n");
403 printf(" (default is data+metadata)\n");
404 printf(" -o <dir> output directory, default is html\n");
408 int main(int argc
, char **argv
)
415 DIR *dirstream
= NULL
;
418 int c
= getopt(argc
, argv
, "cmso:h");
426 flags
|= BTRFS_BLOCK_GROUP_DATA
;
429 flags
|= BTRFS_BLOCK_GROUP_METADATA
;
432 flags
|= BTRFS_BLOCK_GROUP_SYSTEM
;
444 if (check_argc_min(argc
- optind
, 1))
447 path
= argv
[optind
++];
449 fd
= btrfs_open_dir(path
, &dirstream
, 1);
454 flags
= BTRFS_BLOCK_GROUP_DATA
| BTRFS_BLOCK_GROUP_METADATA
;
456 ret
= list_fragments(fd
, flags
, dir
);
457 close_file_or_dir(fd
, dirstream
);