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>
26 #include "kerncompat.h"
30 #include "send-utils.h"
33 #include "btrfs-list.h"
34 #include "cmds-inspect-dump-tree.h"
35 #include "cmds-inspect-dump-super.h"
36 #include "cmds-inspect-tree-stats.h"
38 static const char * const inspect_cmd_group_usage
[] = {
39 "btrfs inspect-internal <command> <args>",
43 static int __ino_to_path_fd(u64 inum
, int fd
, int verbose
, const char *prepend
)
47 struct btrfs_ioctl_ino_path_args ipa
;
48 struct btrfs_data_container fspath
[PATH_MAX
];
50 memset(fspath
, 0, sizeof(*fspath
));
53 ipa
.fspath
= ptr_to_u64(fspath
);
55 ret
= ioctl(fd
, BTRFS_IOC_INO_PATHS
, &ipa
);
57 error("ino paths ioctl: %s", strerror(errno
));
62 printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
63 "cnt=%d, missed=%d\n", ret
,
64 (unsigned long)fspath
->bytes_left
,
65 (unsigned long)fspath
->bytes_missing
,
66 fspath
->elem_cnt
, fspath
->elem_missed
);
68 for (i
= 0; i
< fspath
->elem_cnt
; ++i
) {
71 ptr
= (u64
)(unsigned long)fspath
->val
;
72 ptr
+= fspath
->val
[i
];
73 str
= (char *)(unsigned long)ptr
;
75 printf("%s/%s\n", prepend
, str
);
84 static const char * const cmd_inspect_inode_resolve_usage
[] = {
85 "btrfs inspect-internal inode-resolve [-v] <inode> <path>",
86 "Get file system paths for the given inode",
92 static int cmd_inspect_inode_resolve(int argc
, char **argv
)
97 DIR *dirstream
= NULL
;
100 int c
= getopt(argc
, argv
, "v");
109 usage(cmd_inspect_inode_resolve_usage
);
113 if (check_argc_exact(argc
- optind
, 2))
114 usage(cmd_inspect_inode_resolve_usage
);
116 fd
= btrfs_open_dir(argv
[optind
+ 1], &dirstream
, 1);
120 ret
= __ino_to_path_fd(arg_strtou64(argv
[optind
]), fd
, verbose
,
122 close_file_or_dir(fd
, dirstream
);
127 static const char * const cmd_inspect_logical_resolve_usage
[] = {
128 "btrfs inspect-internal logical-resolve [-Pv] [-s bufsize] <logical> <path>",
129 "Get file system paths for the given logical address",
130 "-P skip the path resolving and print the inodes instead",
132 "-s bufsize set inode container's size. This is used to increase inode",
133 " container's size in case it is not enough to read all the ",
134 " resolved results. The max value one can set is 64k",
138 static int cmd_inspect_logical_resolve(int argc
, char **argv
)
146 struct btrfs_ioctl_logical_ino_args loi
;
147 struct btrfs_data_container
*inodes
;
149 char full_path
[4096];
151 DIR *dirstream
= NULL
;
154 int c
= getopt(argc
, argv
, "Pvs:");
166 size
= arg_strtou64(optarg
);
169 usage(cmd_inspect_logical_resolve_usage
);
173 if (check_argc_exact(argc
- optind
, 2))
174 usage(cmd_inspect_logical_resolve_usage
);
176 size
= min(size
, (u64
)64 * 1024);
177 inodes
= malloc(size
);
181 memset(inodes
, 0, sizeof(*inodes
));
182 loi
.logical
= arg_strtou64(argv
[optind
]);
184 loi
.inodes
= ptr_to_u64(inodes
);
186 fd
= btrfs_open_dir(argv
[optind
+ 1], &dirstream
, 1);
192 ret
= ioctl(fd
, BTRFS_IOC_LOGICAL_INO
, &loi
);
194 error("logical ino ioctl: %s", strerror(errno
));
199 printf("ioctl ret=%d, total_size=%llu, bytes_left=%lu, "
200 "bytes_missing=%lu, cnt=%d, missed=%d\n",
202 (unsigned long)inodes
->bytes_left
,
203 (unsigned long)inodes
->bytes_missing
,
204 inodes
->elem_cnt
, inodes
->elem_missed
);
206 bytes_left
= sizeof(full_path
);
207 ret
= snprintf(full_path
, bytes_left
, "%s/", argv
[optind
+1]);
208 path_ptr
= full_path
+ ret
;
209 bytes_left
-= ret
+ 1;
210 BUG_ON(bytes_left
< 0);
212 for (i
= 0; i
< inodes
->elem_cnt
; i
+= 3) {
213 u64 inum
= inodes
->val
[i
];
214 u64 offset
= inodes
->val
[i
+1];
215 u64 root
= inodes
->val
[i
+2];
221 name
= btrfs_list_path_for_root(fd
, root
);
231 ret
= snprintf(path_ptr
, bytes_left
, "%s",
233 BUG_ON(ret
>= bytes_left
);
235 path_fd
= btrfs_open_dir(full_path
, &dirs
, 1);
241 __ino_to_path_fd(inum
, path_fd
, verbose
, full_path
);
243 close_file_or_dir(path_fd
, dirs
);
245 printf("inode %llu offset %llu root %llu\n", inum
,
251 close_file_or_dir(fd
, dirstream
);
256 static const char * const cmd_inspect_subvolid_resolve_usage
[] = {
257 "btrfs inspect-internal subvolid-resolve <subvolid> <path>",
258 "Get file system paths for the given subvolume ID.",
262 static int cmd_inspect_subvolid_resolve(int argc
, char **argv
)
268 DIR *dirstream
= NULL
;
270 clean_args_no_options(argc
, argv
, cmd_inspect_subvolid_resolve_usage
);
272 if (check_argc_exact(argc
- optind
, 2))
273 usage(cmd_inspect_subvolid_resolve_usage
);
275 fd
= btrfs_open_dir(argv
[optind
+ 1], &dirstream
, 1);
281 subvol_id
= arg_strtou64(argv
[optind
]);
282 ret
= btrfs_subvolid_resolve(fd
, path
, sizeof(path
), subvol_id
);
285 error("resolving subvolid %llu error %d",
286 (unsigned long long)subvol_id
, ret
);
290 path
[PATH_MAX
- 1] = '\0';
291 printf("%s\n", path
);
294 close_file_or_dir(fd
, dirstream
);
298 static const char* const cmd_inspect_rootid_usage
[] = {
299 "btrfs inspect-internal rootid <path>",
300 "Get tree ID of the containing subvolume of path.",
304 static int cmd_inspect_rootid(int argc
, char **argv
)
309 DIR *dirstream
= NULL
;
311 clean_args_no_options(argc
, argv
, cmd_inspect_rootid_usage
);
313 if (check_argc_exact(argc
- optind
, 1))
314 usage(cmd_inspect_rootid_usage
);
316 fd
= btrfs_open_dir(argv
[optind
], &dirstream
, 1);
322 ret
= lookup_ino_rootid(fd
, &rootid
);
324 error("failed to lookup root id: %s", strerror(-ret
));
328 printf("%llu\n", (unsigned long long)rootid
);
330 close_file_or_dir(fd
, dirstream
);
335 static const char* const cmd_inspect_min_dev_size_usage
[] = {
336 "btrfs inspect-internal min-dev-size [options] <path>",
337 "Get the minimum size the device can be shrunk to. The",
338 "device id 1 is used by default.",
339 "--id DEVID specify the device id to query",
343 struct dev_extent_elem
{
347 struct list_head list
;
350 static int add_dev_extent(struct list_head
*list
,
351 const u64 start
, const u64 end
,
354 struct dev_extent_elem
*e
;
356 e
= malloc(sizeof(*e
));
364 list_add_tail(&e
->list
, list
);
366 list_add(&e
->list
, list
);
371 static void free_dev_extent_list(struct list_head
*list
)
373 while (!list_empty(list
)) {
374 struct dev_extent_elem
*e
;
376 e
= list_first_entry(list
, struct dev_extent_elem
, list
);
382 static int hole_includes_sb_mirror(const u64 start
, const u64 end
)
387 for (i
= 0; i
< BTRFS_SUPER_MIRROR_MAX
; i
++) {
388 u64 bytenr
= btrfs_sb_offset(i
);
390 if (bytenr
>= start
&& bytenr
<= end
) {
399 static void adjust_dev_min_size(struct list_head
*extents
,
400 struct list_head
*holes
,
404 * If relocation of the block group of a device extent must happen (see
405 * below) scratch space is used for the relocation. So track here the
406 * size of the largest device extent that has to be relocated. We track
407 * only the largest and not the sum of the sizes of all relocated block
408 * groups because after each block group is relocated the running
409 * transaction is committed so that pinned space is released.
411 u64 scratch_space
= 0;
414 * List of device extents is sorted by descending order of the extent's
415 * end offset. If some extent goes beyond the computed minimum size,
416 * which initially matches the sum of the lengths of all extents,
417 * we need to check if the extent can be relocated to an hole in the
418 * device between [0, *min_size[ (which is what the resize ioctl does).
420 while (!list_empty(extents
)) {
421 struct dev_extent_elem
*e
;
422 struct dev_extent_elem
*h
;
427 e
= list_first_entry(extents
, struct dev_extent_elem
, list
);
428 if (e
->end
<= *min_size
)
432 * Our extent goes beyond the computed *min_size. See if we can
433 * find a hole large enough to relocate it to. If not we must stop
434 * and set *min_size to the end of the extent.
436 extent_len
= e
->end
- e
->start
+ 1;
437 list_for_each_entry(h
, holes
, list
) {
438 hole_len
= h
->end
- h
->start
+ 1;
439 if (hole_len
>= extent_len
) {
446 *min_size
= e
->end
+ 1;
451 * If the hole found contains the location for a superblock
452 * mirror, we are pessimistic and require allocating one
453 * more extent of the same size. This is because the block
454 * group could be in the worst case used by a single extent
455 * with a size >= (block_group.length - superblock.size).
457 if (hole_includes_sb_mirror(h
->start
,
458 h
->start
+ extent_len
- 1))
459 *min_size
+= extent_len
;
461 if (hole_len
> extent_len
) {
462 h
->start
+= extent_len
;
471 if (extent_len
> scratch_space
)
472 scratch_space
= extent_len
;
476 *min_size
+= scratch_space
;
478 * Chunk allocation requires inserting/updating items in the
479 * chunk tree, so often this can lead to the need of allocating
480 * a new system chunk too, which has a maximum size of 32Mb.
482 *min_size
+= 32 * 1024 * 1024;
486 static int print_min_dev_size(int fd
, u64 devid
)
490 * Device allocations starts at 1Mb or at the value passed through the
491 * mount option alloc_start if it's bigger than 1Mb. The alloc_start
492 * option is used for debugging and testing only, and recently the
493 * possibility of deprecating/removing it has been discussed, so we
496 u64 min_size
= 1 * 1024 * 1024ull;
497 struct btrfs_ioctl_search_args args
;
498 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
499 u64 last_pos
= (u64
)-1;
503 memset(&args
, 0, sizeof(args
));
504 sk
->tree_id
= BTRFS_DEV_TREE_OBJECTID
;
505 sk
->min_objectid
= devid
;
506 sk
->max_objectid
= devid
;
507 sk
->max_type
= BTRFS_DEV_EXTENT_KEY
;
508 sk
->min_type
= BTRFS_DEV_EXTENT_KEY
;
510 sk
->max_offset
= (u64
)-1;
512 sk
->max_transid
= (u64
)-1;
517 struct btrfs_ioctl_search_header
*sh
;
518 unsigned long off
= 0;
520 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
522 error("tree search ioctl: %s", strerror(errno
));
527 if (sk
->nr_items
== 0)
530 for (i
= 0; i
< sk
->nr_items
; i
++) {
531 struct btrfs_dev_extent
*extent
;
534 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
537 extent
= (struct btrfs_dev_extent
*)(args
.buf
+ off
);
538 off
+= btrfs_search_header_len(sh
);
540 sk
->min_objectid
= btrfs_search_header_objectid(sh
);
541 sk
->min_type
= btrfs_search_header_type(sh
);
542 sk
->min_offset
= btrfs_search_header_offset(sh
) + 1;
544 if (btrfs_search_header_objectid(sh
) != devid
||
545 btrfs_search_header_type(sh
) != BTRFS_DEV_EXTENT_KEY
)
548 len
= btrfs_stack_dev_extent_length(extent
);
550 ret
= add_dev_extent(&extents
,
551 btrfs_search_header_offset(sh
),
552 btrfs_search_header_offset(sh
) + len
- 1, 0);
554 if (!ret
&& last_pos
!= (u64
)-1 &&
555 last_pos
!= btrfs_search_header_offset(sh
))
556 ret
= add_dev_extent(&holes
, last_pos
,
557 btrfs_search_header_offset(sh
) - 1, 1);
559 error("add device extent: %s", strerror(-ret
));
564 last_pos
= btrfs_search_header_offset(sh
) + len
;
567 if (sk
->min_type
!= BTRFS_DEV_EXTENT_KEY
||
568 sk
->min_objectid
!= devid
)
572 adjust_dev_min_size(&extents
, &holes
, &min_size
);
573 printf("%llu bytes (%s)\n", min_size
, pretty_size(min_size
));
576 free_dev_extent_list(&extents
);
577 free_dev_extent_list(&holes
);
582 static int cmd_inspect_min_dev_size(int argc
, char **argv
)
586 DIR *dirstream
= NULL
;
591 enum { GETOPT_VAL_DEVID
= 256 };
592 static const struct option long_options
[] = {
593 { "id", required_argument
, NULL
, GETOPT_VAL_DEVID
},
597 c
= getopt_long(argc
, argv
, "", long_options
, NULL
);
602 case GETOPT_VAL_DEVID
:
603 devid
= arg_strtou64(optarg
);
606 usage(cmd_inspect_min_dev_size_usage
);
609 if (check_argc_exact(argc
- optind
, 1))
610 usage(cmd_inspect_min_dev_size_usage
);
612 fd
= btrfs_open_dir(argv
[optind
], &dirstream
, 1);
618 ret
= print_min_dev_size(fd
, devid
);
619 close_file_or_dir(fd
, dirstream
);
624 static const char inspect_cmd_group_info
[] =
625 "query various internal information";
627 const struct cmd_group inspect_cmd_group
= {
628 inspect_cmd_group_usage
, inspect_cmd_group_info
, {
629 { "inode-resolve", cmd_inspect_inode_resolve
,
630 cmd_inspect_inode_resolve_usage
, NULL
, 0 },
631 { "logical-resolve", cmd_inspect_logical_resolve
,
632 cmd_inspect_logical_resolve_usage
, NULL
, 0 },
633 { "subvolid-resolve", cmd_inspect_subvolid_resolve
,
634 cmd_inspect_subvolid_resolve_usage
, NULL
, 0 },
635 { "rootid", cmd_inspect_rootid
, cmd_inspect_rootid_usage
, NULL
,
637 { "min-dev-size", cmd_inspect_min_dev_size
,
638 cmd_inspect_min_dev_size_usage
, NULL
, 0 },
639 { "dump-tree", cmd_inspect_dump_tree
,
640 cmd_inspect_dump_tree_usage
, NULL
, 0 },
641 { "dump-super", cmd_inspect_dump_super
,
642 cmd_inspect_dump_super_usage
, NULL
, 0 },
643 { "tree-stats", cmd_inspect_tree_stats
,
644 cmd_inspect_tree_stats_usage
, NULL
, 0 },
649 int cmd_inspect(int argc
, char **argv
)
651 return handle_command_group(&inspect_cmd_group
, argc
, argv
);