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>
24 #include "kerncompat.h"
29 #include "btrfs-list.h"
31 static const char * const inspect_cmd_group_usage
[] = {
32 "btrfs inspect-internal <command> <args>",
36 static int __ino_to_path_fd(u64 inum
, int fd
, int verbose
, const char *prepend
)
40 struct btrfs_ioctl_ino_path_args ipa
;
41 struct btrfs_data_container
*fspath
;
43 fspath
= malloc(4096);
49 ipa
.fspath
= (u64
)fspath
;
51 ret
= ioctl(fd
, BTRFS_IOC_INO_PATHS
, &ipa
);
53 printf("ioctl ret=%d, error: %s\n", ret
, strerror(errno
));
58 printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
59 "cnt=%d, missed=%d\n", ret
,
60 (unsigned long)fspath
->bytes_left
,
61 (unsigned long)fspath
->bytes_missing
,
62 fspath
->elem_cnt
, fspath
->elem_missed
);
64 for (i
= 0; i
< fspath
->elem_cnt
; ++i
) {
65 char **str
= (char **)fspath
->val
;
66 str
[i
] += (unsigned long)fspath
->val
;
68 printf("%s/%s\n", prepend
, str
[i
]);
70 printf("%s\n", str
[i
]);
78 static const char * const cmd_inode_resolve_usage
[] = {
79 "btrfs inspect-internal inode-resolve [-v] <inode> <path>",
80 "Get file system paths for the given inode",
84 static int cmd_inode_resolve(int argc
, char **argv
)
91 int c
= getopt(argc
, argv
, "v");
100 usage(cmd_inode_resolve_usage
);
104 if (check_argc_exact(argc
- optind
, 2))
105 usage(cmd_inode_resolve_usage
);
107 fd
= open_file_or_dir(argv
[optind
+1]);
109 fprintf(stderr
, "ERROR: can't access '%s'\n", argv
[optind
+1]);
113 return __ino_to_path_fd(atoll(argv
[optind
]), fd
, verbose
,
117 static const char * const cmd_logical_resolve_usage
[] = {
118 "btrfs inspect-internal logical-resolve [-Pv] [-s bufsize] <logical> <path>",
119 "Get file system paths for the given logical address",
120 "-P skip the path resolving and print the inodes instead",
122 "-s bufsize set inode container's size. This is used to increase inode",
123 " container's size in case it is not enough to read all the ",
124 " resolved results. The max value one can set is 64k",
128 static int cmd_logical_resolve(int argc
, char **argv
)
136 struct btrfs_ioctl_logical_ino_args loi
;
137 struct btrfs_data_container
*inodes
;
139 char full_path
[4096];
144 int c
= getopt(argc
, argv
, "Pvs:");
156 size
= atoll(optarg
);
159 usage(cmd_logical_resolve_usage
);
163 if (check_argc_exact(argc
- optind
, 2))
164 usage(cmd_logical_resolve_usage
);
166 size
= min(size
, (u64
)64 * 1024);
167 inodes
= malloc(size
);
171 loi
.logical
= atoll(argv
[optind
]);
173 loi
.inodes
= (u64
)inodes
;
175 fd
= open_file_or_dir(argv
[optind
+1]);
177 fprintf(stderr
, "ERROR: can't access '%s'\n", argv
[optind
+1]);
182 ret
= ioctl(fd
, BTRFS_IOC_LOGICAL_INO
, &loi
);
184 printf("ioctl ret=%d, error: %s\n", ret
, strerror(errno
));
189 printf("ioctl ret=%d, total_size=%llu, bytes_left=%lu, "
190 "bytes_missing=%lu, cnt=%d, missed=%d\n",
192 (unsigned long)inodes
->bytes_left
,
193 (unsigned long)inodes
->bytes_missing
,
194 inodes
->elem_cnt
, inodes
->elem_missed
);
196 bytes_left
= sizeof(full_path
);
197 ret
= snprintf(full_path
, bytes_left
, "%s/", argv
[optind
+1]);
198 path_ptr
= full_path
+ ret
;
199 bytes_left
-= ret
+ 1;
200 BUG_ON(bytes_left
< 0);
202 for (i
= 0; i
< inodes
->elem_cnt
; i
+= 3) {
203 u64 inum
= inodes
->val
[i
];
204 u64 offset
= inodes
->val
[i
+1];
205 u64 root
= inodes
->val
[i
+2];
210 name
= btrfs_list_path_for_root(fd
, root
);
212 return PTR_ERR(name
);
218 ret
= snprintf(path_ptr
, bytes_left
, "%s",
220 BUG_ON(ret
>= bytes_left
);
222 path_fd
= open_file_or_dir(full_path
);
224 fprintf(stderr
, "ERROR: can't access "
225 "'%s'\n", full_path
);
229 __ino_to_path_fd(inum
, path_fd
, verbose
, full_path
);
231 printf("inode %llu offset %llu root %llu\n", inum
,
241 static const char * const cmd_bsum_usage
[] = {
242 "btrfs inspect-internal _bsum <blockno> <file>",
243 "Get file block checksum of given file",
247 static int csum_for_offset(int fd
, u64 offset
, u8
*csums
, int *count
)
249 struct btrfs_ioctl_search_args args
;
250 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
251 struct btrfs_ioctl_search_header
*sh
;
255 u32
*realcsums
= (u32
*)csums
;
257 sk
->tree_id
= BTRFS_CSUM_TREE_OBJECTID
;
258 sk
->min_objectid
= BTRFS_EXTENT_CSUM_OBJECTID
;
259 sk
->max_objectid
= BTRFS_EXTENT_CSUM_OBJECTID
;
260 sk
->max_type
= BTRFS_EXTENT_CSUM_KEY
;
261 sk
->min_type
= BTRFS_EXTENT_CSUM_KEY
;
262 sk
->min_offset
= offset
;
263 sk
->max_offset
= (u64
)-1;
264 sk
->max_transid
= (u64
)-1;
267 printf("Search block: %llu\n", (unsigned long long)sk
->min_offset
);
268 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
270 printf("%s: search ioctl: ioctl ret=%d, error: %s\n", __func__
, ret
, strerror(errno
));
274 if (sk
->nr_items
== 0) {
275 printf("no items found\n");
281 for (i
= 0; i
< sk
->nr_items
; i
++) {
284 int csum_size
= sizeof(item
);
286 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
289 printf("SH: tid %llu objid %llu off %llu type %u len %u\n",
290 (unsigned long long)sh
->transid
,
291 (unsigned long long)sh
->objectid
,
292 (unsigned long long)sh
->offset
,
297 for (j
= 0; j
< sh
->len
/ csum_size
; j
++) {
298 memcpy(&item
, args
.buf
+ off
+ j
* csum_size
, sizeof(item
));
299 printf("DATA[%d]: u32 = 0x%08x\n", j
, item
);
300 realcsums
[*count
] = item
;
305 sk
->min_objectid
= sh
->objectid
;
306 sk
->min_type
= sh
->type
;
307 sk
->min_offset
= sh
->offset
;
313 static int extent_offset_to_physical(int fd
, u64 ino
, u64 offset
, u64
*phys
)
315 struct btrfs_ioctl_search_args args
;
316 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
317 struct btrfs_ioctl_search_header
*sh
;
322 sk
->tree_id
= BTRFS_FS_TREE_OBJECTID
;
323 sk
->min_objectid
= ino
;
324 sk
->max_objectid
= ino
;
325 sk
->max_type
= BTRFS_EXTENT_DATA_KEY
;
326 sk
->min_type
= BTRFS_EXTENT_DATA_KEY
;
327 sk
->min_offset
= offset
;
328 sk
->max_offset
= (u64
)-1;
329 sk
->max_transid
= (u64
)-1;
332 printf("Search extent offset: %llu\n", (unsigned long long)sk
->min_offset
);
333 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
335 printf("%s: search ioctl: ioctl ret=%d, error: %s\n", __func__
, ret
, strerror(errno
));
339 if (sk
->nr_items
== 0) {
340 printf("no items found\n");
345 for (i
= 0; i
< sk
->nr_items
; i
++) {
346 struct btrfs_file_extent_item fi
;
348 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
351 printf("SH: tid %llu objid %llu off %llu type %u len %u\n",
352 (unsigned long long)sh
->transid
,
353 (unsigned long long)sh
->objectid
,
354 (unsigned long long)sh
->offset
,
360 memcpy(&fi
, args
.buf
+ off
, sizeof(fi
));
361 printf("FI: disk_bytenr %llu disk_num_bytes %llu offset %llu\n",
362 (unsigned long long)fi
.disk_bytenr
,
363 (unsigned long long)fi
.disk_num_bytes
,
364 (unsigned long long)fi
.offset
);
365 *phys
= fi
.disk_bytenr
;
369 sk
->min_objectid
= sh
->objectid
;
370 sk
->min_type
= sh
->type
;
371 sk
->min_offset
= sh
->offset
;
377 static int cmd_bsum(int argc
, char **argv
)
390 int c
= getopt(argc
, argv
, "");
396 usage(cmd_logical_resolve_usage
);
400 if (check_argc_exact(argc
- optind
, 2)) {
401 usage(cmd_logical_resolve_usage
);
405 fd
= open_file_or_dir(argv
[optind
+1]);
407 fprintf(stderr
, "ERROR: can't access '%s'\n", argv
[optind
+1]);
411 offset
= atoi(argv
[optind
]);
412 if(fstat(fd
, &st
) == -1) {
413 fprintf(stderr
, "ERROR: stat\n");
417 printf("Inode: %llu\n", (unsigned long long)st
.st_ino
);
418 printf("Offset: %llu\n", (unsigned long long)offset
);
419 extent_offset_to_physical(fd
, st
.st_ino
, offset
, &phys
);
420 printf("Physical: %llu\n", (unsigned long long)phys
);
421 csum_for_offset(fd
, phys
, csums
, &count
);
422 for (j
= 0; j
< count
; j
++) {
423 u32
*items
= (u32
*)csums
;
424 printf("BLOCK[%d] CSUM=0x%x\n",
432 const struct cmd_group inspect_cmd_group
= {
433 inspect_cmd_group_usage
, NULL
, {
434 { "inode-resolve", cmd_inode_resolve
, cmd_inode_resolve_usage
,
436 { "logical-resolve", cmd_logical_resolve
,
437 cmd_logical_resolve_usage
, NULL
, 0 },
439 cmd_bsum_usage
, NULL
, 0 },
444 int cmd_inspect(int argc
, char **argv
)
446 return handle_command_group(&inspect_cmd_group
, argc
, argv
);