[Ocfs2-tools-devel] [PATCH 17/50] debugfs.ocfs2: Dump refcount trees

Tao Ma tao.ma at oracle.com
Mon Jan 11 07:31:03 PST 2010


From: Joel Becker <joel.becker at oracle.com>

debugfs.ocfs2 gains the 'refcount' command.  This will dump a refcount
tree including its extents.  If passed an inode specification, it will
dump the refcount tree associated with that inode.  If it is passed the
refcount block directly (surrounded by angle brackets, of course), it
will just read the refcount block.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 debugfs.ocfs2/commands.c     |  142 ++++++++++++++++++++++++++++++++++
 debugfs.ocfs2/dump.c         |   65 +++++++++++++++-
 debugfs.ocfs2/include/dump.h |    2 +
 include/ocfs2/ocfs2.h        |    8 ++
 libocfs2/feature_string.c    |  175 +++++++++++++++++++++++++++++++++++++++++-
 libocfs2/refcount.c          |   55 +++++++++++++
 6 files changed, 443 insertions(+), 4 deletions(-)

diff --git a/debugfs.ocfs2/commands.c b/debugfs.ocfs2/commands.c
index c0bf85a..94da555 100644
--- a/debugfs.ocfs2/commands.c
+++ b/debugfs.ocfs2/commands.c
@@ -76,6 +76,7 @@ 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_refcount(char **args);
 
 dbgfs_gbls gbls;
 
