[Ocfs2-tools-devel] [RFC 2/9] dx_dirs v5: debugfs.ocfs2 support

Coly Li coly.li at suse.de
Wed Jan 27 12:11:37 PST 2010


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 <mfasheh at suse.com>
Signed-off-by: Coly Li <coly.li at suse.de>
---
 commands.c     |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 dump.c         |  164 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 include/dump.h |    5 +
 3 files changed, 335 insertions(+), 7 deletions(-)

Index: ocfs2-tools/debugfs.ocfs2/commands.c
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/commands.c
+++ ocfs2-tools/debugfs.ocfs2/commands.c
@@ -76,6 +76,10 @@ static void do_controld(char **args);
 static void do_dirblocks(char **args);
 static void do_xattr(char **args);
 static void do_frag(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;

@@ -114,6 +118,10 @@ static Command commands[] = {
 	{ "decode",	do_decode_lockres },
 	{ "dirblocks",	do_dirblocks },
 	{ "frag",	do_frag },
+	{ "dx_root",	do_dx_root },
+	{ "dx_leaf",	do_dx_leaf },
+	{ "dx_dump",	do_dx_dump },
+	{ "dx_space",	do_dx_space },
 };

 /*
@@ -840,6 +848,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");
@@ -1312,6 +1324,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()
  *
  */
Index: ocfs2-tools/debugfs.ocfs2/dump.c
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/dump.c
+++ ocfs2-tools/debugfs.ocfs2/dump.c
@@ -100,6 +100,9 @@ void dump_super_block(FILE *out, struct
 	fprintf(out, "\n");
 	fprintf(out, "\tUUID_hash: %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"
@@ -310,6 +313,9 @@ void dump_inode(FILE *out, struct ocfs2_
 	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)
@@ -477,6 +483,21 @@ int  dump_dir_entry (struct ocfs2_dir_en
 }

 /*
+ * 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()
  *
  */
@@ -494,13 +515,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");
@@ -520,6 +537,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()
  *
Index: ocfs2-tools/debugfs.ocfs2/include/dump.h
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/include/dump.h
+++ ocfs2-tools/debugfs.ocfs2/include/dump.h
@@ -52,7 +52,12 @@ void dump_extent_block (FILE *out, struc
 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,
--
Coly Li
SuSE Labs



More information about the Ocfs2-tools-devel mailing list