From ea63b432090f6925f5d21cac07afae1748f572c7 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 5 Mar 2010 15:48:13 +0800 Subject: [PATCH 02/15] dx_dirs: debugfs.ocfs2 support This adds a full set of functionality to debugfs.ocfs2 so that we can visualize and debug indexed directories. Aside from updates to other commands to dump newly added/used fields in old structures, we get the following debugfs.ocfs2 commands: dx_space - Show all entries in the free list dx_dump - Show the directory index (including root block) dx_leaf - Show a single directory index leaf block dx_root - Show directory index root block, as well as any extent blocks for non-inline dx_roots. Signed-off-by: Mark Fasheh Signed-off-by: Coly Li --- debugfs.ocfs2/commands.c | 173 ++++++++++++++++++++++++++++++++++++++++++ debugfs.ocfs2/dump.c | 164 ++++++++++++++++++++++++++++++++++++++-- debugfs.ocfs2/include/dump.h | 5 + 3 files changed, 335 insertions(+), 7 deletions(-) diff --git a/debugfs.ocfs2/commands.c b/debugfs.ocfs2/commands.c index 1c19ab4..04e56b4 100644 --- a/debugfs.ocfs2/commands.c +++ b/debugfs.ocfs2/commands.c @@ -77,6 +77,10 @@ static void do_dirblocks(char **args); static void do_xattr(char **args); static void do_frag(char **args); static void do_refcount(char **args); +static void do_dx_root(char **args); +static void do_dx_leaf(char **args); +static void do_dx_dump(char **args); +static void do_dx_space(char **args); dbgfs_gbls gbls; @@ -116,6 +120,10 @@ static Command commands[] = { { "dirblocks", do_dirblocks }, { "frag", do_frag }, { "refcount", do_refcount }, + { "dx_root", do_dx_root }, + { "dx_leaf", do_dx_leaf }, + { "dx_dump", do_dx_dump }, + { "dx_space", do_dx_space }, }; /* @@ -842,6 +850,10 @@ static void do_help (char **args) printf ("dlm_locks [-f ] [-l] lockname\t\t\tShow live dlm locking state\n"); printf ("dump [-p] \t\tDumps file to outfile on a mounted fs\n"); printf ("dirblocks \t\t\tDump directory blocks\n"); + printf ("dx_space \t\t\tDump directory free space list\n"); + printf ("dx_dump \t\t\tShow directory index information\n"); + printf ("dx_leaf \t\t\tShow directory index leaf block only\n"); + printf ("dx_root \t\t\tShow directory index root block only\n"); printf ("encode \t\t\tShow lock name\n"); printf ("extent \t\t\t\tShow extent block\n"); printf ("findpath \t\t\tList one pathname of the inode/lockname\n"); @@ -1316,6 +1328,167 @@ static void do_dirblocks (char **args) } /* + * do_dx_root() + * + */ +static void do_dx_root (char **args) +{ + struct ocfs2_dx_root_block *dx_root; + uint64_t blkno; + char *buf = NULL; + FILE *out; + errcode_t ret = 0; + + if (process_inodestr_args(args, 1, &blkno) != 1) + return; + + buf = gbls.blockbuf; + out = open_pager(gbls.interactive); + + ret = ocfs2_read_dx_root(gbls.fs, blkno, buf); + if (ret) { + com_err(args[0], ret, "while reading dx dir root " + "block %"PRIu64"", blkno); + close_pager (out); + return; + } + + dx_root = (struct ocfs2_dx_root_block *)buf; + dump_dx_root(out, dx_root); + if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) + traverse_extents(gbls.fs, &dx_root->dr_list, out); + close_pager(out); + + return; +} + +/* + * do_dx_leaf() + * + */ +static void do_dx_leaf (char **args) +{ + struct ocfs2_dx_leaf *dx_leaf; + uint64_t blkno; + char *buf = NULL; + FILE *out; + errcode_t ret = 0; + + if (process_inodestr_args(args, 1, &blkno) != 1) + return; + + buf = gbls.blockbuf; + out = open_pager(gbls.interactive); + + ret = ocfs2_read_dx_leaf(gbls.fs, blkno, buf); + if (ret) { + com_err(args[0], ret, "while reading dx dir leaf " + "block %"PRIu64"", blkno); + close_pager (out); + return; + } + + dx_leaf = (struct ocfs2_dx_leaf *)buf; + dump_dx_leaf(out, dx_leaf); + + close_pager(out); + + return; +} + +/* + * do_dx_dump() + * + */ +static void do_dx_dump (char **args) +{ + struct ocfs2_dinode *inode; + uint64_t ino_blkno; + char *buf = NULL; + FILE *out; + errcode_t ret = 0; + + if (process_inode_args(args, &ino_blkno)) + return; + + out = open_pager(gbls.interactive); + + buf = gbls.blockbuf; + ret = ocfs2_read_inode(gbls.fs, ino_blkno, buf); + if (ret) { + com_err(args[0], ret, "while reading inode %"PRIu64"", + ino_blkno); + close_pager (out); + return ; + } + + inode = (struct ocfs2_dinode *)buf; + + dump_dx_entries(out, inode); + + close_pager(out); + + return; +} + +/* + * do_dx_space() + * + */ +static void do_dx_space (char **args) +{ + struct ocfs2_dinode *inode; + struct ocfs2_dx_root_block *dx_root; + uint64_t ino_blkno, dx_blkno; + char *buf = NULL, *dx_root_buf = NULL; + FILE *out; + errcode_t ret = 0; + + if (process_inode_args(args, &ino_blkno)) + return; + + out = open_pager(gbls.interactive); + + buf = gbls.blockbuf; + ret = ocfs2_read_inode(gbls.fs, ino_blkno, buf); + if (ret) { + com_err(args[0], ret, "while reading inode %"PRIu64"", + ino_blkno); + goto out; + } + + inode = (struct ocfs2_dinode *)buf; + if (!(ocfs2_dir_indexed(inode))) { + fprintf(out, "Inode %"PRIu64" is not indexed\n", ino_blkno); + goto out; + } + + ret = ocfs2_malloc_block(gbls.fs->fs_io, &dx_root_buf); + if (ret) { + goto out; + } + + dx_blkno = (uint64_t) inode->i_dx_root; + + ret = ocfs2_read_dx_root(gbls.fs, dx_blkno, dx_root_buf); + if (ret) { + com_err(args[0], ret, "while reading dx dir root " + "block %"PRIu64"", dx_blkno); + goto out; + } + + dx_root = (struct ocfs2_dx_root_block *)dx_root_buf; + + dump_dx_space(out, inode, dx_root); +out: + close_pager(out); + if (dx_root_buf) + ocfs2_free(&dx_root_buf); + + return; +} + +/* * do_extent() * */ diff --git a/debugfs.ocfs2/dump.c b/debugfs.ocfs2/dump.c index 7880991..2e887ce 100644 --- a/debugfs.ocfs2/dump.c +++ b/debugfs.ocfs2/dump.c @@ -99,6 +99,9 @@ void dump_super_block(FILE *out, struct ocfs2_super_block *sb) fprintf(out, "%02X", sb->s_uuid[i]); fprintf(out, "\n"); fprintf(out, "\tHash: %u (0x%x)\n", sb->s_uuid_hash, sb->s_uuid_hash); + for (i = 0; i < 3; i++) + fprintf(out, "\tDX Seed[%d]: 0x%08x\n", i, sb->s_dx_seed[i]); + if (ocfs2_userspace_stack(sb)) fprintf(out, "\tCluster stack: %s\n" @@ -315,6 +318,9 @@ void dump_inode(FILE *out, struct ocfs2_dinode *in) if (in->i_dyn_features & OCFS2_INLINE_DATA_FL) { fprintf(out, "\tInline Data Max: %u\n", in->id2.i_data.id_count); + } else if (in->i_dyn_features & OCFS2_INDEXED_DIR_FL) { + fprintf(out, "\tIndexed Tree Root: %"PRIu64"\n", + (uint64_t)in->i_dx_root); } if (flags) @@ -490,6 +496,21 @@ int dump_dir_entry (struct ocfs2_dir_entry *rec, int offset, int blocksize, } /* + * dump_dir_trailer() + */ +static void dump_dir_trailer(FILE *out, struct ocfs2_dir_block_trailer *trailer) +{ + fprintf(out, + "\tTrailer Block: %-15"PRIu64" Inode: %-15"PRIu64" rec_len: %-4u\n", + trailer->db_blkno, trailer->db_parent_dinode, + trailer->db_compat_rec_len); + fprintf(out, + "\tLargest hole: %u Next in list: %-15"PRIu64"\n", + trailer->db_free_rec_len, trailer->db_free_next); + dump_block_check(out, &trailer->db_check); +} + +/* * dump_dir_block() * */ @@ -507,13 +528,9 @@ void dump_dir_block(FILE *out, char *buf) }; if (!strncmp((char *)trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE, - sizeof(trailer->db_signature))) { - fprintf(out, - "\tTrailer Block: %-15"PRIu64" Inode: %-15"PRIu64" rec_len: %-4u\n", - trailer->db_blkno, trailer->db_parent_dinode, - trailer->db_compat_rec_len); - dump_block_check(out, &trailer->db_check); - } else + sizeof(trailer->db_signature))) + dump_dir_trailer(out, trailer); + else end = gbls.fs->fs_blocksize; fprintf(out, "\tEntries:\n"); @@ -533,6 +550,139 @@ void dump_dir_block(FILE *out, char *buf) } } +static void dump_dx_entry(FILE *out, int i, struct ocfs2_dx_entry *dx_entry) +{ + fprintf(out, "\t %-2d (0x%08x 0x%08x) %-13"PRIu64"\n", + i, dx_entry->dx_major_hash, dx_entry->dx_minor_hash, + (uint64_t)dx_entry->dx_dirent_blk); +} + +static void dump_dx_entry_list(FILE *out, struct ocfs2_dx_entry_list *dl_list, + int traverse) +{ + int i; + + fprintf(out, "\tCount: %u Num Used: %u\n", + dl_list->de_count, dl_list->de_num_used); + + if (traverse) { + fprintf(out, "\t## %-11s %-13s\n", "Hash (Major Minor)", + "Dir Block#"); + + for (i = 0; i < dl_list->de_num_used; i++) + dump_dx_entry(out, i, &dl_list->de_entries[i]); + } +} + +void dump_dx_root(FILE *out, struct ocfs2_dx_root_block *dr) +{ + char tmp_str[30]; + GString *flags = NULL; + + flags = g_string_new(NULL); + if (dr->dr_flags & OCFS2_DX_FLAG_INLINE) + g_string_append(flags, "Inline "); + + fprintf(out, "\tDir Index Root: %"PRIu64" FS Generation: %u (0x%x)\n", + (uint64_t)dr->dr_blkno, dr->dr_fs_generation, + dr->dr_fs_generation); + + fprintf(out, "\tClusters: %u Last Extblk: %"PRIu64" " + "Dir Inode: %"PRIu64"\n", + dr->dr_clusters, (uint64_t)dr->dr_last_eb_blk, + (uint64_t)dr->dr_dir_blkno); + + if (dr->dr_suballoc_slot == (uint16_t)OCFS2_INVALID_SLOT) + strcpy(tmp_str, "Global"); + else + sprintf(tmp_str, "%d", dr->dr_suballoc_slot); + fprintf(out, "\tSub Alloc Slot: %s Sub Alloc Bit: %u " + "Flags: (0x%x) %s\n", + tmp_str, dr->dr_suballoc_bit, dr->dr_flags, flags->str); + + dump_block_check(out, &dr->dr_check); + + if (dr->dr_flags & OCFS2_DX_FLAG_INLINE) + dump_dx_entry_list(out, &dr->dr_entries, 0); + + if (flags) + g_string_free(flags, 1); +} + +void dump_dx_leaf (FILE *out, struct ocfs2_dx_leaf *dx_leaf) +{ + fprintf(out, "\tDir Index Leaf: %"PRIu64" FS Generation: %u (0x%x)\n", + (uint64_t)dx_leaf->dl_blkno, dx_leaf->dl_fs_generation, + dx_leaf->dl_fs_generation); + dump_block_check(out, &dx_leaf->dl_check); + + dump_dx_entry_list(out, &dx_leaf->dl_list, 1); +} + +static int entries_iter(ocfs2_filesys *fs, + struct ocfs2_dx_entry_list *entry_list, + struct ocfs2_dx_root_block *dx_root, + struct ocfs2_dx_leaf *dx_leaf, + void *priv_data) +{ + FILE *out = priv_data; + + if (dx_leaf) { + dump_dx_leaf(out, dx_leaf); + return 0; + } + + /* Inline entries. Dump the list directly. */ + dump_dx_entry_list(out, entry_list, 1); + + return 0; +} + +void dump_dx_entries(FILE *out, struct ocfs2_dinode *inode) +{ + struct ocfs2_dx_root_block *dx_root; + uint64_t dx_blkno; + char *buf = NULL; + errcode_t ret = 0; + + if (ocfs2_malloc_block(gbls.fs->fs_io, &buf)) + return; + + if (!(ocfs2_dir_indexed(inode))) + return; + + dx_blkno = (uint64_t) inode->i_dx_root; + + ret = ocfs2_read_dx_root(gbls.fs, dx_blkno, buf); + if (ret) + return; + + dx_root = (struct ocfs2_dx_root_block *)buf; + dump_dx_root(out, dx_root); + + ocfs2_dx_entries_iterate(gbls.fs, inode, 0, entries_iter, out); + return; +} + +static int dx_space_iter(ocfs2_filesys *fs, + uint64_t blkno, + struct ocfs2_dir_block_trailer *trailer, + char *dirblock, + void *priv_data) +{ + FILE *out = priv_data; + + dump_dir_trailer(out, trailer); + + return 0; +} + +void dump_dx_space(FILE *out, struct ocfs2_dinode *inode, + struct ocfs2_dx_root_block *dx_root) +{ + ocfs2_dx_frees_iterate(gbls.fs, inode, dx_root, 0, dx_space_iter, out); +} + /* * dump_jbd_header() * diff --git a/debugfs.ocfs2/include/dump.h b/debugfs.ocfs2/include/dump.h index cb677c9..79b10b3 100644 --- a/debugfs.ocfs2/include/dump.h +++ b/debugfs.ocfs2/include/dump.h @@ -52,7 +52,12 @@ void dump_extent_block (FILE *out, struct ocfs2_extent_block *blk); void dump_group_descriptor (FILE *out, struct ocfs2_group_desc *grp, int index); int dump_dir_entry (struct ocfs2_dir_entry *rec, int offset, int blocksize, char *buf, void *priv_data); +void dump_dx_root (FILE *out, struct ocfs2_dx_root_block *dx_root); +void dump_dx_leaf (FILE *out, struct ocfs2_dx_leaf *dx_leaf); void dump_dir_block(FILE *out, char *buf); +void dump_dx_entries(FILE *out, struct ocfs2_dinode *inode); +void dump_dx_space(FILE *out, struct ocfs2_dinode *inode, + struct ocfs2_dx_root_block *dx_root); void dump_jbd_header (FILE *out, journal_header_t *header); void dump_jbd_superblock (FILE *out, journal_superblock_t *jsb); void dump_jbd_block (FILE *out, journal_superblock_t *jsb, -- 1.6.4.2