@@ -114,6 +115,7 @@ static Command commands[] = {
 	{ "decode",	do_decode_lockres },
 	{ "dirblocks",	do_dirblocks },
 	{ "frag",	do_frag },
+	{ "refcount",	do_refcount },
 };
 
 /*
@@ -856,6 +858,8 @@ static void do_help (char **args)
 	printf ("open <device> [-i] [-s backup#]\t\tOpen a device\n");
 	printf ("quit, q\t\t\t\t\tExit the program\n");
 	printf ("rdump [-v] <filespec> <outdir>\t\tRecursively dumps from src to a dir on a mounted filesystem\n");
+	printf ("refcount [-e] <filespec>\t\t\tDump the refcount tree "
+		"for the specified inode or refcount block\n");
 	printf ("slotmap\t\t\t\t\tShow slot map\n");
 	printf ("stat <filespec>\t\t\t\tShow inode\n");
 	printf ("stats [-h]\t\t\t\tShow superblock\n");
@@ -1775,6 +1779,7 @@ static void do_icheck(char **args)
 
 	return;
 }
+
 /*
  * do_xattr()
  *
@@ -1939,3 +1944,140 @@ static void do_frag(char **args)
 
 	return ;
 }
+
+static void walk_refcount_block(FILE *out, struct ocfs2_refcount_block *rb,
+				int extent_tree)
+{
+	errcode_t ret = 0;
+	uint32_t phys_cpos = UINT32_MAX;
+	uint32_t e_cpos = 0, num_clusters = 0;
+	uint64_t p_blkno = 0;
+	char *buf = NULL;
+	struct ocfs2_refcount_block *leaf_rb;
+
+	if (!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)) {
+		dump_refcount_records(out, rb);
+		return;
+	}
+
+	if (extent_tree) {
+		fprintf(out,
+			"\tExtent tree in refcount block %"PRIu64"\n"
+			"\tDepth: %d  Records: %d\n",
+			(uint64_t)rb->rf_blkno,
+			rb->rf_list.l_tree_depth,
+			rb->rf_list.l_next_free_rec);
+		ret = traverse_extents(gbls.fs, &rb->rf_list, out);
+		if (ret)
+			com_err("refcount", ret,
+				"while traversing the extent tree "
+				"of refcount block %"PRIu64,
+				rb->rf_blkno);
+	}
+
+	ret = ocfs2_malloc_block(gbls.fs->fs_io, &buf);
+	if (ret) {
+		com_err("refcount", ret, "while allocating a buffer");
+		return;
+	}
+
+	while (phys_cpos > 0) {
+		ret = ocfs2_refcount_tree_get_rec(gbls.fs, rb, phys_cpos,
+						  &p_blkno, &e_cpos,
+						  &num_clusters);
+		if (ret) {
+			com_err("refcount", ret,
+				"while looking up next refcount leaf in "
+				"recount block %"PRIu64"\n",
+				rb->rf_blkno);
+			break;
+		}
+
+		ret = ocfs2_read_refcount_block(gbls.fs, p_blkno, buf);
+		if (ret) {
+			com_err("refcount", ret, "while reading refcount block"
+				" %"PRIu64, p_blkno);
+			break;
+		}
+
+		leaf_rb = (struct ocfs2_refcount_block *)buf;
+		dump_refcount_block(out, leaf_rb);
+		walk_refcount_block(out, leaf_rb, extent_tree);
+
+		if (e_cpos == 0)
+			break;
+
+		phys_cpos = e_cpos - 1;
+	}
+
+	ocfs2_free(&buf);
+}
+
+/* do_refcount() can take an inode or a refcount block address. */
+static void do_refcount(char **args)
+{
+	struct ocfs2_dinode *di;
+	struct ocfs2_refcount_block *rb;
+	uint64_t blkno;
+	char *buf = NULL;
+	FILE *out;
+	errcode_t ret = 0;
+	int extent_tree = 0;
+	char *inode_args[3] = {
+		args[0],
+		args[1],
+		NULL,
+	};
+
+	if (args[1] && !strcmp(args[1], "-e")) {
+		extent_tree = 1;
+		inode_args[1] = args[2];
+	}
+
+	if (!inode_args[1]) {
+		fprintf(stderr, "usage: %s [-e] <filespec>\n", args[0]);
+		return;
+	}
+
+	if (process_inode_args(inode_args, &blkno))
+		return ;
+
+	buf = gbls.blockbuf;
+	ret = ocfs2_read_inode(gbls.fs, blkno, buf);
+	if (!ret) {
+		di = (struct ocfs2_dinode *)buf;
+		if (!di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
+			fprintf(stderr,
+				"%s: Inode %"PRIu64" does not have a "
+				"refcount tree\n",
+				args[0], blkno);
+			return;
+		}
+
+		blkno = di->i_refcount_loc;
+	} else if ((ret != OCFS2_ET_IO) && (ret != OCFS2_ET_BAD_INODE_MAGIC)) {
+		/*
+		 * If the user passed a refcount block address,
+		 * read_inode() will return ET_IO or ET_BAD_INODE_MAGIC.
+		 * For those cases we proceed treating blkno as a
+		 * refcount block.  All other errors are real errors.
+		 */
+		com_err(args[0], ret, "while reading inode %"PRIu64"", blkno);
+		return;
+	}
+
+	ret = ocfs2_read_refcount_block(gbls.fs, blkno, buf);
+	if (ret) {
+		com_err(args[0], ret, "while reading refcount block %"PRIu64,
+			blkno);
+		return;
+	}
+
+	out = open_pager(gbls.interactive);
+
+	rb = (struct ocfs2_refcount_block *)buf;
+	dump_refcount_block(out, rb);
+	walk_refcount_block(out, rb, extent_tree);
+
+	close_pager(out);
+}
diff --git a/debugfs.ocfs2/dump.c b/debugfs.ocfs2/dump.c
index 4c6891a..75ee08e 100644
--- a/debugfs.ocfs2/dump.c
+++ b/debugfs.ocfs2/dump.c
@@ -240,6 +240,8 @@ void dump_inode(FILE *out, struct ocfs2_dinode *in)
 		g_string_append(dyn_features, "InlineXattr ");
 	if (in->i_dyn_features & OCFS2_INDEXED_DIR_FL)
 		g_string_append(dyn_features, "IndexedDir ");
+	if (in->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)
+		g_string_append(dyn_features, "Refcounted ");
 
 	fprintf(out, "\tInode: %"PRIu64"   Mode: 0%0o   Generation: %u (0x%x)\n",
 		(uint64_t)in->i_blkno, mode, in->i_generation, in->i_generation);
