From: Theodore Ts'o Date: Mon, 27 Jul 2009 02:29:47 +0000 (-0400) Subject: debugfs: Add the new command dump_extents and extent the stat command X-Git-Tag: v1.41.9~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=187cb623dc8085439d366dceb07bc2191da3c21e;p=thirdparty%2Fe2fsprogs.git debugfs: Add the new command dump_extents and extent the stat command Extend the stat command to display more detailed extent information if the file uses extent mapping instead of displaying the block map using the block_iterate funtion. Add the command dump_extents which displays even more detailed information about an inode's extent tree. This commit is an extension of a patch from Curt Wohlgemuth. Signed-off-by: Curt Wohlgemuth Signed-off-by: "Theodore Ts'o" --- diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct index 5355764e2..95dea0dfc 100644 --- a/debugfs/debug_cmds.ct +++ b/debugfs/debug_cmds.ct @@ -43,6 +43,9 @@ request do_list_dir, "List directory", request do_stat, "Show inode information ", show_inode_info, stat; +request do_dump_extents, "Dump extents information ", + dump_extents, extents, ex; + request do_link, "Create directory link", link, ln; diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in index 4dcc48b82..9012a56a0 100644 --- a/debugfs/debugfs.8.in +++ b/debugfs/debugfs.8.in @@ -192,6 +192,25 @@ option is given set the owner, group and permissions information on to match .IR filespec . .TP +.I dump_extents [-n] [-l] filespec +Dump the the extent tree of the inode +.IR filespec . +The +.I -n +flag will cause +.I dump_extents +to only display the interior nodes in the extent tree. The +.I -l +flag cause +.I dump_extents +to only display the leaf nodes in the extent tree. +.IP +(Please note that the length and range of blocks for the last extent in +an interior node is an estimate by the extents library functions, and is +not stored in file esystem data structures. Hence, the values displayed +may not necessarily by accurate and does not indicate a problem or +corruption in the file system.) +.TP .I expand_dir filespec Expand the directory .IR filespec . diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index 1710aa224..a72d800da 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -551,6 +551,139 @@ static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode) fprintf(f,"\n"); } +static int int_log10(unsigned long long arg) +{ + int l = 0; + + arg = arg / 10; + while (arg) { + l++; + arg = arg / 10; + } + return l; +} + +#define DUMP_LEAF_EXTENTS 0x01 +#define DUMP_NODE_EXTENTS 0x02 +#define DUMP_EXTENT_TABLE 0x04 + +static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino, + int flags, int logical_width, int physical_width) +{ + ext2_extent_handle_t handle; + struct ext2fs_extent extent; + struct ext2_extent_info info; + int op = EXT2_EXTENT_ROOT; + unsigned int printed = 0; + errcode_t errcode; + + errcode = ext2fs_extent_open(current_fs, ino, &handle); + if (errcode) + return; + + if (flags & DUMP_EXTENT_TABLE) + fprintf(f, "Level Entries %*s %*s Length Flags\n", + (logical_width*2)+3, "Logical", + (physical_width*2)+3, "Physical"); + else + fprintf(f, "%sEXTENTS:\n%s", prefix, prefix); + + while (1) { + errcode = ext2fs_extent_get(handle, op, &extent); + + if (errcode) + break; + + op = EXT2_EXTENT_NEXT; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { + if ((flags & DUMP_LEAF_EXTENTS) == 0) + continue; + } else { + if ((flags & DUMP_NODE_EXTENTS) == 0) + continue; + } + + errcode = ext2fs_extent_get_info(handle, &info); + if (errcode) + continue; + + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu%*s %6u\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width+3, "", extent.e_len); + continue; + } + + fprintf(f, "%s(NODE #%d, %lld-%lld, blk %lld)", + printed ? ", " : "", + info.curr_entry, + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_pblk); + printed = 1; + continue; + } + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu - %*llu %6u %s\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width, + extent.e_pblk + (extent.e_len - 1), + extent.e_len, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + "Uninit" : ""); + continue; + } + + if (extent.e_len == 0) + continue; + else if (extent.e_len == 1) + fprintf(f, + "%s(%lld%s): %lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk); + else + fprintf(f, + "%s(%lld-%lld%s): %lld-%lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk, + extent.e_pblk + (extent.e_len - 1)); + printed = 1; + } + if (printed) + fprintf(f, "\n"); +} void internal_dump_inode(FILE *out, const char *prefix, ext2_ino_t inode_num, struct ext2_inode *inode, @@ -671,9 +804,13 @@ void internal_dump_inode(FILE *out, const char *prefix, } fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n", devnote, major, minor, major, minor); + } else if (do_dump_blocks) { + if (inode->i_flags & EXT4_EXTENTS_FL) + dump_extents(out, prefix, inode_num, + DUMP_LEAF_EXTENTS, 0, 0); + else + dump_blocks(out, prefix, inode_num); } - else if (do_dump_blocks) - dump_blocks(out, prefix, inode_num); } static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode) @@ -716,6 +853,69 @@ void do_stat(int argc, char *argv[]) return; } +void do_dump_extents(int argc, char *argv[]) +{ + struct ext2_inode inode; + ext2_ino_t ino; + FILE *out; + int c, flags = 0; + int logical_width; + int physical_width; + + reset_getopt(); + while ((c = getopt(argc, argv, "nl")) != EOF) { + switch (c) { + case 'n': + flags |= DUMP_NODE_EXTENTS; + break; + case 'l': + flags |= DUMP_LEAF_EXTENTS; + break; + } + } + + if (argc != optind+1) { + print_usage: + com_err(0, 0, "Usage: dump_extents [-n] [-l] file"); + return; + } + + if (flags == 0) + flags = DUMP_NODE_EXTENTS | DUMP_LEAF_EXTENTS; + flags |= DUMP_EXTENT_TABLE; + + if (check_fs_open(argv[0])) + return; + + ino = string_to_inode(argv[optind]); + if (ino == 0) + return; + + if (debugfs_read_inode(ino, &inode, argv[0])) + return; + + if ((inode.i_flags & EXT4_EXTENTS_FL) == 0) { + fprintf(stderr, "%s: does not uses extent block maps\n", + argv[optind]); + return; + } + + logical_width = int_log10(((inode.i_size | + (__u64) inode.i_size_high << 32) + + current_fs->blocksize - 1) / + current_fs->blocksize) + 1; + if (logical_width < 5) + logical_width = 5; + physical_width = int_log10(current_fs->super->s_blocks_count) + 1; + if (physical_width < 5) + physical_width = 5; + + out = open_pager(); + dump_extents(out, "", ino, flags, logical_width, physical_width); + close_pager(out); + return; +} + void do_chroot(int argc, char *argv[]) { ext2_ino_t inode;