forked from pool/ocfs2-tools
c8700c5230
OBS-URL: https://build.opensuse.org/package/show/network:ha-clustering:Factory/ocfs2-tools?expand=0&rev=8
455 lines
12 KiB
Diff
455 lines
12 KiB
Diff
From b891260ad1500f3f2c0562d4376307b18bc4a9f4 Mon Sep 17 00:00:00 2001
|
|
From: Mark Fasheh <mfasheh@suse.com>
|
|
Date: Sun, 11 Apr 2010 16:09:59 +0800
|
|
Subject: [PATCH 02/30] 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.
|
|
|
|
[modified the patch for code rebase and cleanup -- Coly Li]
|
|
|
|
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
|
|
Signed-off-by: Coly Li <coly.li@suse.de>
|
|
---
|
|
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 <file>] [-l] lockname\t\t\tShow live dlm locking state\n");
|
|
printf ("dump [-p] <filespec> <outfile>\t\tDumps file to outfile on a mounted fs\n");
|
|
printf ("dirblocks <filespec>\t\t\tDump directory blocks\n");
|
|
+ printf ("dx_space <filespec>\t\t\tDump directory free space list\n");
|
|
+ printf ("dx_dump <blkno>\t\t\tShow directory index information\n");
|
|
+ printf ("dx_leaf <blkno>\t\t\tShow directory index leaf block only\n");
|
|
+ printf ("dx_root <blkno>\t\t\tShow directory index root block only\n");
|
|
printf ("encode <filespec>\t\t\tShow lock name\n");
|
|
printf ("extent <block#>\t\t\t\tShow extent block\n");
|
|
printf ("findpath <block#>\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.7.0.2
|
|
|