@@ -285,6 +287,9 @@ void dump_inode(FILE *out, struct ocfs2_dinode *in)
 	fprintf(out, "\tmtime_nsec: 0x%08"PRIx32" -- %u\n",
 		in->i_mtime_nsec, in->i_mtime_nsec);
 
+	fprintf(out, "\tRefcount Block: %"PRIu64"\n",
+		(uint64_t)in->i_refcount_loc);
+
 	fprintf(out, "\tLast Extblk: %"PRIu64"\n", (uint64_t)in->i_last_eb_blk);
 	if (in->i_suballoc_slot == (uint16_t)OCFS2_INVALID_SLOT)
 		strcpy(tmp_str, "Global");
@@ -357,6 +362,7 @@ void dump_extent_list (FILE *out, struct ocfs2_extent_list *ext)
 	struct ocfs2_extent_rec *rec;
 	int i;
 	uint32_t clusters;
+	char flags[PATH_MAX];
 
 	fprintf(out, "\tTree Depth: %u   Count: %u   Next Free Rec: %u\n",
 		ext->l_tree_depth, ext->l_count, ext->l_next_free_rec);
@@ -379,11 +385,18 @@ void dump_extent_list (FILE *out, struct ocfs2_extent_list *ext)
 			fprintf(out, "\t%-2d %-11u   %-12u   %"PRIu64"\n",
 				i, rec->e_cpos, clusters,
 				(uint64_t)rec->e_blkno);
-		else
+		else {
+			flags[0] = '\0';
+			if (ocfs2_snprint_extent_flags(flags, PATH_MAX,
+						       rec->e_flags))
+				flags[0] = '\0';
+
 			fprintf(out,
-				"\t%-2d %-11u   %-12u   %-13"PRIu64"   0x%x\n",
+				"\t%-2d %-11u   %-12u   "
+				"%-13"PRIu64"   0x%x %s\n",
 				i, rec->e_cpos, clusters,
-				(uint64_t)rec->e_blkno,	rec->e_flags);
+				(uint64_t)rec->e_blkno, rec->e_flags, flags);
+		}
 	}
 
 bail:
@@ -1028,3 +1041,49 @@ void dump_frag(FILE *out, uint64_t ino, uint32_t clusters,
 		" %u\textents: %u\tscore: %.0f\n", ino,
 		frag_level, clusters, extents, frag_level * clusters_per_mb);
 }
+
+void dump_refcount_block(FILE *out, struct ocfs2_refcount_block *rb)
+{
+	char flags[PATH_MAX];
+
+	fprintf(out, "\tSubAlloc Bit: %u   SubAlloc Slot: %u\n",
+		rb->rf_suballoc_bit, rb->rf_suballoc_slot);
+
+	fprintf(out, "\tFS Generation: %u (0x%x)\n", rb->rf_fs_generation,
+		rb->rf_fs_generation);
+	fprintf(out, "\tBlknum: %"PRIu64"   Parent: %"PRIu64"\n",
+		(uint64_t)rb->rf_blkno, (uint64_t)rb->rf_parent);
+	fprintf(out, "\tCpos: %"PRIu64"   Last Leaf block: %"PRIu64"\n",
+		(uint64_t)rb->rf_cpos, (uint64_t)rb->rf_last_eb_blk);
+	fprintf(out, "\tReftree Count: %u   Ref clusters: %u\n",
+		rb->rf_count, rb->rf_clusters);
+
+	flags[0] = '\0';
+	if (ocfs2_snprint_refcount_flags(flags, PATH_MAX, rb->rf_flags))
+		flags[0] = '\0';
+	fprintf(out, "\tFlags: 0x%x %s\n", rb->rf_flags, flags);
+	dump_block_check(out, &rb->rf_check);
+
+	return;
+
+}
+
+void dump_refcount_records(FILE *out, struct ocfs2_refcount_block *rb)
+{
+	int i;
+	struct ocfs2_refcount_list *rl = &rb->rf_records;
+
+	fprintf(out, "\tRefcount records: %u   Used: %u\n",
+		rl->rl_count, rl->rl_used);
+	fprintf(out, "\t### %-20s   %-12s   %-12s\n", "Physical cpos",
+			"Clusters", "Reference count");
+
+	for (i = 0; i < rl->rl_used; i++) {
+		fprintf(out,
+			"\t%-3d %-20"PRIu64"   %-12"PRIu32"   %"PRIu32"\n",
+			i, rl->rl_recs[i].r_cpos, rl->rl_recs[i].r_clusters,
+			rl->rl_recs[i].r_refcount);
+	}
+}
+
+
diff --git a/debugfs.ocfs2/include/dump.h b/debugfs.ocfs2/include/dump.h
index 8cd9a97..cb677c9 100644
--- a/debugfs.ocfs2/include/dump.h
+++ b/debugfs.ocfs2/include/dump.h
@@ -78,5 +78,7 @@ errcode_t dump_xattr_block(FILE *out, ocfs2_filesys *fs,
 			   int verbose);
 void dump_frag(FILE *out, uint64_t ino, uint32_t clusters,
 	       uint32_t extents);
