[Cluster-devel] [gfs2-utils PATCH] gfs2_edit: Add more intelligence to journal dumps

Bob Peterson rpeterso at redhat.com
Thu Feb 27 14:25:12 UTC 2014


Hi,

This patch adds the ability for a gfs2_edit journal dump to look for
journal entries pertaining to a particular block. The syntax is:
gfs2_edit -p journal0 0x12345 /dev/my_vg/my_lv

Regards,

Bob Peterson
Red Hat File Systems

Signed-off-by: Bob Peterson <rpeterso at redhat.com> 
---
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index e191a27..fb30a03 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -45,8 +45,6 @@ int details = 0;
 long int gziplevel = 9;
 static int termcols;
 
-int display(int identify_only);
-
 /* for assigning numeric fields: */
 #define checkassign(strfield, struct, member, value) do {		\
 		if (strcmp(#member, strfield) == 0) {			\
@@ -578,14 +576,73 @@ static void print_usage(void)
 /* returns: metatype if block is a GFS2 structure block type                */
 /*          0 if block is not a GFS2 structure                              */
 /* ------------------------------------------------------------------------ */
-uint32_t get_block_type(const struct gfs2_buffer_head *lbh)
+uint32_t get_block_type(const struct gfs2_buffer_head *lbh, int *structlen)
 {
 	const struct gfs2_meta_header *mh = lbh->iov.iov_base;
+	uint32_t ty;
 
-	if (be32_to_cpu(mh->mh_magic) == GFS2_MAGIC)
-		return be32_to_cpu(mh->mh_type);
+	if (!be32_to_cpu(mh->mh_magic) == GFS2_MAGIC)
+		return 0;
 
-	return 0;
+	ty = be32_to_cpu(mh->mh_type);
+	if (structlen == NULL)
+		return ty;
+	switch (ty) {
+	case GFS2_METATYPE_SB:   /* 1 */
+		if (sbd.gfs1)
+			*structlen = sizeof(struct gfs_sb);
+		else
+			*structlen = sizeof(struct gfs2_sb);
+		break;
+	case GFS2_METATYPE_RG:   /* 2 */
+		*structlen = sizeof(struct gfs2_rgrp);
+		break;
+	case GFS2_METATYPE_RB:   /* 3 */
+		*structlen = sizeof(struct gfs2_meta_header);
+		break;
+	case GFS2_METATYPE_DI:   /* 4 */
+		*structlen = sizeof(struct gfs2_dinode);
+		break;
+	case GFS2_METATYPE_IN:   /* 5 */
+		if (sbd.gfs1)
+			*structlen = sizeof(struct gfs_indirect);
+		else
+			*structlen = sizeof(struct gfs2_meta_header);
+		break;
+	case GFS2_METATYPE_LF:   /* 6 */
+		*structlen = sizeof(struct gfs2_leaf);
+		break;
+	case GFS2_METATYPE_JD:
+		*structlen = sizeof(struct gfs2_meta_header);
+		break;
+	case GFS2_METATYPE_LH:
+		*structlen = sizeof(struct gfs2_log_header);
+		break;
+	case GFS2_METATYPE_LD:
+		if (sbd.gfs1)
+			*structlen = sizeof(struct gfs_log_descriptor);
+		else
+			*structlen = sizeof(struct gfs2_log_descriptor);
+		break;
+	case GFS2_METATYPE_EA:
+		*structlen = sizeof(struct gfs2_meta_header) +
+			sizeof(struct gfs2_ea_header);
+		break;
+	case GFS2_METATYPE_ED:
+		*structlen = sizeof(struct gfs2_meta_header) +
+			sizeof(struct gfs2_ea_header);
+		break;
+	case GFS2_METATYPE_LB:
+		*structlen = sizeof(struct gfs2_meta_header);
+		break;
+	case GFS2_METATYPE_QC:
+		*structlen = sizeof(struct gfs2_quota_change);
+		break;
+	default:
+		*structlen = sbd.bsize;
+		break;
+	}
+	return ty;
 }
 
 /* ------------------------------------------------------------------------ */
@@ -624,78 +681,52 @@ int display_block_type(int from_restore)
 		struct_len = sbd.gfs1 ? sizeof(struct gfs_rgrp) :
 			sizeof(struct gfs2_rgrp);
 	} else {
-		ret_type = get_block_type(bh);
+		ret_type = get_block_type(bh, &struct_len);
 		switch (ret_type) {
 		case GFS2_METATYPE_SB:   /* 1 */
 			print_gfs2("(superblock)");
-			if (sbd.gfs1)
-				struct_len = sizeof(struct gfs_sb);
-			else
-				struct_len = sizeof(struct gfs2_sb);
 			break;
 		case GFS2_METATYPE_RG:   /* 2 */
 			print_gfs2("(rsrc grp hdr)");
-			struct_len = sizeof(struct gfs2_rgrp);
 			break;
 		case GFS2_METATYPE_RB:   /* 3 */
 			print_gfs2("(rsrc grp bitblk)");
-			struct_len = sizeof(struct gfs2_meta_header);
 			break;
 		case GFS2_METATYPE_DI:   /* 4 */
 			print_gfs2("(disk inode)");
-			struct_len = sizeof(struct gfs2_dinode);
 			break;
 		case GFS2_METATYPE_IN:   /* 5 */
 			print_gfs2("(indir blklist)");
-			if (sbd.gfs1)
-				struct_len = sizeof(struct gfs_indirect);
-			else
-				struct_len = sizeof(struct gfs2_meta_header);
 			break;
 		case GFS2_METATYPE_LF:   /* 6 */
 			print_gfs2("(directory leaf)");
-			struct_len = sizeof(struct gfs2_leaf);
 			break;
 		case GFS2_METATYPE_JD:
 			print_gfs2("(journal data)");
-			struct_len = sizeof(struct gfs2_meta_header);
 			break;
 		case GFS2_METATYPE_LH:
 			print_gfs2("(log header)");
-			struct_len = sizeof(struct gfs2_log_header);
 			break;
 		case GFS2_METATYPE_LD:
 		 	print_gfs2("(log descriptor)");
-			if (sbd.gfs1)
-				struct_len = sizeof(struct gfs_log_descriptor);
-			else
-				struct_len =
-					sizeof(struct gfs2_log_descriptor);
 			break;
 		case GFS2_METATYPE_EA:
 			print_gfs2("(extended attr hdr)");
-			struct_len = sizeof(struct gfs2_meta_header) +
-				sizeof(struct gfs2_ea_header);
 			break;
 		case GFS2_METATYPE_ED:
 			print_gfs2("(extended attr data)");
-			struct_len = sizeof(struct gfs2_meta_header) +
-				sizeof(struct gfs2_ea_header);
 			break;
 		case GFS2_METATYPE_LB:
 			print_gfs2("(log buffer)");
-			struct_len = sizeof(struct gfs2_meta_header);
 			break;
 		case GFS2_METATYPE_QC:
 			print_gfs2("(quota change)");
-			struct_len = sizeof(struct gfs2_quota_change);
 			break;
 		case 0:
 			struct_len = sbd.bsize;
 			break;
 		default:
 			print_gfs2("(wtf?)");
-			struct_len = sbd.bsize;
 			break;
 		}
 	}
@@ -848,18 +879,26 @@ static const struct lgfs2_metadata *find_mtype(uint32_t mtype, const unsigned ve
 /* ------------------------------------------------------------------------ */
 /* hexdump - hex dump the filesystem block to the screen                    */
 /* ------------------------------------------------------------------------ */
-static int hexdump(uint64_t startaddr, int len)
+static int hexdump(uint64_t startaddr, int len, int trunc_zeros,
+		   uint64_t flagref)
 {
-	const unsigned char *pointer,*ptr2;
+	const unsigned char *pointer, *ptr2;
 	int i;
 	uint64_t l;
 	const char *lpBuffer = bh->b_data;
+	const char *zeros_strt = lpBuffer + sbd.bsize;
 	int print_field, cursor_line;
-	const uint32_t block_type = get_block_type(bh);
+	const uint32_t block_type = get_block_type(bh, NULL);
+	uint64_t *ref;
 
 	strcpy(edit_fmt,"%02x");
 	pointer = (unsigned char *)lpBuffer + offset;
 	ptr2 = (unsigned char *)lpBuffer + offset;
+	ref = (uint64_t *)lpBuffer + offset;
+	if (trunc_zeros) {
+		while (zeros_strt > lpBuffer && (*(zeros_strt - 1) == 0))
+			zeros_strt--;
+	}
 	l = offset;
 	print_entry_ndx = 0;
 	while (((termlines && line < termlines &&
@@ -990,9 +1029,20 @@ static int hexdump(uint64_t startaddr, int len)
 		}
 		if (line - 3 > last_entry_onscreen[dmode])
 			last_entry_onscreen[dmode] = line - 3;
+		if (flagref && be64_to_cpu(*ref) == flagref)
+			print_gfs2("<------------------------- ref to 0x%llx",
+				   flagref);
+		ref++;
+		if (flagref && be64_to_cpu(*ref) == flagref)
+			print_gfs2("<------------------------- ref to 0x%llx",
+				   flagref);
+		ref++;
 		eol(0);
-		l+=16;
+		l += 16;
 		print_entry_ndx++;
+		/* This should only happen if trunc_zeros is specified: */
+		if ((const char *)pointer >= zeros_strt)
+			break;
 	} /* while */
 	if (sbd.gfs1) {
 		COLORS_NORMAL;
@@ -1343,7 +1393,7 @@ static void read_master_dir(void)
 /* ------------------------------------------------------------------------ */
 /* display                                                                  */
 /* ------------------------------------------------------------------------ */
-int display(int identify_only)
+int display(int identify_only, int trunc_zeros, uint64_t flagref)
 {
 	uint64_t blk;
 
@@ -1432,7 +1482,8 @@ int display(int identify_only)
 	}
 	if (dmode == HEX_MODE)          /* if hex display mode           */
 		hexdump(dev_offset, (gfs2_struct_type == GFS2_METATYPE_DI)?
-			struct_len + di.di_size:sbd.bsize);
+			struct_len + di.di_size:sbd.bsize, trunc_zeros,
+			flagref);
 	else if (dmode == GFS2_MODE)    /* if structure display          */
 		display_gfs2();            /* display the gfs2 structure    */
 	else
@@ -1952,7 +2003,7 @@ static void find_print_block_type(void)
 
 	tblock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
 	lbh = bread(&sbd, tblock);
-	type = get_block_type(lbh);
+	type = get_block_type(lbh, NULL);
 	print_block_type(tblock, type, "");
 	brelse(lbh);
 	gfs2_rgrp_free(&sbd.rgtree);
@@ -2086,7 +2137,7 @@ static void process_field(const char *field, const char *nstr)
 		setstring = 1;
 	fblock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
 	rbh = bread(&sbd, fblock);
-	type = get_block_type(rbh);
+	type = get_block_type(rbh, NULL);
 	switch (type) {
 	case GFS2_METATYPE_SB:
 		gfs2_sb_in(&lsb, rbh);
@@ -2233,7 +2284,7 @@ static void interactive_mode(void)
 	Quit = FALSE;
 	editing = FALSE;
 	while (!Quit) {
-		display(FALSE);
+		display(FALSE, 0, 0);
 		if (editing) {
 			if (edit_row[dmode] == -1)
 				block = goto_block();
@@ -2701,9 +2752,16 @@ static void process_parameters(int argc, char *argv[], int pass)
 		if (termlines || strchr(argv[i],'/')) /* if print or slash */
 			continue;
 			
-		if (!strncmp(argv[i], "journal", 7) &&
-		    isdigit(argv[i][7])) {
-			dump_journal(argv[i]);
+		if (!strncmp(argv[i], "journal", 7) && isdigit(argv[i][7])) {
+			int blk = 0;
+
+			if (i < argc - 1 && isdigit(argv[i + 1][0])) {
+				if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
+					sscanf(argv[i + 1], "%x", &blk);
+				else
+					blk = atoi(argv[i + 1]);
+			}
+			dump_journal(argv[i], blk);
 			continue;
 		}
 		keyword_blk = check_keywords(argv[i]);
@@ -2907,7 +2965,7 @@ int main(int argc, char *argv[])
 			block = blockstack[i + 1].block;
 			if (!block)
 				break;
-			display(identify);
+			display(identify, 0, 0);
 			if (!identify) {
 				display_extended();
 				printf("-------------------------------------" \
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index 8117f15..fc0f2cb 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -67,6 +67,7 @@ extern int dsplines;
 extern int dsp_lines[DMODES];
 extern int combined_display;
 extern int details;
+extern const char *allocdesc[2][5];
 
 struct gfs2_dirents {
 	uint64_t block;
@@ -224,11 +225,12 @@ extern void gfs_dinode_in(struct gfs_dinode *di, struct gfs2_buffer_head *bh);
 extern void savemeta(char *out_fn, int saveoption, int gziplevel);
 extern void restoremeta(const char *in_fn, const char *out_device,
 			uint64_t printblocksonly);
-extern int display(int identify_only);
+extern int display(int identify_only, int trunc_zeros, uint64_t flagref);
 extern uint64_t check_keywords(const char *kword);
 extern uint64_t masterblock(const char *fn);
 extern void gfs_rgrp_print(struct gfs_rgrp *rg);
 extern int has_indirect_blocks(void);
-extern uint32_t get_block_type(const struct gfs2_buffer_head *lbh);
+extern uint32_t get_block_type(const struct gfs2_buffer_head *lbh,
+			       int *structlen);
 
 #endif /* __HEXVIEW_DOT_H__ */
diff --git a/gfs2/edit/journal.c b/gfs2/edit/journal.c
index 2f32f34..5ad7cf8 100644
--- a/gfs2/edit/journal.c
+++ b/gfs2/edit/journal.c
@@ -28,10 +28,10 @@
 #include "gfs2hex.h"
 #include "journal.h"
 
-/* ------------------------------------------------------------------------ */
-/* find_journal_block - figure out where a journal starts, given the name   */
-/* Returns: journal block number, changes j_size to the journal size        */
-/* ------------------------------------------------------------------------ */
+/**
+ * find_journal_block - figure out where a journal starts, given the name
+ * Returns: journal block number, changes j_size to the journal size
+ */
 uint64_t find_journal_block(const char *journal, uint64_t *j_size)
 {
 	int journal_num;
@@ -108,10 +108,10 @@ static int is_meta(struct gfs2_buffer_head *lbh)
 	return 0;
 }
 
-/* ------------------------------------------------------------------------ */
-/* fsck_readi - same as libgfs2's gfs2_readi, but sets absolute block #     */
-/*              of the first bit of data read.                              */
-/* ------------------------------------------------------------------------ */
+/**
+ * fsck_readi - same as libgfs2's gfs2_readi, but sets absolute block #
+ *              of the first bit of data read.
+ */
 static int fsck_readi(struct gfs2_inode *ip, void *rbuf, uint64_t roffset,
 	       unsigned int size, uint64_t *abs_block)
 {
@@ -173,60 +173,290 @@ static int fsck_readi(struct gfs2_inode *ip, void *rbuf, uint64_t roffset,
 	return copied;
 }
 
-/* ------------------------------------------------------------------------ */
-/* print_ld_blocks - print all blocks given in a log descriptor             */
-/* returns: the number of block numbers it printed                          */
-/* ------------------------------------------------------------------------ */
-static int print_ld_blocks(const uint64_t *b, const char *end, int start_line)
+/**
+ * ld_is_pertinent - determine if a log descriptor is pertinent
+ *
+ * This function checks a log descriptor buffer to see if it contains
+ * references to a given traced block, or its rgrp bitmap block.
+ */
+static int ld_is_pertinent(const uint64_t *b, const char *end, uint64_t tblk,
+			   struct rgrp_tree *rgd, uint64_t bitblk)
 {
-	int bcount = 0, i = 0;
+	const uint64_t *blk = b;
+
+	if (!tblk)
+		return 1;
+
+	while (*blk && (char *)blk < end) {
+		if (be64_to_cpu(*blk) == tblk || be64_to_cpu(*blk) == bitblk)
+			return 1;
+		blk++;
+		if (sbd.gfs1)
+			blk++;
+	}
+	return 0;
+}
+
+/**
+ * print_ld_blks - print all blocks given in a log descriptor
+ * returns: the number of block numbers it printed
+ */
+static int print_ld_blks(const uint64_t *b, const char *end, int start_line,
+			 uint64_t tblk, uint64_t *tblk_off, uint64_t bitblk,
+			 struct rgrp_tree *rgd, uint64_t abs_block, int prnt,
+			 uint64_t *bblk_off, int is_meta_ld)
+{
+	int bcount = 0, found_tblk = 0, found_bblk = 0;
 	static char str[256];
 
+	if (tblk_off)
+		*tblk_off = 0;
+	if (bblk_off)
+		*bblk_off = 0;
 	while (*b && (char *)b < end) {
 		if (!termlines ||
 		    (print_entry_ndx >= start_row[dmode] &&
 		     ((print_entry_ndx - start_row[dmode])+1) *
 		     lines_per_row[dmode] <= termlines - start_line - 2)) {
-			if (i && i % 4 == 0) {
+			if (prnt && bcount && bcount % 4 == 0) {
 				eol(0);
 				print_gfs2("                    ");
 			}
-			i++;
-			sprintf(str, "0x%llx",
-				(unsigned long long)be64_to_cpu(*b));
-			print_gfs2("%-18.18s ", str);
 			bcount++;
+			if (prnt) {
+				sprintf(str, "0x%llx",
+					(unsigned long long)be64_to_cpu(*b));
+				print_gfs2("%-18.18s ", str);
+			}
+			if (!found_tblk && tblk_off)
+				(*tblk_off)++;
+			if (!found_bblk && bblk_off)
+				(*bblk_off)++;
+			if (tblk && (be64_to_cpu(*b) == tblk)) {
+				found_tblk = 1;
+				print_gfs2("<-------------------------0x%llx ",
+					   (unsigned long long)tblk);
+				eol(18 * (bcount % 4) + 1);
+				print_gfs2("                    ");
+			}
+			if (tblk && rgd && (be64_to_cpu(*b) == bitblk)) {
+				int type, bmap = 0;
+				uint64_t o;
+				struct gfs2_buffer_head *save_bh;
+				struct gfs2_buffer_head *j_bmap_bh;
+
+				found_bblk = 1;
+				print_gfs2("<-------------------------");
+				if (is_meta_ld) {
+					o = tblk - rgd->ri.ri_data0;
+					if (o >= (rgd->bits->bi_start +
+						  rgd->bits->bi_len) *
+					    GFS2_NBBY)
+						o += (sizeof(struct gfs2_rgrp) -
+						      sizeof(struct gfs2_meta_header))
+							* GFS2_NBBY;
+					bmap = o / sbd.sd_blocks_per_bitmap;
+					save_bh = rgd->bh[bmap];
+					j_bmap_bh = bread(&sbd, abs_block +
+							  bcount);
+					rgd->bh[bmap] = j_bmap_bh;
+					type = lgfs2_get_bitmap(&sbd, tblk,
+								rgd);
+					brelse(j_bmap_bh);
+					rgd->bh[bmap] = save_bh;
+					print_gfs2("bit for blk 0x%llx is %d "
+						   "(%s)",
+						   (unsigned long long)tblk,
+						   type,
+						   allocdesc[sbd.gfs1][type]);
+				} else {
+					print_gfs2("bitmap for blk 0x%llx "
+						   "was revoked",
+						   (unsigned long long)tblk);
+				}
+				eol(18 * (bcount % 4) + 1);
+				print_gfs2("                    ");
+			}
 		}
 		b++;
 		if (sbd.gfs1)
 			b++;
 	}
-	eol(0);
+	if (prnt)
+		eol(0);
+	if (!found_tblk || !is_meta_ld)
+		*tblk_off = 0;
+	if (!found_bblk || !is_meta_ld)
+		*bblk_off = 0;
 	return bcount;
 }
 
-/* ------------------------------------------------------------------------ */
-/* dump_journal - dump a journal file's contents.                           */
-/* ------------------------------------------------------------------------ */
-void dump_journal(const char *journal)
+/**
+ * find_wrap_pt - figure out where a journal wraps
+ * Returns: The wrap point, in bytes
+ */
+static uint64_t find_wrap_pt(struct gfs2_inode *j_inode, char *jbuf,
+			     uint64_t jblock, uint64_t j_size)
 {
 	struct gfs2_buffer_head *j_bh = NULL, dummy_bh;
-	uint64_t jblock, j_size, jb, abs_block, saveblk;
+	uint64_t jb, abs_block;
+	int error;
+	uint64_t highest_seq = 0;
+
+	for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1 : sbd.bsize)) {
+		if (sbd.gfs1) {
+			if (j_bh)
+				brelse(j_bh);
+			j_bh = bread(&sbd, jblock + jb);
+			abs_block = jblock + jb;
+			dummy_bh.b_data = j_bh->b_data;
+		} else {
+			error = fsck_readi(j_inode, (void *)jbuf, jb,
+					   sbd.bsize, &abs_block);
+			if (!error) /* end of file */
+				break;
+			dummy_bh.b_data = jbuf;
+		}
+		if (get_block_type(&dummy_bh, NULL) == GFS2_METATYPE_LH) {
+			struct gfs2_log_header lh;
+			struct gfs_log_header lh1;
+
+			if (sbd.gfs1) {
+				gfs_log_header_in(&lh1, &dummy_bh);
+				if (lh1.lh_sequence < highest_seq)
+					return jb;
+				highest_seq = lh1.lh_sequence;
+			} else {
+				gfs2_log_header_in(&lh, &dummy_bh);
+				if (lh.lh_sequence < highest_seq)
+					return jb;
+				highest_seq = lh.lh_sequence;
+			}
+		}
+		if (j_bh)
+			brelse(j_bh);
+	}
+	return 0;
+}
+
+/**
+ * process_ld - process a log descriptor
+ */
+static int process_ld(uint64_t abs_block, uint64_t wrappt, uint64_t j_size,
+		      uint64_t jb, struct gfs2_buffer_head *dummy_bh, int tblk,
+		      uint64_t *tblk_off, uint64_t bitblk,
+		      struct rgrp_tree *rgd, int *prnt, uint64_t *bblk_off)
+{
+	uint64_t *b;
+	struct gfs2_log_descriptor ld;
+	int ltndx, is_meta_ld = 0;
+	int ld_blocks = 0;
+	uint32_t logtypes[2][6] = {
+		{GFS2_LOG_DESC_METADATA, GFS2_LOG_DESC_REVOKE,
+		 GFS2_LOG_DESC_JDATA, 0, 0, 0},
+		{GFS_LOG_DESC_METADATA, GFS_LOG_DESC_IUL, GFS_LOG_DESC_IDA,
+		 GFS_LOG_DESC_Q, GFS_LOG_DESC_LAST, 0}};
+	const char *logtypestr[2][6] = {
+		{"Metadata", "Revoke", "Jdata",
+		 "Unknown", "Unknown", "Unknown"},
+		{"Metadata", "Unlinked inode", "Dealloc inode",
+		 "Quota", "Final Entry", "Unknown"}};
+
+	gfs2_log_descriptor_in(&ld, dummy_bh);
+	if (sbd.gfs1)
+		b = (uint64_t *)(dummy_bh->b_data +
+				 sizeof(struct gfs_log_descriptor));
+	else
+		b = (uint64_t *)(dummy_bh->b_data +
+				 sizeof(struct gfs2_log_descriptor));
+	*prnt = ld_is_pertinent(b, (dummy_bh->b_data + sbd.bsize), tblk, rgd,
+			       bitblk);
+
+	if (*prnt) {
+		print_gfs2("0x%llx (j+%4llx): Log descriptor, ",
+			   abs_block, ((jb + wrappt) % j_size) / sbd.bsize);
+		print_gfs2("type %d ", ld.ld_type);
+
+		for (ltndx = 0;; ltndx++) {
+			if (ld.ld_type == logtypes[sbd.gfs1][ltndx] ||
+			    logtypes[sbd.gfs1][ltndx] == 0)
+				break;
+		}
+		print_gfs2("(%s) ", logtypestr[sbd.gfs1][ltndx]);
+		print_gfs2("len:%u, data1: %u", ld.ld_length, ld.ld_data1);
+		eol(0);
+		print_gfs2("                    ");
+	}
+	ld_blocks = ld.ld_data1;
+	if (ld.ld_type == GFS2_LOG_DESC_METADATA ||
+	    ld.ld_type == GFS_LOG_DESC_METADATA)
+		is_meta_ld = 1;
+	ld_blocks -= print_ld_blks(b, (dummy_bh->b_data + sbd.bsize), line,
+				   tblk, tblk_off, bitblk, rgd, abs_block,
+				   *prnt, bblk_off, is_meta_ld);
+
+	return ld_blocks;
+}
+
+/**
+ * meta_has_ref - check if a metadata block references a given block
+ */
+static int meta_has_ref(uint64_t abs_block, int tblk)
+{
+	struct gfs2_buffer_head *mbh;
+	int structlen, ty, has_ref = 0;
+	uint64_t *b;
+
+	mbh = bread(&sbd, abs_block);
+	ty = get_block_type(mbh, &structlen);
+	b = (uint64_t *)(mbh->b_data + structlen);
+	while (ty && (char *)b < mbh->b_data + sbd.bsize) {
+		if (be64_to_cpu(*b) == tblk) {
+			has_ref = 1;
+			break;
+		}
+		b++;
+	}
+	brelse(mbh);
+	return has_ref;
+}
+
+/**
+ * dump_journal - dump a journal file's contents.
+ * @journal: name of the journal to dump
+ * @tblk: block number to trace in the journals
+ *
+ * This function dumps the contents of a journal. If a trace block is specified
+ * then only information printed is: (1) log descriptors that reference that
+ * block, (2) metadata in the journal that references the block, or (3)
+ * rgrp bitmaps that reference that block's allocation bit status.
+ */
+void dump_journal(const char *journal, int tblk)
+{
+	struct gfs2_buffer_head *j_bh = NULL, dummy_bh;
+	uint64_t jblock, j_size, jb, abs_block, saveblk, wrappt = 0;
 	int error, start_line, journal_num;
 	struct gfs2_inode *j_inode = NULL;
-	int ld_blocks = 0;
+	int ld_blocks = 0, offset_from_ld = 0;
+	uint64_t tblk_off = 0, bblk_off = 0, bitblk = 0;
 	uint64_t highest_seq = 0;
 	char *jbuf = NULL;
+	struct rgrp_tree *rgd = NULL;
 
 	start_line = line;
 	lines_per_row[dmode] = 1;
 	error = 0;
 	journal_num = atoi(journal + 7);
 	print_gfs2("Dumping journal #%d.", journal_num);
+	if (tblk) {
+		dmode = HEX_MODE;
+		print_gfs2(" Tracing block 0x%llx", (unsigned long long)tblk);
+	}
 	eol(0);
 	jblock = find_journal_block(journal, &j_size);
 	if (!jblock)
 		return;
+
 	if (!sbd.gfs1) {
 		j_bh = bread(&sbd, jblock);
 		j_inode = lgfs2_inode_get(&sbd, j_bh);
@@ -241,67 +471,68 @@ void dump_journal(const char *journal)
 		}
 	}
 
-	for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1:sbd.bsize)) {
+	if (tblk) {
+		uint64_t wp;
+
+		rgd = gfs2_blk2rgrpd(&sbd, tblk);
+		if (!rgd) {
+			print_gfs2("Can't locate the rgrp for block 0x%x",
+				   tblk);
+			eol(0);
+		} else {
+			uint64_t o;
+			int bmap = 0;
+
+			print_gfs2("rgd: 0x%llx for 0x%x, ", rgd->ri.ri_addr,
+				   rgd->ri.ri_length);
+			o = tblk - rgd->ri.ri_data0;
+			if (o >= (rgd->bits->bi_start +
+				  rgd->bits->bi_len) * GFS2_NBBY)
+				o += (sizeof(struct gfs2_rgrp) -
+				      sizeof(struct gfs2_meta_header))
+					* GFS2_NBBY;
+			bmap = o / sbd.sd_blocks_per_bitmap;
+			bitblk = rgd->ri.ri_addr + bmap;
+			print_gfs2("bitmap: %d, bitblk: 0x%llx", bmap,
+				   (unsigned long long)bitblk);
+			eol(0);
+		}
+
+		wrappt = find_wrap_pt(j_inode, jbuf, jblock, j_size);
+		wp = wrappt / (sbd.gfs1 ? 1 : sbd.bsize);
+		print_gfs2("Starting at journal wrap block: 0x%llx "
+			   "(j + 0x%llx)",
+			   (unsigned long long)jblock + wp,
+			   (unsigned long long)wp);
+		eol(0);
+	}
+
+	for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1 : sbd.bsize)) {
+		int is_pertinent = 1;
+
 		if (sbd.gfs1) {
 			if (j_bh)
 				brelse(j_bh);
-			j_bh = bread(&sbd, jblock + jb);
-			abs_block = jblock + jb;
+			abs_block = jblock + ((jb + wrappt) % j_size);
+			j_bh = bread(&sbd, abs_block);
 			dummy_bh.b_data = j_bh->b_data;
 		} else {
-			error = fsck_readi(j_inode, (void *)jbuf, jb,
+			error = fsck_readi(j_inode, (void *)jbuf,
+					   ((jb + wrappt) % j_size),
 					   sbd.bsize, &abs_block);
 			if (!error) /* end of file */
 				break;
 			dummy_bh.b_data = jbuf;
 		}
-		if (get_block_type(&dummy_bh) == GFS2_METATYPE_LD) {
-			uint64_t *b;
-			struct gfs2_log_descriptor ld;
-			int ltndx;
-			uint32_t logtypes[2][6] = {
-				{GFS2_LOG_DESC_METADATA,
-				 GFS2_LOG_DESC_REVOKE,
-				 GFS2_LOG_DESC_JDATA,
-				 0, 0, 0},
-				{GFS_LOG_DESC_METADATA,
-				 GFS_LOG_DESC_IUL,
-				 GFS_LOG_DESC_IDA,
-				 GFS_LOG_DESC_Q,
-				 GFS_LOG_DESC_LAST,
-				 0}};
-			const char *logtypestr[2][6] = {
-				{"Metadata", "Revoke", "Jdata",
-				 "Unknown", "Unknown", "Unknown"},
-				{"Metadata", "Unlinked inode", "Dealloc inode",
-				 "Quota", "Final Entry", "Unknown"}};
-
-			print_gfs2("0x%llx (j+%4llx): Log descriptor, ",
-				   abs_block, jb / (sbd.gfs1 ? 1 : sbd.bsize));
-			gfs2_log_descriptor_in(&ld, &dummy_bh);
-			print_gfs2("type %d ", ld.ld_type);
-
-			for (ltndx = 0;; ltndx++) {
-				if (ld.ld_type == logtypes[sbd.gfs1][ltndx] ||
-				    logtypes[sbd.gfs1][ltndx] == 0)
-					break;
-			}
-			print_gfs2("(%s) ", logtypestr[sbd.gfs1][ltndx]);
-			print_gfs2("len:%u, data1: %u",
-				   ld.ld_length, ld.ld_data1);
-			eol(0);
-			print_gfs2("                    ");
-			if (sbd.gfs1)
-				b = (uint64_t *)(dummy_bh.b_data +
-					sizeof(struct gfs_log_descriptor));
-			else
-				b = (uint64_t *)(dummy_bh.b_data +
-					sizeof(struct gfs2_log_descriptor));
-			ld_blocks = ld.ld_data1;
-			ld_blocks -= print_ld_blocks(b, (dummy_bh.b_data +
-							 sbd.bsize),
-						     start_line);
-		} else if (get_block_type(&dummy_bh) == GFS2_METATYPE_LH) {
+		offset_from_ld++;
+		if (get_block_type(&dummy_bh, NULL) == GFS2_METATYPE_LD) {
+			ld_blocks = process_ld(abs_block, wrappt, j_size, jb,
+					       &dummy_bh, tblk, &tblk_off,
+					       bitblk, rgd, &is_pertinent,
+					       &bblk_off);
+			offset_from_ld = 0;
+		} else if (!tblk &&
+			   get_block_type(&dummy_bh, NULL) == GFS2_METATYPE_LH) {
 			struct gfs2_log_header lh;
 			struct gfs_log_header lh1;
 
@@ -310,10 +541,10 @@ void dump_journal(const char *journal)
 				check_journal_wrap(lh1.lh_sequence,
 						   &highest_seq);
 				print_gfs2("0x%llx (j+%4llx): Log header: "
-					   "Flags:%x, Seq: 0x%x, "
-					   "1st: 0x%x, tail: 0x%x, "
-					   "last: 0x%x", abs_block,
-					   jb, lh1.lh_flags, lh1.lh_sequence,
+					   "Flags:%x, Seq: 0x%x, 1st: 0x%x, "
+					   "tail: 0x%x, last: 0x%x",
+					   abs_block, jb + wrappt,
+					   lh1.lh_flags, lh1.lh_sequence,
 					   lh1.lh_first, lh1.lh_tail,
 					   lh1.lh_last_dump);
 			} else {
@@ -322,8 +553,8 @@ void dump_journal(const char *journal)
 						   &highest_seq);
 				print_gfs2("0x%llx (j+%4llx): Log header: Seq"
 					   ": 0x%x, tail: 0x%x, blk: 0x%x",
-					   abs_block,
-					   jb / sbd.bsize, lh.lh_sequence,
+					   abs_block, ((jb + wrappt) % j_size)
+					   / sbd.bsize, lh.lh_sequence,
 					   lh.lh_tail, lh.lh_blkno);
 			}
 			eol(0);
@@ -332,13 +563,24 @@ void dump_journal(const char *journal)
 				   " continuation block", abs_block, jb);
 			eol(0);
 			print_gfs2("                    ");
-			ld_blocks -= print_ld_blocks((uint64_t *)dummy_bh.b_data,
-						     (dummy_bh.b_data +
-						      sbd.bsize), start_line);
-		} else if (details && is_meta(&dummy_bh)) {
+			ld_blocks -= print_ld_blks((uint64_t *)dummy_bh.b_data,
+						   (dummy_bh.b_data +
+						    sbd.bsize), start_line,
+						   tblk, &tblk_off, 0, rgd,
+						   0, 1, NULL, 1);
+		} else if (!is_meta(&dummy_bh)) {
+			continue;
+		}
+		/* Check if this metadata block references the block we're
+		   trying to trace. */
+		if (details ||
+		    (is_pertinent && tblk &&
+		     ((tblk_off && offset_from_ld == tblk_off) ||
+		      (bblk_off && offset_from_ld == bblk_off))) ||
+		    meta_has_ref(abs_block, tblk)) {
 			saveblk = block;
 			block = abs_block;
-			display(0);
+			display(0, tblk ? 1 : 0, tblk);
 			block = saveblk;
 		}
 	}
@@ -346,5 +588,7 @@ void dump_journal(const char *journal)
 	brelse(j_bh);
 	blockhist = -1; /* So we don't print anything else */
 	free(jbuf);
+	if (!termlines)
+		fflush(stdout);
 }
 
diff --git a/gfs2/edit/journal.h b/gfs2/edit/journal.h
index e227a77..1e5968b 100644
--- a/gfs2/edit/journal.h
+++ b/gfs2/edit/journal.h
@@ -1,8 +1,7 @@
 #ifndef __JOURNAL_DOT_H__
 #define __JOURNAL_DOT_H__
 
-extern void dump_journal(const char *journal);
+extern void dump_journal(const char *journal, int tblk);
 extern uint64_t find_journal_block(const char *journal, uint64_t *j_size);
 
-
 #endif
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index b4c85d6..b80ce10 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -929,7 +929,7 @@ static int restore_data(int fd, gzFile gzin_fd, int printblocksonly,
 			block = savedata->blk;
 			if (printblocksonly > 1 && printblocksonly == block) {
 				block_in_mem = block;
-				display(0);
+				display(0, 0, 0);
 				return 0;
 			} else if (printblocksonly == 1) {
 				print_gfs2("%d (l=0x%x): ", blks_saved,




More information about the Cluster-devel mailing list