+void dump_refcount_block(FILE *out, struct ocfs2_refcount_block *rb);
+void dump_refcount_records(FILE *out, struct ocfs2_refcount_block *rb);
 
 #endif		/* __DUMP_H__ */
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index aa9a77d..161d6c8 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -409,6 +409,12 @@ errcode_t ocfs2_decrease_refcount(ocfs2_filesys *fs,
 errcode_t ocfs2_refcount_cow(ocfs2_cached_inode *cinode,
 			     uint32_t cpos, uint32_t write_len,
 			     uint32_t max_cpos);
+errcode_t ocfs2_refcount_tree_get_rec(ocfs2_filesys *fs,
+				      struct ocfs2_refcount_block *rb,
+				      uint32_t phys_cpos,
+				      uint64_t *p_blkno,
+				      uint32_t *e_cpos,
+				      uint32_t *num_clusters);
 errcode_t ocfs2_swap_dir_entries_from_cpu(void *buf, uint64_t bytes);
 errcode_t ocfs2_swap_dir_entries_to_cpu(void *buf, uint64_t bytes);
 void ocfs2_swap_dir_trailer(struct ocfs2_dir_block_trailer *trailer);
@@ -850,6 +856,8 @@ enum ocfs2_feature_levels {
 errcode_t ocfs2_snprint_feature_flags(char *str, size_t size,
 				      ocfs2_fs_options *flags);
 errcode_t ocfs2_snprint_tunefs_flags(char *str, size_t size, uint16_t flags);
+errcode_t ocfs2_snprint_extent_flags(char *str, size_t size, uint8_t flags);
+errcode_t ocfs2_snprint_refcount_flags(char *str, size_t size, uint8_t flags);
 errcode_t ocfs2_parse_feature(const char *opts,
 			      ocfs2_fs_options *feature_flags,
 			      ocfs2_fs_options *reverse_flags);
diff --git a/libocfs2/feature_string.c b/libocfs2/feature_string.c
index 7dcdc27..6e773f3 100644
--- a/libocfs2/feature_string.c
+++ b/libocfs2/feature_string.c
@@ -48,6 +48,18 @@ struct tunefs_flag_name {
 	uint16_t	tfn_flag;
 };
 
+/* Printable names for extent flags */
+struct extent_flag_name {
+	const char	*efn_name;
+	uint8_t		efn_flag;
+};
+
+/* Printable names for refcount flags */
+struct refcount_flag_name {
+	const char	*rfn_name;
+	uint32_t	rfn_flag;
+};
+
 struct feature_level_translation {
 	const char *fl_str;
 	enum ocfs2_feature_levels fl_type;
@@ -244,6 +256,46 @@ static struct tunefs_flag_name ocfs2_tunefs_flag_names[] = {
 	},
 };
 
+/*
+ * The printable names of every flag in e_flags.  If libocfs2 supports the
+ * flag, its name must be here.
+ *
+ * These MUST be kept in sync with the flags in ocfs2_fs.h.
+ */
+static struct extent_flag_name ocfs2_extent_flag_names[] = {
+	{
+		.efn_name = "Unwritten",
+		.efn_flag = OCFS2_EXT_UNWRITTEN,
+	},
+	{
+		.efn_name = "Refcounted",
+		.efn_flag = OCFS2_EXT_REFCOUNTED,
+	},
+	{
+		.efn_name = NULL,
+	},
+};
+
+/*
+ * The printable names of every flag in rf_flags.  If libocfs2 supports the
+ * flag, its name must be here.
+ *
+ * These MUST be kept in sync with the flags in ocfs2_fs.h.
+ */
+static struct refcount_flag_name ocfs2_refcount_flag_names[] = {
+	{
+		.rfn_name = "Leaf",
+		.rfn_flag = OCFS2_REFCOUNT_LEAF_FL,
+	},
+	{
+		.rfn_name = "Tree",
+		.rfn_flag = OCFS2_REFCOUNT_TREE_FL,
+	},
+	{
+		.rfn_name = NULL,
+	},
+};
+
 static inline void merge_features(ocfs2_fs_options *features,
 				  ocfs2_fs_options new_features)
 {
@@ -388,6 +440,90 @@ errcode_t ocfs2_snprint_tunefs_flags(char *str, size_t size, uint16_t flags)
 	return err;
 }
 
+errcode_t ocfs2_snprint_extent_flags(char *str, size_t size, uint8_t flags)
+{
+	int i, printed;
+	char *ptr = str;
+	size_t remain = size;
+	errcode_t err = 0;
+	char *sep = " ";
+	uint8_t found = 0;
+
+	for (i = 0; ocfs2_extent_flag_names[i].efn_name; i++) {
+		if (!(flags & ocfs2_extent_flag_names[i].efn_flag))
+			continue;
+		found |= ocfs2_extent_flag_names[i].efn_flag;
+
+		printed = snprintf(ptr, remain, "%s%s",
+				   ptr == str ? "" : sep,
+				   ocfs2_extent_flag_names[i].efn_name);
+		if (printed < 0)
+			err = OCFS2_ET_INTERNAL_FAILURE;
+		else if (printed >= remain)
+			err = OCFS2_ET_NO_SPACE;
+		if (err)
+			break;
+
+		remain -= printed;
+		ptr += printed;
+	}
+
+	if (!err) {
+		if (found != flags) {
+			printed = snprintf(ptr, remain, "%sUnknown",
+					   ptr == str ? "" : sep);
+			if (printed < 0)
+				err = OCFS2_ET_INTERNAL_FAILURE;
+			else if (printed >= remain)
+				err = OCFS2_ET_NO_SPACE;
+		}
+	}
+
+	return err;
+}
+
+errcode_t ocfs2_snprint_refcount_flags(char *str, size_t size, uint8_t flags)
+{
+	int i, printed;
+	char *ptr = str;
+	size_t remain = size;
+	errcode_t err = 0;
+	char *sep = " ";
+	uint8_t found = 0;
+
+	for (i = 0; ocfs2_refcount_flag_names[i].rfn_name; i++) {
+		if (!(flags & ocfs2_refcount_flag_names[i].rfn_flag))
+			continue;
+		found |= ocfs2_refcount_flag_names[i].rfn_flag;
+
+		printed = snprintf(ptr, remain, "%s%s",
+				   ptr == str ? "" : sep,
+				   ocfs2_refcount_flag_names[i].rfn_name);
+		if (printed < 0)
+			err = OCFS2_ET_INTERNAL_FAILURE;
+		else if (printed >= remain)
+			err = OCFS2_ET_NO_SPACE;
+		if (err)
+			break;
+
+		remain -= printed;
+		ptr += printed;
+	}
+
+	if (!err) {
+		if (found != flags) {
+			printed = snprintf(ptr, remain, "%sUnknown",
+					   ptr == str ? "" : sep);
+			if (printed < 0)
+				err = OCFS2_ET_INTERNAL_FAILURE;
+			else if (printed >= remain)
+				err = OCFS2_ET_NO_SPACE;
+		}
+	}
+
+	return err;
+}
+
 
 /*
  * If we are asked to clear a feature, we also need to clear any other
@@ -661,7 +797,42 @@ static void print_tunefs_flags(void)
 	fprintf(stdout, "Printable s_tunefs_flag:\n");
 
 	err = ocfs2_snprint_tunefs_flags(buf, PATH_MAX,
-					 OCFS2_TUNEFS_INPROG_REMOVE_SLOT);
+					 OCFS2_TUNEFS_INPROG_REMOVE_SLOT |
+					 OCFS2_TUNEFS_INPROG_DIR_TRAILER);
+	if (err)
+		snprintf(buf, PATH_MAX, "An error occurred: %s",
+			 error_message(err));
+	fprintf(stdout, "FLAGS:\t\t%s\n", buf);
+	fprintf(stdout, "\n");
+}
+
+static void print_extent_flags(void)
+{
+	errcode_t err;
+	char buf[PATH_MAX];
+
+	fprintf(stdout, "Printable e_flags:\n");
+
+	err = ocfs2_snprint_extent_flags(buf, PATH_MAX,
+					 OCFS2_EXT_UNWRITTEN |
+					 OCFS2_EXT_REFCOUNTED);
+	if (err)
+		snprintf(buf, PATH_MAX, "An error occurred: %s",
+			 error_message(err));
+	fprintf(stdout, "FLAGS:\t\t%s\n", buf);
+	fprintf(stdout, "\n");
+}
+
+static void print_refcount_flags(void)
+{
+	errcode_t err;
+	char buf[PATH_MAX];
+
+	fprintf(stdout, "Printable rf_flags:\n");
+
+	err = ocfs2_snprint_refcount_flags(buf, PATH_MAX,
+					   OCFS2_REFCOUNT_TREE_FL |
+					   OCFS2_REFCOUNT_LEAF_FL);
 	if (err)
 		snprintf(buf, PATH_MAX, "An error occurred: %s",
 			 error_message(err));
@@ -768,6 +939,8 @@ int main(int argc, char *argv[])
 	print_order(1, &clear_features);
 
 	print_tunefs_flags();
+	print_extent_flags();
+	print_refcount_flags();
 
 	return 0;
 }
diff --git a/libocfs2/refcount.c b/libocfs2/refcount.c
index 5ece2eb..260aefe 100644
--- a/libocfs2/refcount.c
+++ b/libocfs2/refcount.c
@@ -1839,3 +1839,58 @@ errcode_t ocfs2_refcount_cow(ocfs2_cached_inode *cinode,
 
 	return ret;
 }
+
+errcode_t ocfs2_refcount_tree_get_rec(ocfs2_filesys *fs,
+				      struct ocfs2_refcount_block *rb,
+				      uint32_t phys_cpos,
+				      uint64_t *p_blkno,
+				      uint32_t *e_cpos,
+				      uint32_t *num_clusters)
+{
+	int i;
+	errcode_t ret = 0;
+	char *eb_buf = NULL;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_rec *rec = NULL;
+	struct ocfs2_extent_list *el = &rb->rf_list;
+	uint64_t e_blkno = 0;
+
+	if (el->l_tree_depth) {
+		ret = ocfs2_tree_find_leaf(fs, el, rb->rf_blkno,
+					   (char *)rb, phys_cpos,
+					   &eb_buf);
+		if (ret)
+			goto out;
+
+		eb = (struct ocfs2_extent_block *)eb_buf;
+		el = &eb->h_list;
+
+		if (el->l_tree_depth) {
+			ret = OCFS2_ET_INVALID_ARGUMENT;
+			goto out;
+		}
+	}
+
+	for (i = el->l_next_free_rec - 1; i >= 0; i--) {
+		rec = &el->l_recs[i];
+
+		if (rec->e_cpos <= phys_cpos) {
+			e_blkno = rec->e_blkno;
+			break;
+		}
+	}
+
+	if (!e_blkno) {
+		ret = OCFS2_ET_INVALID_ARGUMENT;
+		goto out;
+	}
+
+	*p_blkno = rec->e_blkno;
+	*num_clusters = rec->e_leaf_clusters;
+	if (e_cpos)
+		*e_cpos = rec->e_cpos;
+out:
+	if (eb_buf)
+		ocfs2_free(&eb_buf);
+	return ret;
+}
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list