[Cluster-devel] cluster/gfs2 edit/gfs2hex.c edit/hexedit.c edi ...

rpeterso at sourceware.org rpeterso at sourceware.org
Fri Nov 16 19:42:36 UTC 2007


CVSROOT:	/cvs/cluster
Module name:	cluster
Branch: 	RHEL5
Changes by:	rpeterso at sourceware.org	2007-11-16 19:42:35

Modified files:
	gfs2/edit      : gfs2hex.c hexedit.c hexedit.h savemeta.c 
	gfs2/libgfs2   : ondisk.c ondisk.h 

Log message:
	Resolves: bz 369771: GFS2: bring RHEL gfs2_edit up to date

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/gfs2hex.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.3&r2=1.5.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.6.2.3&r2=1.6.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4.2.5&r2=1.4.2.6
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/savemeta.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.1.2.2&r2=1.1.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/ondisk.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.3&r2=1.5.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/ondisk.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2&r2=1.2.2.1

--- cluster/gfs2/edit/gfs2hex.c	2007/06/26 01:40:43	1.5.2.3
+++ cluster/gfs2/edit/gfs2hex.c	2007/11/16 19:42:34	1.5.2.4
@@ -192,6 +192,7 @@
 		memcpy(&indir->dirent[d].dirent, &de, sizeof(struct gfs2_dirent));
 		memcpy(&indir->dirent[d].filename,
 			   ptr + sizeof(struct gfs2_dirent), de.de_name_len);
+		indir->dirent[d].filename[de.de_name_len] = '\0';
 		indir->dirent[d].block = de.de_inum.no_addr;
 		indir->is_dir = TRUE;
 		indir->dirents++;
@@ -222,7 +223,7 @@
 		(gfs1 && di->__pad1 == GFS_FILE_DIR);
 
 	indirect_blocks = 0;
-	memset(&indirect, 0, sizeof(indirect));
+	memset(indirect, 0, sizeof(indirect));
 	if (di->di_height > 0) {
 		/* Indirect pointers */
 		for (x = sizeof(struct gfs2_dinode), y = 0;
@@ -230,21 +231,23 @@
 			 x += sizeof(uint64_t), y++) {
 			p = be64_to_cpu(*(uint64_t *)(buf + x));
 			if (p) {
-				indirect[indirect_blocks].block = p;
-				indirect[indirect_blocks].is_dir = FALSE;
+				indirect->ii[indirect_blocks].block = p;
+				indirect->ii[indirect_blocks].is_dir = FALSE;
 				indirect_blocks++;
 			}
 		}
 	}
-	else if (isdir &&
-			 !(di->di_flags & GFS2_DIF_EXHASH)) {
+	else if (isdir && !(di->di_flags & GFS2_DIF_EXHASH)) {
 		int skip = 0;
+
 		/* Directory Entries: */
-		indirect[0].dirents = 0;
-		indirect[0].block = block;
-		indirect[0].is_dir = TRUE;
+		indirect->ii[0].dirents = 0;
+		indirect->ii[0].block = block;
+		indirect->ii[0].is_dir = TRUE;
 		for (x = sizeof(struct gfs2_dinode); x < bufsize; x += skip) {
-			skip = indirect_dirent(&indirect[0], buf + x, indirect[0].dirents);
+			skip = indirect_dirent(indirect->ii,
+					       buf + x,
+					       indirect->ii[0].dirents);
 			if (skip <= 0)
 				break;
 		}
@@ -267,20 +270,22 @@
 				struct gfs2_leaf leaf;
 				unsigned int bufoffset;
 
+				if (last >= max_block)
+					break;
 				tmp_bh = bread(&sbd, last);
 				gfs2_leaf_in(&leaf, tmp_bh->b_data);
-				indirect[indirect_blocks].dirents = 0;
+				indirect->ii[indirect_blocks].dirents = 0;
 				for (direntcount = 0, bufoffset = sizeof(struct gfs2_leaf);
 					 bufoffset < bufsize;
 					 direntcount++, bufoffset += skip) {
-					skip = indirect_dirent(&indirect[indirect_blocks],
+					skip = indirect_dirent(&indirect->ii[indirect_blocks],
 										   tmp_bh->b_data + bufoffset,
 										   direntcount);
 					if (skip <= 0)
 						break;
 				}
 				brelse(tmp_bh, not_updated);
-				indirect[indirect_blocks].block = last;
+				indirect->ii[indirect_blocks].block = last;
 				indirect_blocks++;
 				last = p;
 			} /* if not duplicate pointer */
@@ -303,24 +308,26 @@
 **
 *******************************************************************************
 ******************************************************************************/
-void do_indirect_extended(char *buf)
+int do_indirect_extended(char *buf, struct iinfo *iinf)
 {
 	unsigned int x, y;
 	uint64_t p;
+	int i_blocks;
 
-	indirect_blocks = 0;
-	memset(&indirect, 0, sizeof(indirect));
+	i_blocks = 0;
+	memset(iinf, 0, sizeof(struct iinfo));
 	for (x = (gfs1 ? sizeof(struct gfs_indirect):
 			  sizeof(struct gfs2_meta_header)), y = 0;
 		 x < bufsize;
 		 x += sizeof(uint64_t), y++) {
 		p = be64_to_cpu(*(uint64_t *)(buf + x));
 		if (p) {
-			indirect[indirect_blocks].block = p;
-			indirect[indirect_blocks].is_dir = FALSE;
-			indirect_blocks++;
+			iinf->ii[i_blocks].block = p;
+			iinf->ii[i_blocks].is_dir = FALSE;
+			i_blocks++;
 		}
 	}
+	return i_blocks;
 }
 
 /******************************************************************************
@@ -338,20 +345,32 @@
 **
 *******************************************************************************
 ******************************************************************************/
-void do_leaf_extended(char *buf)
+void do_leaf_extended(char *buf, struct iinfo *indir)
 {
+	int x, i;
 	struct gfs2_dirent de;
-	unsigned int x;
 
-	eol(0);
-	print_gfs2("Directory Entries:");
-	eol(0);
-
-	for (x = sizeof(struct gfs2_leaf); x < bufsize; x += de.de_rec_len) {
-		eol(0);
-		gfs2_dirent_in(&de, buf + x);
-		if (de.de_inum.no_addr)
-			gfs2_dirent_print(&de, buf + x + sizeof(struct gfs2_dirent));
+	x = 0;
+	memset(indir, 0, sizeof(indir));
+	/* Directory Entries: */
+	for (i = sizeof(struct gfs2_leaf); i < bufsize;
+	     i += de.de_rec_len) {
+		gfs2_dirent_in(&de, buf + i);
+		if (de.de_inum.no_addr) {
+			indir->ii[0].block = de.de_inum.no_addr;
+			indir->ii[0].dirent[x].block = de.de_inum.no_addr;
+			memcpy(&indir->ii[0].dirent[x].dirent,
+			       &de, sizeof(struct gfs2_dirent));
+			memcpy(&indir->ii[0].dirent[x].filename,
+			       buf + i + sizeof(struct gfs2_dirent),
+			       de.de_name_len);
+			indir->ii[0].dirent[x].filename[de.de_name_len] = '\0';
+			indir->ii[0].is_dir = TRUE;
+			indir->ii[0].dirents++;
+			x++;
+		}
+		if (de.de_rec_len <= sizeof(struct gfs2_dirent))
+			break;
 	}
 }
 
@@ -456,7 +475,10 @@
 	struct gfs2_meta_header mh;
 	struct gfs2_rgrp rg;
 	struct gfs2_leaf lf;
+	struct gfs_log_header lh1;
 	struct gfs2_log_header lh;
+	struct gfs2_log_descriptor ld;
+	struct gfs2_quota_change qc;
 
 	uint32_t magic;
 
@@ -517,14 +539,26 @@
 		case GFS2_METATYPE_LH:
 			print_gfs2("Log Header:");
 			eol(0);
-			gfs2_log_header_in(&lh, buf);
-			gfs2_log_header_print(&lh);
+			if (gfs1) {
+				gfs_log_header_in(&lh1, buf);
+				gfs_log_header_print(&lh1);
+			} else {
+				gfs2_log_header_in(&lh, buf);
+				gfs2_log_header_print(&lh);
+			}
 			break;
 			
+		case GFS2_METATYPE_LD:
+			print_gfs2("Log descriptor");
+			eol(0);
+			gfs2_log_descriptor_in(&ld, buf);
+			gfs2_log_descriptor_print(&ld);
+			break;
+
 		case GFS2_METATYPE_EA:
 			print_gfs2("Eattr Block:");
 			eol(0);
-			gfs2_meta_header_print(&mh);
+			do_eattr_extended(buf);
 			break;
 			
 		case GFS2_METATYPE_ED:
@@ -533,6 +567,19 @@
 			gfs2_meta_header_print(&mh);
 			break;
 			
+		case GFS2_METATYPE_LB:
+			print_gfs2("Log Buffer");
+			eol(0);
+			gfs2_meta_header_print(&mh);
+			break;
+
+		case GFS2_METATYPE_QC:
+			print_gfs2("Quota Change");
+			eol(0);
+			gfs2_quota_change_in(&qc, buf);
+			gfs2_quota_change_print(&qc);
+			break;
+
 		default:
 			print_gfs2("Unknown metadata type");
 			eol(0);
--- cluster/gfs2/edit/hexedit.c	2007/06/26 01:40:43	1.6.2.3
+++ cluster/gfs2/edit/hexedit.c	2007/11/16 19:42:34	1.6.2.4
@@ -46,9 +46,11 @@
 
 int display(int identify_only);
 extern void eol(int col);
-extern void do_indirect_extended(char *buf);
-extern void savemeta(const char *in_fn, const char *out_fn, int slow);
-extern void restoremeta(const char *in_fn, const char *out_device);
+extern void do_leaf_extended(char *buf, struct iinfo *indir);
+extern int do_indirect_extended(char *buf, struct iinfo *ii);
+extern void savemeta(const char *out_fn, int slow);
+extern void restoremeta(const char *in_fn, const char *out_device,
+			int printblocksonly);
 
 /* ------------------------------------------------------------------------ */
 /* UpdateSize - screen size changed, so update it                           */
@@ -326,12 +328,31 @@
 	Erase();
 }
 
+
+
+/* ------------------------------------------------------------------------ */
+/* get_block_type                                                           */
+/* returns: metatype if block is a GFS2 structure block type                */
+/*          0 if block is not a GFS2 structure                              */
+/* ------------------------------------------------------------------------ */
+int get_block_type(const char *lpBuffer)
+{
+	int ret_type = 0;
+
+	if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 &&
+	    *(lpBuffer+2)==0x19 && *(lpBuffer+3)==0x70 &&
+	    *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 &&
+	    *(lpBuffer+6)==0x00) /* If magic number appears at the start */
+		ret_type = *(lpBuffer+7);
+	return ret_type;
+}
+
 /* ------------------------------------------------------------------------ */
 /* display_block_type                                                       */
 /* returns: metatype if block is a GFS2 structure block type                */
 /*          0 if block is not a GFS2 structure                              */
 /* ------------------------------------------------------------------------ */
-int display_block_type(const char *lpBuffer)
+int display_block_type(const char *lpBuffer, int from_restore)
 {
 	int ret_type = 0; /* return type */
 
@@ -356,21 +377,19 @@
 	}
 	else
 		print_gfs2(" ");
-	print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block, max_block);
-	if (termlines)
-		move(line, 55);
-	else
-		printf(" ");
-
+	if (!from_restore) {
+		print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block,
+			   max_block);
+		if (termlines)
+			move(line, 55);
+		else
+			printf(" ");
+	}
 	if (block == RGLIST_DUMMY_BLOCK) {
 		ret_type = GFS2_METATYPE_RG;
 		struct_len = sizeof(struct gfs2_rgrp);
 	}
-	else if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 &&
-	    *(lpBuffer+2)==0x19 && *(lpBuffer+3)==0x70 &&
-	    *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 &&
-	    *(lpBuffer+6)==0x00) { /* If magic number appears at the start */
-		ret_type = *(lpBuffer+7);
+	else if ((ret_type = get_block_type(lpBuffer))) {
 		switch (*(lpBuffer+7)) {
 		case GFS2_METATYPE_SB:   /* 1 */
 			print_gfs2("(superblock)");
@@ -396,7 +415,7 @@
 			struct_len = sizeof(struct gfs2_meta_header);
 			break;
 		case GFS2_METATYPE_LF:   /* 6 */
-			print_gfs2("(leaf dinode blklst)");
+			print_gfs2("(directory leaf)");
 			struct_len = sizeof(struct gfs2_leaf);
 			break;
 		case GFS2_METATYPE_JD:
@@ -408,16 +427,30 @@
 			struct_len = sizeof(struct gfs2_log_header);
 			break;
 		case GFS2_METATYPE_LD:
-			print_gfs2("(log descriptor)");
-			struct_len = sizeof(struct gfs2_log_descriptor);
+		 	print_gfs2("(log descriptor)");
+			if (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_ea_header);
+			struct_len = sizeof(struct gfs2_meta_header) +
+				sizeof(struct gfs2_ea_header);
 			break;
 		case GFS2_METATYPE_ED:
 			print_gfs2("(extended attr data)");
-			struct_len = 512;
+			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;
 		default:
 			print_gfs2("(wtf?)");
@@ -428,6 +461,8 @@
 	else
 		struct_len = 512;
 	eol(0);
+	if (from_restore)
+		return ret_type;
 	if (termlines && dmode == HEX_MODE) {
 		/* calculate how much of the buffer we can fit on screen */
 		screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
@@ -583,6 +618,100 @@
 }
 
 /* ------------------------------------------------------------------------ */
+/* rgcount - return how many rgrps there are.                               */
+/* ------------------------------------------------------------------------ */
+void rgcount(void)
+{
+	uint64_t block;
+	struct gfs2_buffer_head *ribh;
+	struct gfs2_inode *riinode;
+
+	if (gfs1)
+		block = sbd1->sb_rindex_di.no_addr;
+	else
+		block = masterblock("rindex");
+	ribh = bread(&sbd, block);
+	riinode = inode_get(&sbd, ribh);
+	printf("%lld RGs in this file system.\n",
+	       riinode->i_di.di_size / sizeof(struct gfs2_rindex));
+	inode_put(riinode, not_updated);
+	exit(EXIT_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------ */
+/* find_rgrp_block - locate the block for a given rgrp number               */
+/* ------------------------------------------------------------------------ */
+uint64_t find_rgrp_block(struct gfs2_inode *di, int rg)
+{
+	char buf[sizeof(struct gfs2_rindex)];
+	int amt;
+	struct gfs2_rindex ri;
+
+	amt = gfs2_readi(di, (void *)&buf,
+			 rg * sizeof(struct gfs2_rindex),
+			 sizeof(struct gfs2_rindex));
+	if (!amt) /* end of file */
+		return 0;
+	gfs2_rindex_in(&ri, buf);
+	return ri.ri_addr;
+}
+
+/* ------------------------------------------------------------------------ */
+/* set_rgrp_flags - Set an rgrp's flags to a given value                    */
+/* rgnum: which rg to print or modify flags for (0 - X)                     */
+/* new_flags: value to set new rg_flags to (if modify == TRUE)              */
+/* modify: TRUE if the value is to be modified, FALSE if it's to be printed */
+/* full: TRUE if the full RG should be printed.                             */
+/* ------------------------------------------------------------------------ */
+void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full)
+{
+	struct gfs2_rgrp rg;
+	struct gfs2_buffer_head *bh, *ribh;
+	uint64_t rgblk, block;
+	struct gfs2_inode *riinode;
+
+	if (gfs1)
+		block = sbd1->sb_rindex_di.no_addr;
+	else
+		block = masterblock("rindex");
+	ribh = bread(&sbd, block);
+	riinode = inode_get(&sbd, ribh);
+	if (rgnum >= riinode->i_di.di_size / sizeof(struct gfs2_rindex)) {
+		fprintf(stderr, "Error: File system only has %lld RGs.\n",
+		       riinode->i_di.di_size / sizeof(struct gfs2_rindex));
+		inode_put(riinode, not_updated);
+		brelse(ribh, not_updated);
+		return;
+	}
+	rgblk = find_rgrp_block(riinode, rgnum);
+	bh = bread(&sbd, rgblk);
+	gfs2_rgrp_in(&rg, bh->b_data);
+	if (modify) {
+		printf("RG #%d (block %llu / 0x%llx) rg_flags changed from 0x%08x to 0x%08x\n",
+		       rgnum, (unsigned long long)rgblk,
+		       (unsigned long long)rgblk, rg.rg_flags, new_flags);
+		rg.rg_flags = new_flags;
+		gfs2_rgrp_out(&rg, bh->b_data);
+		brelse(bh, updated);
+	} else {
+		if (full) {
+			print_gfs2("RG #%d", rgnum);
+			print_gfs2(" located at: %llu (0x%llx)", rgblk, rgblk);
+                        eol(0);
+			gfs2_rgrp_print(&rg);
+		}
+		else
+			printf("RG #%d (block %llu / 0x%llx) rg_flags = 0x%08x\n",
+			       rgnum, (unsigned long long)rgblk,
+			       (unsigned long long)rgblk, rg.rg_flags);
+		brelse(bh, not_updated);
+	}
+	inode_put(riinode, not_updated);
+	if (modify)
+		bsync(&sbd);
+}
+
+/* ------------------------------------------------------------------------ */
 /* parse_rindex - print the rgindex file.                                   */
 /* ------------------------------------------------------------------------ */
 int parse_rindex(struct gfs2_inode *di, int print_rindex)
@@ -603,9 +732,9 @@
 		error = gfs2_readi(di, (void *)&buf,
 				   print_entry_ndx * sizeof(struct gfs2_rindex),
 				   sizeof(struct gfs2_rindex));
-		gfs2_rindex_in(&ri, buf);
 		if (!error) /* end of file */
 			break;
+		gfs2_rindex_in(&ri, buf);
 		if (!termlines ||
 			(print_entry_ndx >= start_row[dmode] &&
 			 ((print_entry_ndx - start_row[dmode])+1) * lines_per_row[dmode] <=
@@ -677,7 +806,7 @@
 	print_gfs2("Journal index entries found: %d.",
 		   di->i_di.di_size / sizeof(struct gfs_jindex));
 	eol(0);
-	lines_per_row[dmode] = 6;
+	lines_per_row[dmode] = 4;
 	for (print_entry_ndx=0; ; print_entry_ndx++) {
 		error = gfs2_readi(di, (void *)&buf,
 				   print_entry_ndx*sizeof(struct gfs_jindex),
@@ -777,8 +906,9 @@
 int has_indirect_blocks(void)
 {
 	if (indirect_blocks || gfs2_struct_type == GFS2_METATYPE_SB ||
-		(gfs2_struct_type == GFS2_METATYPE_DI &&
-		 (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR))))
+	    gfs2_struct_type == GFS2_METATYPE_LF ||
+	    (gfs2_struct_type == GFS2_METATYPE_DI &&
+	     (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR))))
 		return TRUE;
 	return FALSE;
 }
@@ -820,51 +950,100 @@
 }
 
 /* ------------------------------------------------------------------------ */
+/* display_leaf - display directory leaf                                    */
+/* ------------------------------------------------------------------------ */
+int display_leaf(struct iinfo *ind)
+{
+	int start_line, total_dirents = 0;
+	int d;
+
+	eol(0);
+	if (gfs2_struct_type == GFS2_METATYPE_SB)
+		print_gfs2("The superblock has 2 directories");
+	else
+		print_gfs2("This directory contains %d directory entries.",
+			   ind->ii[0].dirents);
+
+	start_line = line;
+	for (d = 0; d < ind->ii[0].dirents; d++) {
+		if (termlines && d >= termlines - start_line - 1
+		    + start_row[dmode])
+			break;
+		total_dirents++;
+		if (ind->ii[0].dirents > 1) {
+			eol(5);
+			if (termlines) {
+				if (edit_row[dmode] >=0 &&
+				    line - start_line - 1 == 
+				    edit_row[dmode] -
+				    start_row[dmode]) {
+					COLORS_HIGHLIGHT;
+					sprintf(estring, "%"PRIx64,
+						ind->ii[0].dirent[d].block);
+					strcpy(edit_fmt, "%"PRIx64);
+				}
+			}
+			print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ",
+				   total_dirents, d + 1,
+				   ind->ii[0].dirent[d].dirent.de_inum.no_formal_ino,
+				   ind->ii[0].dirent[d].dirent.de_inum.no_formal_ino,
+				   ind->ii[0].dirent[d].block,
+				   ind->ii[0].dirent[d].block);
+		}
+		print_inode_type(ind->ii[0].dirent[d].dirent.de_type);
+		print_gfs2(" %s", ind->ii[0].dirent[d].filename);
+		if (termlines) {
+			if (edit_row[dmode] >= 0 &&
+			    line - start_line - 1 == edit_row[dmode] -
+			    start_row[dmode])
+				COLORS_NORMAL;
+		}
+	}
+	if (line >= 4)
+		last_entry_onscreen[dmode] = line - 4;
+	eol(0);
+	end_row[dmode] = ind->ii[0].dirents;
+	if (end_row[dmode] < last_entry_onscreen[dmode])
+		end_row[dmode] = last_entry_onscreen[dmode];
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
 /* display_indirect                                                         */
 /* ------------------------------------------------------------------------ */
-int display_indirect(void)
+int display_indirect(struct iinfo *ind, int indblocks, int level, uint64_t startoff)
 {
-	int start_line, total_dirents, indir_blocks;
-	int i, cur_height = -1;
+	int start_line, total_dirents;
+	int i, cur_height = -1, pndx;
 	uint64_t factor[5]={0,0,0,0,0};
 	int offsets[5];
 
 	last_entry_onscreen[dmode] = 0;
-	eol(0);
-	start_line = line;
+	if (!level)
+		eol(0);
 	if (!has_indirect_blocks())
 		return -1;
-
-	indir_blocks = indirect_blocks;
-	if (!indirect_blocks) {
-		if (gfs2_struct_type == GFS2_METATYPE_SB)
-			print_gfs2("The superblock has 2 directories");
-		else
-			print_gfs2("This directory contains %d directory entries.",
-					   indirect[0].dirents);
-		indir_blocks = 1; /* not really an indirect block, but treat it as one */
-	}
-	else {
+	if (!level) {
 		if (gfs2_struct_type == GFS2_METATYPE_DI) {
 			if (S_ISDIR(di.di_mode))
 				print_gfs2("This directory contains %d indirect blocks",
-						   indirect_blocks);
+					   indblocks);
 			else
 				print_gfs2("This inode contains %d indirect blocks",
-						   indirect_blocks);
+					   indblocks);
 		}
 		else
 			print_gfs2("This indirect block contains %d indirect blocks",
-					   indirect_blocks);
+				   indblocks);
 	}
+	eol(0);
 	total_dirents = 0;
 	/* Figure out multiplication factors for indirect pointers. */
-	if ((indir_blocks == indirect_blocks) && !S_ISDIR(di.di_mode)) {
+	if (!S_ISDIR(di.di_mode)) {
 		memset(&offsets, 0, sizeof(offsets));
 		/* See if we are on an inode or have one in history. */
-		cur_height = 0;
-		if (gfs2_struct_type != GFS2_METATYPE_DI) {
-			cur_height = 0;
+		cur_height = level;
+		if (!level && gfs2_struct_type != GFS2_METATYPE_DI) {
 			for (i = 0; i <= blockhist && i < 5; i++) {
 				offsets[i] = blockstack[(blockhist - i) % BLOCK_STACK_SIZE].edit_row[dmode];
 				if (blockstack[(blockhist - i) % BLOCK_STACK_SIZE].gfs2_struct_type == GFS2_METATYPE_DI)
@@ -890,112 +1069,113 @@
 			for (i = 0; i < di.di_height; i++)
 				factor[i + 1] = factor[i] * inptrs;
 		}
-		print_gfs2("  (at height=%d)", cur_height);
-	}
-	if (indirect_blocks) {
+		if (!level)
+			print_gfs2("  (at height=%d)", cur_height);
 		eol(0);
+	}
+	if (!level && indblocks) {
 		print_gfs2("Indirect blocks:");
+		eol(0);
 	}
-	eol(0);
-	for (print_entry_ndx = start_row[dmode];
-		 (!termlines || print_entry_ndx < termlines - start_line - 2
-		  + start_row[dmode]) && print_entry_ndx < indir_blocks;
-		 print_entry_ndx++) {
+	start_line = line;
+	for (pndx = start_row[dmode];
+		 (!termlines || pndx < termlines - start_line - 1
+		  + start_row[dmode]) && pndx < indblocks;
+		 pndx++) {
+		uint64_t file_offset;
+
+		print_entry_ndx = pndx;
 		if (termlines) {
 			if (edit_row[dmode] >= 0 &&
-				line - start_line - 2 == edit_row[dmode] -
-				start_row[dmode])
+			    line - start_line ==
+			    edit_row[dmode] - start_row[dmode])
 				COLORS_HIGHLIGHT;
 			move(line, 1);
 		}
-		if (indir_blocks == indirect_blocks) {
-			print_gfs2("%d => ", print_entry_ndx);
-			if (termlines)
-				move(line,9);
-			print_gfs2("0x%llx / %lld", indirect[print_entry_ndx].block,
-					   indirect[print_entry_ndx].block);
-			if (termlines) {
-				if (edit_row[dmode] >= 0 &&
-					line - start_line - 2 == edit_row[dmode] -
-					start_row[dmode]) { 
-					sprintf(estring, "%"PRIx64,
-							indirect[print_entry_ndx].block);
-					strcpy(edit_fmt, "%"PRIx64);
-					edit_size[dmode] = strlen(estring);
-					COLORS_NORMAL;
-				}
-			}
-			if (!S_ISDIR(di.di_mode)) {
-				int hgt;
-				uint64_t file_offset = 0ull;
-				float human_off;
-				char h;
-				
-				/* Now divide by how deep we are at the moment.      */
-				/* This is how much data is represented by each      */
-				/* indirect pointer for each height we've traversed. */
-				offsets[0] = print_entry_ndx;
-				for (hgt = cur_height; hgt >= 0; hgt--)
-					file_offset += offsets[cur_height - hgt] *
-						factor[di.di_height - hgt - 1] * bufsize;
-				print_gfs2("     ");
-				h = 'K';
-				human_off = (file_offset / 1024.0);
-				if (human_off > 1024.0) { h = 'M'; human_off /= 1024.0; }
-				if (human_off > 1024.0) { h = 'G'; human_off /= 1024.0; }
-				if (human_off > 1024.0) { h = 'T'; human_off /= 1024.0; }
-				if (human_off > 1024.0) { h = 'P'; human_off /= 1024.0; }
-				if (human_off > 1024.0) { h = 'E'; human_off /= 1024.0; }
-				print_gfs2("(data offset 0x%llx / %lld / %6.2f%c)",
-						   file_offset, file_offset, human_off, h);
+		if (!termlines) {
+			int h;
+
+			for (h = 0; h < level; h++)
 				print_gfs2("   ");
+		}
+		print_gfs2("%d => ", pndx);
+		if (termlines)
+			move(line,9);
+		print_gfs2("0x%llx / %lld", ind->ii[pndx].block,
+			   ind->ii[pndx].block);
+		if (termlines) {
+			if (edit_row[dmode] >= 0 &&
+			    line - start_line ==
+			    edit_row[dmode] - start_row[dmode]) { 
+				sprintf(estring, "%"PRIx64,
+					ind->ii[print_entry_ndx].block);
+				strcpy(edit_fmt, "%"PRIx64);
+				edit_size[dmode] = strlen(estring);
+				COLORS_NORMAL;
 			}
 		}
-		if (indirect[print_entry_ndx].is_dir) {
-			int d;
+		if (!S_ISDIR(di.di_mode)) {
+			int hgt;
+			file_offset = startoff;
+			float human_off;
+			char h;
+
+			/* Now divide by how deep we are at the moment.      */
+			/* This is how much data is represented by each      */
+			/* indirect pointer for each height we've traversed. */
+			offsets[0] = pndx;
+			for (hgt = cur_height; hgt >= 0; hgt--)
+				file_offset += offsets[cur_height - hgt] *
+					factor[di.di_height - hgt - 1] * bufsize;
+			print_gfs2("     ");
+			h = 'K';
+			human_off = (file_offset / 1024.0);
+			if (human_off > 1024.0) { h = 'M'; human_off /= 1024.0; }
+			if (human_off > 1024.0) { h = 'G'; human_off /= 1024.0; }
+			if (human_off > 1024.0) { h = 'T'; human_off /= 1024.0; }
+			if (human_off > 1024.0) { h = 'P'; human_off /= 1024.0; }
+			if (human_off > 1024.0) { h = 'E'; human_off /= 1024.0; }
+			print_gfs2("(data offset 0x%llx / %lld / %6.2f%c)",
+				   file_offset, file_offset, human_off, h);
+			print_gfs2("   ");
+		}
+		else
+			file_offset = 0;
+		if (!termlines && ((level + 1 < di.di_height) ||
+				   (S_ISDIR(di.di_mode) && !level))) {
+			struct iinfo *more_indir;
+			int more_ind;
+			char *tmpbuf;
 			
-			if (indirect[print_entry_ndx].dirents > 1 &&
-				indir_blocks == indirect_blocks)
-				print_gfs2("(directory leaf with %d entries)",
-						   indirect[print_entry_ndx].dirents);
-			for (d = 0; d < indirect[print_entry_ndx].dirents; d++) {
-				total_dirents++;
-				if (indirect[print_entry_ndx].dirents > 1) {
-					eol(5);
-					if (termlines) {
-						if (edit_row[dmode] >=0 &&
-							line - start_line - 2 == 
-							edit_row[dmode] -
-							start_row[dmode]) {
-							COLORS_HIGHLIGHT;
-							sprintf(estring, "%"PRIx64,
-									indirect[print_entry_ndx].dirent[d].block);
-							strcpy(edit_fmt, "%"PRIx64);
-						}
-					}
-					print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ",
-							   total_dirents, d + 1,
-							   indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino,
-							   indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino,
-							   indirect[print_entry_ndx].dirent[d].block,
-							   indirect[print_entry_ndx].dirent[d].block);
-				}
-				print_inode_type(indirect[print_entry_ndx].dirent[d].dirent.de_type);
-				print_gfs2(" %s", indirect[print_entry_ndx].dirent[d].filename);
-				if (termlines) {
-					if (edit_row[dmode] >= 0 &&
-						line - start_line - 2 == edit_row[dmode] -
-						start_row[dmode])
-						COLORS_NORMAL;
+			more_indir = malloc(sizeof(struct iinfo));
+			tmpbuf = malloc(bufsize);
+			if (tmpbuf) {
+				do_lseek(sbd.device_fd,
+					 ind->ii[pndx].block * bufsize);
+				do_read(sbd.device_fd, tmpbuf,
+					bufsize); /* read in the desired block */
+				memset(more_indir, 0, sizeof(struct iinfo));
+				if (S_ISDIR(di.di_mode)) {
+					do_leaf_extended(tmpbuf, more_indir);
+					display_leaf(more_indir);
+				} else {
+					more_ind = do_indirect_extended(tmpbuf,
+									more_indir);
+					display_indirect(more_indir,
+							 more_ind, level + 1,
+							 file_offset);
 				}
+				free(tmpbuf);
 			}
-		} /* if isdir */
+			free(more_indir);
+		}
+		print_entry_ndx = pndx; /* restore after recursion */
 		eol(0);
 	} /* for each display row */
 	if (line >= 7) /* 7 because it was bumped at the end */
 		last_entry_onscreen[dmode] = line - 7;
 	eol(0);
-	end_row[dmode] = (indirect_blocks ? indirect_blocks:indirect[0].dirents);
+	end_row[dmode] = indblocks;
 	if (end_row[dmode] < last_entry_onscreen[dmode])
 		end_row[dmode] = last_entry_onscreen[dmode];
 	lines_per_row[dmode] = 1;
@@ -1091,14 +1271,17 @@
 	struct gfs2_buffer_head *tmp_bh;
 
 	/* Display any indirect pointers that we have. */
-	if (display_indirect() == 0)
-		return -1;
-	else if (block_is_rindex()) {
+	if (block_is_rindex()) {
 		tmp_bh = bread(&sbd, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		parse_rindex(tmp_inode, TRUE);
 		brelse(tmp_bh, not_updated);
 	}
+	else if (has_indirect_blocks() && !indirect_blocks &&
+		 !display_leaf(indirect))
+		return -1;
+	else if (display_indirect(indirect, indirect_blocks, 0, 0) == 0)
+		return -1;
 	else if (block_is_rglist()) {
 		tmp_bh = bread(&sbd, masterblock("rindex"));
 		tmp_inode = inode_get(&sbd, tmp_bh);
@@ -1135,7 +1318,7 @@
 /* ------------------------------------------------------------------------ */
 /* read_superblock - read the superblock                                    */
 /* ------------------------------------------------------------------------ */
-void read_superblock(void)
+void read_superblock(int fd)
 {
 	int x;
 
@@ -1172,7 +1355,9 @@
 	else
 		gfs1 = FALSE;
 	bufsize = sbd.sd_sb.sb_bsize;
-	block = 0x10 * (4096 / bufsize);
+	if (!bufsize)
+		bufsize = GFS2_DEFAULT_BSIZE;
+	block = 0x10 * (GFS2_DEFAULT_BSIZE / bufsize);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -1180,9 +1365,9 @@
 /* ------------------------------------------------------------------------ */
 void read_master_dir(void)
 {
-	ioctl(fd, BLKFLSBUF, 0);
-	do_lseek(fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize);
-	do_read(fd, buf, bufsize); /* read in the desired block */
+	ioctl(sbd.device_fd, BLKFLSBUF, 0);
+	do_lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize);
+	do_read(sbd.device_fd, buf, bufsize); /* read in the desired block */
 	gfs2_dinode_in(&di, buf); /* parse disk inode into structure */
 	do_dinode_extended(&di, buf); /* get extended data, if any */
 	memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info));
@@ -1205,70 +1390,50 @@
 	}
 	if (block_in_mem != blk) { /* If we changed blocks from the last read */
 		dev_offset = blk * bufsize;
-		ioctl(fd, BLKFLSBUF, 0);
-		do_lseek(fd, dev_offset);
-		do_read(fd, buf, bufsize); /* read in the desired block */
+		ioctl(sbd.device_fd, BLKFLSBUF, 0);
+		do_lseek(sbd.device_fd, dev_offset);
+		do_read(sbd.device_fd, buf, bufsize); /* read desired block */
 		block_in_mem = blk; /* remember which block is in memory */
 	}
 	line = 1;
-	gfs2_struct_type = display_block_type(buf);
+	gfs2_struct_type = display_block_type(buf, FALSE);
 	if (identify_only)
 		return 0;
 	indirect_blocks = 0;
 	lines_per_row[dmode] = 1;
 	if (gfs2_struct_type == GFS2_METATYPE_SB || blk == 0x10 * (4096 / bufsize)) {
 		gfs2_sb_in(&sbd.sd_sb, buf); /* parse it out into the sb structure */
-		memset(&indirect, 0, sizeof(indirect));
-		indirect[0].block = sbd.sd_sb.sb_master_dir.no_addr;
-		indirect[0].is_dir = TRUE;
-		indirect[0].dirents = 2;
+		memset(indirect, 0, sizeof(indirect));
+		indirect->ii[0].block = sbd.sd_sb.sb_master_dir.no_addr;
+		indirect->ii[0].is_dir = TRUE;
+		indirect->ii[0].dirents = 2;
 
-		memcpy(&indirect[0].dirent[0].filename, "root", 4);
-		indirect[0].dirent[0].dirent.de_inum.no_formal_ino =
+		memcpy(&indirect->ii[0].dirent[0].filename, "root", 4);
+		indirect->ii[0].dirent[0].dirent.de_inum.no_formal_ino =
 			sbd.sd_sb.sb_root_dir.no_formal_ino;
-		indirect[0].dirent[0].dirent.de_inum.no_addr =
+		indirect->ii[0].dirent[0].dirent.de_inum.no_addr =
 			sbd.sd_sb.sb_root_dir.no_addr;
-		indirect[0].dirent[0].block = sbd.sd_sb.sb_root_dir.no_addr;
-		indirect[0].dirent[0].dirent.de_type = DT_DIR;
+		indirect->ii[0].dirent[0].block = sbd.sd_sb.sb_root_dir.no_addr;
+		indirect->ii[0].dirent[0].dirent.de_type = DT_DIR;
 
-		memcpy(&indirect[0].dirent[1].filename, "master", 7);
-		indirect[0].dirent[1].dirent.de_inum.no_formal_ino = 
+		memcpy(&indirect->ii[0].dirent[1].filename, "master", 7);
+		indirect->ii[0].dirent[1].dirent.de_inum.no_formal_ino = 
 			sbd.sd_sb.sb_master_dir.no_formal_ino;
-		indirect[0].dirent[1].dirent.de_inum.no_addr =
+		indirect->ii[0].dirent[1].dirent.de_inum.no_addr =
 			sbd.sd_sb.sb_master_dir.no_addr;
-		indirect[0].dirent[1].block = sbd.sd_sb.sb_master_dir.no_addr;
-		indirect[0].dirent[1].dirent.de_type = DT_DIR;
+		indirect->ii[0].dirent[1].block = sbd.sd_sb.sb_master_dir.no_addr;
+		indirect->ii[0].dirent[1].dirent.de_type = DT_DIR;
 	}
 	else if (gfs2_struct_type == GFS2_METATYPE_DI) {
 		gfs2_dinode_in(&di, buf); /* parse disk inode into structure */
 		do_dinode_extended(&di, buf); /* get extended data, if any */
 	}
 	else if (gfs2_struct_type == GFS2_METATYPE_IN) { /* indirect block list */
-		do_indirect_extended(buf);
+		do_indirect_extended(buf, indirect);
+		indirect_blocks = 1;
 	}
 	else if (gfs2_struct_type == GFS2_METATYPE_LF) { /* directory leaf */
-		int x;
-		struct gfs2_dirent de;
-
-		indirect_blocks = 1;
-		memset(&indirect, 0, sizeof(indirect));
-		/* Directory Entries: */
-		for (x = sizeof(struct gfs2_leaf); x < bufsize;
-		     x += de.de_rec_len) {
-			gfs2_dirent_in(&de, buf + x);
-			if (de.de_inum.no_addr) {
-				indirect[indirect_blocks].block = de.de_inum.no_addr;
-				indirect[indirect_blocks].dirent[x].block = de.de_inum.no_addr;
-				memcpy(&indirect[indirect_blocks].dirent[x].dirent, &de,
-					   sizeof(struct gfs2_dirent));
-				memcpy(&indirect[indirect_blocks].dirent[x].filename,
-					   buf + x + sizeof(struct gfs2_dirent), de.de_name_len);
-				indirect[indirect_blocks].is_dir = TRUE;
-				indirect[indirect_blocks].dirents++;
-			}
-			if (de.de_rec_len <= sizeof(struct gfs2_dirent))
-				break;
-		}
+		do_leaf_extended(buf, indirect);
 	}
 	last_entry_onscreen[dmode] = 0;
 	if (dmode == EXTENDED_MODE && !block_has_extended_info())
@@ -1377,6 +1542,20 @@
 					temp_blk = masterblock(string);
 			}
 		}
+		else if (string[0] == '+') {
+			if (string[1] == '0' && string[2] == 'x')
+				sscanf(string, "%"SCNx64, &temp_blk);
+			else
+				sscanf(string, "%" PRIu64, &temp_blk);
+			temp_blk += block;
+		}
+		else if (string[0] == '-') {
+			if (string[1] == '0' && string[2] == 'x')
+				sscanf(string, "%"SCNx64, &temp_blk);
+			else
+				sscanf(string, "%" PRIu64, &temp_blk);
+			temp_blk -= block;
+		}
 		else if (string[0] == '0' && string[1] == 'x')
 			sscanf(string, "%"SCNx64, &temp_blk); /* retrieve in hex */
 		else
@@ -1457,9 +1636,9 @@
 					ch += (estring[i+1] - 'A' + 0x0a);
 				buf[offset + hexoffset] = ch;
 			}
-			do_lseek(fd, dev_offset);
-			do_write(fd, buf, bufsize);
-			fsync(fd);
+			do_lseek(sbd.device_fd, dev_offset);
+			do_write(sbd.device_fd, buf, bufsize);
+			fsync(sbd.device_fd);
 		}
 	}
 }
@@ -1535,9 +1714,11 @@
 		unsigned int col2;
 		uint64_t *b;
 		
-		col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */
-		b = (uint64_t *)&buf[edit_row[dmode]*16 + offset + col2];
-		temp_blk=be64_to_cpu(*b);
+		if (edit_row[dmode] >= 0) {
+			col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */
+			b = (uint64_t *)&buf[edit_row[dmode]*16 + offset + col2];
+			temp_blk=be64_to_cpu(*b);
+		}
 	}
 	else
 		sscanf(estring, "%"SCNx64, &temp_blk);/* retrieve in hex */
@@ -1808,6 +1989,189 @@
 }/* interactive_mode */
 
 /* ------------------------------------------------------------------------ */
+/* gfs_log_header_in - read in a gfs1-style log header                      */
+/* ------------------------------------------------------------------------ */
+void gfs_log_header_in(struct gfs_log_header *head, char *buf)
+{
+	struct gfs_log_header *str = (struct gfs_log_header *) buf;
+
+	gfs2_meta_header_in(&head->lh_header, buf);
+
+	head->lh_flags = be32_to_cpu(str->lh_flags);
+	head->lh_pad = be32_to_cpu(str->lh_pad);
+
+	head->lh_first = be64_to_cpu(str->lh_first);
+	head->lh_sequence = be64_to_cpu(str->lh_sequence);
+
+	head->lh_tail = be64_to_cpu(str->lh_tail);
+	head->lh_last_dump = be64_to_cpu(str->lh_last_dump);
+
+	memcpy(head->lh_reserved, str->lh_reserved, 64);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* gfs_log_header_print - print a gfs1-style log header                     */
+/* ------------------------------------------------------------------------ */
+void gfs_log_header_print(struct gfs_log_header *lh)
+{
+	gfs2_meta_header_print(&lh->lh_header);
+	pv(lh, lh_flags, "%u", "0x%.8X");
+	pv(lh, lh_pad, "%u", "%x");
+	pv(lh, lh_first, "%llu", "%llx");
+	pv(lh, lh_sequence, "%llu", "%llx");
+	pv(lh, lh_tail, "%llu", "%llx");
+	pv(lh, lh_last_dump, "%llu", "%llx");
+}
+
+/* ------------------------------------------------------------------------ */
+/* dump_journal - dump a journal file's contents.                           */
+/* ------------------------------------------------------------------------ */
+void dump_journal(const char *journal)
+{
+	struct gfs2_buffer_head *jindex_bh, *j_bh = NULL;
+	uint64_t jindex_block, jblock, j_size, jb;
+	int error, start_line, journal_num;
+	struct gfs2_dinode jdi;
+	char jbuf[bufsize];
+	struct gfs2_inode *j_inode = NULL;
+
+	start_line = line;
+	lines_per_row[dmode] = 1;
+	error = 0;
+	journal_num = atoi(journal + 7);
+	print_gfs2("Dumping journal #%d.", journal_num);
+	eol(0);
+	/* Figure out the block of the jindex file */
+	if (gfs1)
+		jindex_block = sbd1->sb_jindex_di.no_addr;
+	else
+		jindex_block = masterblock("jindex");
+	/* read in the block */
+	jindex_bh = bread(&sbd, jindex_block);
+	/* get the dinode data from it. */
+	gfs2_dinode_in(&di, jindex_bh->b_data); /* parse disk inode into structure */
+
+	if (!gfs1)
+		do_dinode_extended(&di, jindex_bh->b_data); /* parse dir. */
+	brelse(jindex_bh, not_updated);
+
+	if (gfs1) {
+		struct gfs2_inode *jiinode;
+		struct gfs_jindex ji;
+
+		jiinode = inode_get(&sbd, jindex_bh);
+		error = gfs2_readi(jiinode, (void *)&jbuf,
+				   journal_num * sizeof(struct gfs_jindex),
+				   sizeof(struct gfs_jindex));
+		if (!error)
+			return;
+		gfs_jindex_in(&ji, jbuf);
+		jblock = ji.ji_addr;
+		j_size = ji.ji_nsegment * 0x10;
+	} else {
+		jblock = indirect->ii[0].dirent[journal_num + 2].block;
+		j_bh = bread(&sbd, jblock);
+		j_inode = inode_get(&sbd, j_bh);
+		gfs2_dinode_in(&jdi, j_bh->b_data);/* parse dinode to struct */
+		j_size = jdi.di_size;
+	}
+
+	for (jb = 0; jb < j_size; jb += (gfs1 ? 1:bufsize)) {
+		if (gfs1) {
+			if (j_bh)
+				brelse(j_bh, not_updated);
+			j_bh = bread(&sbd, jblock + jb);
+			memcpy(jbuf, j_bh->b_data, bufsize);
+		}
+		else
+			error = gfs2_readi(j_inode, (void *)&jbuf, jb,
+					   bufsize);
+		if (!error) /* end of file */
+			break;
+		if (get_block_type(jbuf) == GFS2_METATYPE_LD) {
+			uint64_t *b;
+			struct gfs2_log_descriptor ld;
+			int i = 0, 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("Block #%4llx: Log descriptor, ",
+				   jb / (gfs1 ? 1 : bufsize));
+			gfs2_log_descriptor_in(&ld, jbuf);
+			print_gfs2("type %d ", ld.ld_type);
+
+			for (ltndx = 0;; ltndx++) {
+				if (ld.ld_type == logtypes[gfs1][ltndx] ||
+				    logtypes[gfs1][ltndx] == 0)
+					break;
+			}
+			print_gfs2("(%s) ", logtypestr[gfs1][ltndx]);
+			print_gfs2("len:%u, data1: %u",
+				   ld.ld_length, ld.ld_data1);
+			eol(0);
+			print_gfs2("             ");
+			if (gfs1)
+				b = (uint64_t *)(jbuf +
+					sizeof(struct gfs_log_descriptor));
+			else
+				b = (uint64_t *)(jbuf +
+					sizeof(struct gfs2_log_descriptor));
+			while (*b && (char *)b < (jbuf + bufsize)) {
+				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) {
+						eol(0);
+						print_gfs2("             ");
+					}
+					i++;
+					print_gfs2("0x%08llx   ", be64_to_cpu(*b));
+				}
+				b++;
+			}
+			eol(0);
+		} else if (get_block_type(jbuf) == GFS2_METATYPE_LH) {
+			struct gfs2_log_header lh;
+			struct gfs_log_header lh1;
+
+			if (gfs1) {
+				gfs_log_header_in(&lh1, jbuf);
+				print_gfs2("Block #%4llx: Log header: Seq"
+					   "= 0x%x, first = 0x%x tail = "
+					   "0x%x, last = 0x%x",
+					   jb, lh1.lh_sequence, lh1.lh_first,
+					   lh1.lh_tail, lh1.lh_last_dump);
+			} else {
+				gfs2_log_header_in(&lh, jbuf);
+				print_gfs2("Block #%4llx: Log header: Seq"
+					   "= 0x%x, tail = 0x%x, blk = 0x%x",
+					   jb / bufsize, lh.lh_sequence,
+					   lh.lh_tail, lh.lh_blkno);
+			}
+			eol(0);
+		}
+	}
+	brelse(j_bh, not_updated);
+	blockhist = -1; /* So we don't print anything else */
+}
+
+/* ------------------------------------------------------------------------ */
 /* usage - print command line usage                                         */
 /* ------------------------------------------------------------------------ */
 void usage(void)
@@ -1815,9 +2179,13 @@
 	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /dev/device\n\n");
 	fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n");
 	fprintf(stderr,"identify - prints out only the block type, not the details.\n");
-	fprintf(stderr,"savemeta - save off your metadata for analysis and debugging.  The intelligent way (assume bitmap is correct).\n");
+	fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
+	fprintf(stderr,"savemeta <file_system> <file> - save off your metadata for analysis and debugging.\n");
+	fprintf(stderr,"   (The intelligent way: assume bitmap is correct).\n");
 	fprintf(stderr,"savemetaslow - save off your metadata for analysis and debugging.  The SLOW way (block by block).\n");
 	fprintf(stderr,"restoremeta - restore metadata for debugging (DANGEROUS).\n");
+	fprintf(stderr,"rgcount - print how many RGs in the file system.\n");
+	fprintf(stderr,"rgflags rgnum [new flags] - print or modify flags for rg #rgnum (0 - X)\n");
 	fprintf(stderr,"-V   prints version number.\n");
 	fprintf(stderr,"-c 1 selects alternate color scheme 1\n");
 	fprintf(stderr,"-p   prints GFS2 structures or blocks to stdout.\n");
@@ -1830,6 +2198,7 @@
 	fprintf(stderr,"     inum - prints the inum file.\n");
 	fprintf(stderr,"     statfs - prints the statfs file.\n");
 	fprintf(stderr,"     rindex - prints the rindex file.\n");
+	fprintf(stderr,"     rg X - print resource group X.\n");
 	fprintf(stderr,"     rgs - prints all the resource groups (rgs).\n");
 	fprintf(stderr,"     quota - prints the quota file.\n");
 	fprintf(stderr,"-x   print in hexmode.\n");
@@ -1843,6 +2212,12 @@
 	fprintf(stderr,"     gfs2_edit -x -p master /dev/bobs_vg/lvol0\n");
 	fprintf(stderr,"   To print out the block-type for block 0x27381:\n");
 	fprintf(stderr,"     gfs2_edit identify -p 0x27381 /dev/bobs_vg/lvol0\n");
+	fprintf(stderr,"   To print out the fourth Resource Group. (the first R is #0)\n");
+	fprintf(stderr,"     gfs2_edit -p rg 3 /dev/sdb1\n");
+	fprintf(stderr,"   To set the Resource Group flags for rg #7 to 3.\n");
+	fprintf(stderr,"     gfs2_edit rgflags 7 3 /dev/sdc2\n");
+	fprintf(stderr,"   To save off all metadata for /dev/vg/lv:\n");
+	fprintf(stderr,"     gfs2_edit savemeta /dev/vg/lv /tmp/metasave\n");
 }/* usage */
 
 /* ------------------------------------------------------------------------ */
@@ -1883,12 +2258,21 @@
 				dmode = GFS2_MODE;
 			}
 			else if (!strcasecmp(argv[i], "savemeta"))
-				savemeta(argv[i+1], argv[i+2], FALSE);
+				termlines = 0;
 			else if (!strcasecmp(argv[i], "savemetaslow"))
-				savemeta(argv[i+1], argv[i+2], TRUE);
+				termlines = 0;
+			else if (!strcasecmp(argv[i], "printsavedmeta"))
+				restoremeta(argv[i+1], argv[i+2],
+					    TRUE);
 			else if (!strcasecmp(argv[i], "restoremeta"))
-				restoremeta(argv[i+1], argv[i+2]);
-			else if (strchr(argv[i],'/'))
+				restoremeta(argv[i+1], argv[i+2], FALSE);
+			else if (!strcmp(argv[i], "rgcount"))
+				termlines = 0;
+			else if (!strcmp(argv[i], "rgflags"))
+				termlines = 0;
+			else if (!strcmp(argv[i], "rg"))
+				termlines = 0;
+			else if (!device[0] && strchr(argv[i],'/'))
 				strcpy(device, argv[i]);
 		}
 		else { /* second pass */
@@ -1943,6 +2327,61 @@
 					else
 						push_block(masterblock("quota"));
 				}
+				else if (!strcmp(argv[i], "rgcount"))
+					rgcount();
+				else if (!strcmp(argv[i], "rgflags")) {
+					int rg, set = FALSE;
+					uint32_t new_flags = 0;
+					
+					i++;
+					if (i >= argc - 1) {
+						printf("Error: rg # not specified.\n");
+						printf("Format is: %s rgflags rgnum"
+						       "[newvalue]\n",
+						       argv[0]);
+						exit(EXIT_FAILURE);
+					}
+					if (argv[i][0]=='0' && argv[i][1]=='x')
+						sscanf(argv[i], "%"SCNx32,
+						       &rg);
+					else
+						rg = atoi(argv[i]);
+					i++;
+					if (i < argc - 1 &&
+					    isdigit(argv[i][0])) {
+						set = TRUE;
+						if (argv[i][0]=='0' &&
+						    argv[i][1]=='x')
+							sscanf(argv[i],
+							       "%"SCNx32,
+							       &new_flags);
+						else
+							new_flags =
+								atoi(argv[i]);
+					}
+					set_rgrp_flags(rg, new_flags, set,
+						       FALSE);
+					exit(EXIT_SUCCESS);
+				}
+				else if (!strcmp(argv[i], "rg")) {
+					int rg;
+					
+					i++;
+					if (i >= argc - 1) {
+						printf("Error: rg # not specified.\n");
+						printf("Format is: %s rg rgnum"
+						       "\n", argv[0]);
+						exit(EXIT_FAILURE);
+					}
+					rg = atoi(argv[i]);
+					i++;
+					set_rgrp_flags(rg, 0, FALSE, TRUE);
+					exit(EXIT_SUCCESS);
+				}
+				else if (!strcasecmp(argv[i], "savemeta"))
+					savemeta(argv[i+2], FALSE);
+				else if (!strcasecmp(argv[i], "savemetaslow"))
+					savemeta(argv[i+2], TRUE);
 				else if (argv[i][0]=='0' && argv[i][1]=='x') { /* hex addr */
 					sscanf(argv[i], "%"SCNx64, &temp_blk);/* retrieve in hex */
 					push_block(temp_blk);
@@ -1951,6 +2390,9 @@
 					sscanf(argv[i], "%"SCNd64, &temp_blk);
 					push_block(temp_blk);
 				}
+				else if (!strncmp(argv[i], "journal", 7) && isdigit(argv[i][7])) {
+					dump_journal(argv[i]);
+				}
 				else {
 					fprintf(stderr,"I don't know what '%s' means.\n", argv[i]);
 					usage();
@@ -1973,10 +2415,14 @@
 ******************************************************************************/
 int main(int argc, char *argv[])
 {
-	int i, j;
+	int i, j, fd;
 
 	prog_name = argv[0];
 
+	indirect = malloc(sizeof(struct iinfo));
+	if (!indirect)
+		die("Out of memory.");
+	memset(indirect, 0, sizeof(struct iinfo));
 	memset(start_row, 0, sizeof(start_row));
 	memset(lines_per_row, 0, sizeof(lines_per_row));
 	memset(end_row, 0, sizeof(end_row));
@@ -1999,16 +2445,19 @@
 		}
 	}
 
+	edit_row[GFS2_MODE] = 10; /* Start off at root inode
+				     pointer in superblock */
 	memset(device, 0, sizeof(device));
 	termlines = 30;  /* assume interactive mode until we find -p */
 	process_parameters(argc, argv, 0);
 
 	fd = open(device, O_RDWR);
 	if (fd < 0)
-		die("can't open %s: %s\n", argv[1], strerror(errno));
+		die("can't open %s: %s\n", device, strerror(errno));
 	max_block = lseek(fd, 0, SEEK_END) / bufsize;
 
-	read_superblock();
+	read_superblock(fd);
+	strcpy(sbd.device_name, device);
 	if (!gfs1)
 		read_master_dir();
 	block_in_mem = -1;
@@ -2020,11 +2469,13 @@
 	else { /* print all the structures requested */
 		for (i = 0; i <= blockhist; i++) {
 			block = blockstack[i + 1].block;
+			if (!block)
+				break;
 			display(identify);
 			if (!identify) {
 				display_extended();
 				printf("-------------------------------------" \
-					   "-----------------");
+				       "-----------------");
 				eol(0);
 			}
 			block = pop_block();
@@ -2033,5 +2484,7 @@
 	close(fd);
 	if (buf)
 		free(buf);
+	if (indirect)
+		free(indirect);
  	exit(EXIT_SUCCESS);
 }
--- cluster/gfs2/edit/hexedit.h	2007/11/13 17:06:32	1.4.2.5
+++ cluster/gfs2/edit/hexedit.h	2007/11/16 19:42:34	1.4.2.6
@@ -57,8 +57,14 @@
 #define GFS_FILE_FIFO           (101)  /* fifo/pipe */
 #define GFS_FILE_SOCK           (102)  /* socket */
 
+/* GFS 1 journal block types: */
+#define GFS_LOG_DESC_METADATA   (300)    /* metadata */
+#define GFS_LOG_DESC_IUL        (400)    /* unlinked inode */
+#define GFS_LOG_DESC_IDA        (401)    /* de-allocated inode */
+#define GFS_LOG_DESC_Q          (402)    /* quota */
+#define GFS_LOG_DESC_LAST       (500)    /* final in a logged transaction */
+
 EXTERN char *prog_name;
-EXTERN int fd;
 EXTERN uint64_t block INIT(0);
 EXTERN int blockhist INIT(0);
 EXTERN int edit_mode INIT(0);
@@ -96,6 +102,48 @@
 EXTERN int editing INIT(0);
 EXTERN uint64_t temp_blk;
 
+struct gfs_jindex {
+        uint64_t ji_addr;       /* starting block of the journal */
+        uint32_t ji_nsegment;   /* number (quantity) of segments in journal */
+        uint32_t ji_pad;
+
+        char ji_reserved[64];
+};
+
+struct gfs_log_descriptor {
+	struct gfs2_meta_header ld_header;
+
+	uint32_t ld_type;       /* GFS_LOG_DESC_... Type of this log chunk */
+	uint32_t ld_length;     /* Number of buffers in this chunk */
+	uint32_t ld_data1;      /* descriptor-specific field */
+	uint32_t ld_data2;      /* descriptor-specific field */
+	char ld_reserved[64];
+};
+
+struct gfs_log_header {
+	struct gfs2_meta_header lh_header;
+
+	uint32_t lh_flags;      /* GFS_LOG_HEAD_... */
+	uint32_t lh_pad;
+
+	uint64_t lh_first;     /* Block number of first header in this trans */
+	uint64_t lh_sequence;   /* Sequence number of this transaction */
+
+	uint64_t lh_tail;       /* Block number of log tail */
+	uint64_t lh_last_dump;  /* Block number of last dump */
+
+	char lh_reserved[64];
+};
+
+EXTERN int block_is_jindex(void);
+EXTERN int block_is_inum_file(void);
+EXTERN int block_is_statfs_file(void);
+EXTERN int block_is_quota_file(void);
+EXTERN int display_block_type(const char *lpBuffer, int from_restore);
+EXTERN void gfs_jindex_in(struct gfs_jindex *jindex, char *buf);
+EXTERN void gfs_log_header_in(struct gfs_log_header *head, char *buf);
+EXTERN void gfs_log_header_print(struct gfs_log_header *lh);
+
 struct gfs2_dirents {
 	uint64_t block;
 	struct gfs2_dirent dirent;
@@ -109,6 +157,10 @@
 	struct gfs2_dirents dirent[64];
 };
 
+struct iinfo {
+	struct indirect_info ii[512];
+};
+
 struct gfs_indirect {
 	struct gfs2_meta_header in_header;
 
@@ -159,18 +211,9 @@
 	char sb_reserved[96];
 };
 
-struct gfs_jindex {
-        uint64_t ji_addr;       /* starting block of the journal */
-        uint32_t ji_nsegment;   /* number (quantity) of segments in journal */
-        uint32_t ji_pad;
-
-        char ji_reserved[64];
-};
-
 EXTERN struct blkstack_info blockstack[BLOCK_STACK_SIZE];
-EXTERN struct indirect_info indirect[512]; /* more than the most indirect
-											  pointers possible for any given
-											  4K block */
+EXTERN struct iinfo *indirect; /* more than the most indirect
+			       pointers possible for any given 4K block */
 EXTERN struct indirect_info masterdir; /* Master directory info */
 EXTERN int indirect_blocks INIT(0);  /* count of indirect blocks */
 EXTERN enum dsp_mode dmode INIT(HEX_MODE);
--- cluster/gfs2/edit/savemeta.c	2007/10/11 20:32:35	1.1.2.2
+++ cluster/gfs2/edit/savemeta.c	2007/11/16 19:42:34	1.1.2.3
@@ -31,11 +31,13 @@
 #include <linux/gfs2_ondisk.h>
 
 #include "osi_list.h"
+#include "gfs2hex.h"
 #include "hexedit.h"
 #include "libgfs2.h"
 
 #define BUFSIZE (4096)
 #define DFT_SAVE_FILE "/tmp/gfsmeta"
+#define MAX_JOURNALS_SAVED 256
 
 struct saved_metablock {
 	uint64_t blk;
@@ -46,6 +48,8 @@
 struct saved_metablock *savedata;
 uint64_t last_fs_block, last_reported_block, blks_saved, total_out, pct;
 struct gfs2_block_list *blocklist = NULL;
+uint64_t journal_blocks[MAX_JOURNALS_SAVED];
+int journals_found = 0;
 
 extern void read_superblock(void);
 uint64_t masterblock(const char *fn);
@@ -413,13 +417,13 @@
 		*struct_len = sizeof(struct gfs2_log_header);
 		break;
 	case GFS2_METATYPE_LD:   /* 9 (log descriptor) */
-		*struct_len = sizeof(struct gfs2_log_descriptor);
+		*struct_len = bufsize;
 		break;
 	case GFS2_METATYPE_EA:   /* 10 (extended attr hdr) */
-		*struct_len = sizeof(struct gfs2_ea_header);
+		*struct_len = bufsize;
 		break;
 	case GFS2_METATYPE_ED:   /* 11 (extended attr data) */
-		*struct_len = 512;
+		*struct_len = bufsize;
 		break;
 	default:
 		*struct_len = bufsize;
@@ -434,7 +438,7 @@
 /* checking every block kills performance.  We only report    */
 /* every second because we don't need 100 extra messages in   */
 /* logs made from verbose mode.                               */
-void warm_fuzzy_stuff(uint64_t block, int force)
+void warm_fuzzy_stuff(uint64_t block, int force, int save)
 {
         static struct timeval tv;
         static uint32_t seconds = 0;
@@ -448,29 +452,67 @@
 
 		seconds = tv.tv_sec;
 		if (last_fs_block) {
-			percent = (block * 100) / last_fs_block;
-			printf("\r%" PRIu64 " blocks (%"
-			       PRIu64 "%%) processed, ", block, percent);
-			printf("%" PRIu64 " blocks (%" PRIu64 "MB) saved    ",
-			       blks_saved, total_out / (1024*1024));
+			printf("\r");
+			if (save) {
+				percent = (block * 100) / last_fs_block;
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "%%) processed, ", block,
+				       percent);
+			}
+			if (total_out < 1024 * 1024)
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "KB) %s.    ",
+				       blks_saved, total_out / 1024,
+				       save?"saved":"restored");
+			else
+				printf("%" PRIu64 " metadata blocks (%"
+				       PRIu64 "MB) %s.    ",
+				       blks_saved, total_out / (1024*1024),
+				       save?"saved":"restored");
+			if (force)
+				printf("\n");
 			fflush(stdout);
 		}
 	}
 }
 
-void save_block(int fd, int out_fd, uint64_t blk)
+int block_is_a_journal(void)
+{
+	int j;
+
+	for (j = 0; j < journals_found; j++)
+		if (block == journal_blocks[j])
+			return TRUE;
+	return FALSE;
+}
+
+int block_is_systemfile(void)
+{
+	return block_is_jindex() ||
+		block_is_inum_file() ||
+		block_is_statfs_file() ||
+		block_is_quota_file() ||
+		block_is_a_journal();
+}
+
+int save_block(int fd, int out_fd, uint64_t blk)
 {
 	int blktype, blklen, outsz;
 	uint16_t trailing0;
 	char *p;
 
-	warm_fuzzy_stuff(blk, FALSE);
 	memset(savedata, 0, sizeof(struct saved_metablock));
 	do_lseek(fd, blk * bufsize);
 	do_read(fd, savedata->buf, bufsize); /* read in the block */
 
-	if (get_gfs_struct_info(savedata->buf, &blktype, &blklen))
-		return; /* Not metadata, so skip it */
+	/* If this isn't metadata and isn't a system file, we don't want it.
+	   Note that we're checking "block" here rather than blk.  That's
+	   because we want to know if the source inode's "block" is a system
+	   inode, not the block within the inode "blk". They may or may not
+	   be the same thing. */
+	if (get_gfs_struct_info(savedata->buf, &blktype, &blklen) &&
+	    !block_is_systemfile())
+		return 0; /* Not metadata, and not system file, so skip it */
 	trailing0 = 0;
 	p = &savedata->buf[blklen - 1];
 	while (*p=='\0' && trailing0 < bufsize) {
@@ -485,26 +527,198 @@
 	do_write(out_fd, savedata->buf, outsz);
 	total_out += sizeof(savedata->blk) + sizeof(savedata->siglen) + outsz;
 	blks_saved++;
+	return blktype;
+}
+
+/*
+ * save_indirect_blocks - save all indirect blocks for the given buffer
+ */
+void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
+			  struct gfs2_buffer_head *mybh, int height, int hgt)
+{
+	uint64_t old_block = 0, starting_block;
+	uint64_t *ptr;
+	int head_size;
+	struct gfs2_buffer_head *nbh;
+
+	starting_block = block; /* remember where we started */
+	head_size = (hgt > 1 ?
+		     sizeof(struct gfs2_meta_header) :
+		     sizeof(struct gfs2_dinode));
+
+	for (ptr = (uint64_t *)(mybh->b_data + head_size);
+	     (char *)ptr < (mybh->b_data + mybh->b_size); ptr++) {
+		if (!*ptr)
+			continue;
+		block = be64_to_cpu(*ptr);
+		if (block == old_block)
+			continue;
+		old_block = block;
+		save_block(sbd.device_fd, out_fd, block);
+		if (height != hgt) { /* If not at max height */
+			nbh = bread(&sbd, block);
+			osi_list_add_prev(&nbh->b_altlist,
+					  cur_list);
+			brelse(nbh, not_updated);
+		}
+	} /* for all data on the indirect block */
+	block = starting_block; /* go back to where we started */
+}
+
+/*
+ * save_inode_data - save off important data associated with an inode
+ *
+ * out_fd - destination file descriptor
+ * block - block number of the inode to save the data for
+ * 
+ * For user files, we don't want anything except all the indirect block
+ * pointers that reside on blocks on all but the highest height.
+ *
+ * For system files like statfs and inum, we want everything because they
+ * may contain important clues and no user data.
+ *
+ * For file system journals, the "data" is a mixture of metadata and
+ * journaled data.  We want all the metadata and none of the user data.
+ */
+void save_inode_data(int out_fd)
+{
+	uint32_t height;
+	struct gfs2_inode *inode;
+	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
+	osi_list_t *prev_list, *cur_list, *tmp;
+	struct gfs2_buffer_head *metabh, *mybh;
+	int i;
+	char *buf;
+
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
+		osi_list_init(&metalist[i]);
+	buf = malloc(bufsize);
+	metabh = bread(&sbd, block);
+	inode = inode_get(&sbd, metabh);
+	height = inode->i_di.di_height;
+	/* If this is a user inode, we don't follow to the file height.
+	   We stop one level less.  That way we save off the indirect
+	   pointer blocks but not the actual file contents. */
+	if (height && !block_is_systemfile())
+		height--;
+	osi_list_add(&metabh->b_altlist, &metalist[0]);
+        for (i = 1; i <= height; i++){
+		prev_list = &metalist[i - 1];
+		cur_list = &metalist[i];
+
+		for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
+			mybh = osi_list_entry(tmp, struct gfs2_buffer_head,
+					      b_altlist);
+			save_indirect_blocks(out_fd, cur_list, mybh,
+					     height, i);
+		} /* for blocks at that height */
+	} /* for height */
+	/* free metalists */
+	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
+		cur_list = &metalist[i];
+		while (!osi_list_empty(cur_list)) {
+			mybh = osi_list_entry(cur_list->next,
+					    struct gfs2_buffer_head,
+					    b_altlist);
+			osi_list_del(&mybh->b_altlist);
+		}
+	}
+	/* Process directory exhash inodes */
+	if (S_ISDIR(inode->i_di.di_mode)) {
+		if (inode->i_di.di_flags & GFS2_DIF_EXHASH) {
+			save_indirect_blocks(out_fd, cur_list, mybh,
+					     height, 0);
+		}
+	}
+	if (inode->i_di.di_eattr) { /* if this inode has extended attributes */
+		struct gfs2_ea_header ea;
+		int e;
+
+		metabh = bread(&sbd, inode->i_di.di_eattr);
+		save_block(sbd.device_fd, out_fd, inode->i_di.di_eattr);
+		for (e = sizeof(struct gfs2_meta_header);
+		     e < bufsize; e += ea.ea_rec_len) {
+			uint64_t blk, *b;
+			int charoff;
+
+			gfs2_ea_header_in(&ea, metabh->b_data + e);
+			for (i = 0; i < ea.ea_num_ptrs; i++) {
+				charoff = e + ea.ea_name_len +
+					sizeof(struct gfs2_ea_header) +
+					sizeof(uint64_t) - 1;
+				charoff /= sizeof(uint64_t);
+				b = (uint64_t *)(metabh->b_data);
+				b += charoff + i;
+				blk = be64_to_cpu(*b);
+				save_block(sbd.device_fd, out_fd, blk);
+			}
+			if (!ea.ea_rec_len)
+				break;
+		}
+		brelse(metabh, not_updated);
+	}
+	inode_put(inode, not_updated);
+	free(buf);
+}
+
+void get_journal_inode_blocks(void)
+{
+	int journal;
+	struct gfs2_buffer_head *bh;
+
+	journals_found = 0;
+	memset(journal_blocks, 0, sizeof(journal_blocks));
+	/* Save off all the journals--but only the metadata.
+	 * This is confusing so I'll explain.  The journals contain important 
+	 * metadata.  However, in gfs2 the journals are regular files within
+	 * the system directory.  Since they're regular files, the blocks
+	 * within the journals are considered data, not metadata.  Therefore,
+	 * they won't have been saved by the code above.  We want to dump
+	 * these blocks, but we have to be careful.  We only care about the
+	 * journal blocks that look like metadata, and we need to not save
+	 * journaled user data that may exist there as well. */
+	for (journal = 0; ; journal++) { /* while journals exist */
+		uint64_t jblock;
+		int amt;
+		struct gfs2_dinode jdi;
+		struct gfs2_inode *j_inode = NULL;
+
+		if (gfs1) {
+			struct gfs_jindex ji;
+			char jbuf[sizeof(struct gfs_jindex)];
+
+			j_inode = inode_get(&sbd, bh);
+			amt = gfs2_readi(j_inode, (void *)&jbuf,
+					 journal * sizeof(struct gfs_jindex),
+					 sizeof(struct gfs_jindex));
+			if (!amt)
+				break;
+			gfs_jindex_in(&ji, jbuf);
+			jblock = ji.ji_addr;
+			inode_put(j_inode, not_updated);
+		} else {
+			if (journal > indirect->ii[0].dirents - 3)
+				break;
+			jblock = indirect->ii[0].dirent[journal + 2].block;
+			bh = bread(&sbd, jblock);
+			j_inode = inode_get(&sbd, bh);
+			gfs2_dinode_in(&jdi, bh->b_data);
+			inode_put(j_inode, not_updated);
+		}
+		journal_blocks[journals_found++] = jblock;
+	}
 }
 
-void savemeta(const char *in_fn, const char *out_fn, int slow)
+void savemeta(const char *out_fn, int slow)
 {
 	int out_fd;
 	osi_list_t *tmp;
-	uint64_t blk;
 	uint64_t memreq;
 	int rgcount;
+	uint64_t jindex_block;
+	struct gfs2_buffer_head *bh;
 
-	memset(&sbd, 0, sizeof(struct gfs2_sbd));
-	strcpy(sbd.device_name, in_fn);
-	sbd.bsize = GFS2_DEFAULT_BSIZE;
-	sbd.rgsize = -1;
-	sbd.jsize = GFS2_DEFAULT_JSIZE;
-	sbd.qcsize = GFS2_DEFAULT_QCSIZE;
 	sbd.md.journals = 1;
-	sbd.device_fd = open(in_fn, O_RDONLY);
-	if (sbd.device_fd < 0)
-		die("Can't open %s: %s\n", in_fn, strerror(errno));
 
 	if (!out_fn)
 		out_fn = DFT_SAVE_FILE;
@@ -512,6 +726,8 @@
 	if (out_fd < 0)
 		die("Can't open %s: %s\n", out_fn, strerror(errno));
 
+	if (ftruncate(out_fd, 0))
+		die("Can't truncate %s: %s\n", out_fn, strerror(errno));
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the operation.\n");
@@ -536,35 +752,49 @@
 			bufsize = sbd.bsize = sbd.sd_sb.sb_bsize;
 	}
 	last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / bufsize;
-	printf("There are %" PRIu64 " blocks of %" PRIu64 " bytes.\n\n",
+	printf("There are %" PRIu64 " blocks of %" PRIu64 " bytes.\n",
 	       last_fs_block, bufsize);
 	if (!slow) {
-		if (gfs1)
+		if (gfs1) {
 			sbd.md.riinode =
 				gfs2_load_inode(&sbd,
 						sbd1->sb_rindex_di.no_addr);
-		else {
+			jindex_block = sbd1->sb_jindex_di.no_addr;
+		} else {
 			sbd.master_dir =
 				gfs2_load_inode(&sbd,
 						sbd.sd_sb.sb_master_dir.no_addr);
 
 			slow = gfs2_lookupi(sbd.master_dir, "rindex", 6, 
 					    &sbd.md.riinode);
+			jindex_block = masterblock("jindex");
 		}
+		bh = bread(&sbd, jindex_block);
+		gfs2_dinode_in(&di, bh->b_data);
+		if (!gfs1)
+			do_dinode_extended(&di, bh->b_data);
+		brelse(bh, not_updated);
 	}
 	if (!slow) {
+		printf("Reading resource groups...");
+		fflush(stdout);
 		if (gfs1)
 			slow = gfs1_ri_update(&sbd, 0, &rgcount);
 		else
 			slow = ri_update(&sbd, 0, &rgcount);
+		printf("Done.\n\n");
+		fflush(stdout);
 	}
 	if (!slow) {
 		blocklist = gfs2_block_list_create(last_fs_block + 1, &memreq);
 		if (!blocklist)
 			slow = TRUE;
 	}
+	get_journal_inode_blocks();
 	if (!slow) {
+		/* Save off the superblock */
 		save_block(sbd.device_fd, out_fd, 0x10 * (4096 / bufsize));
+		/* Walk through the resource groups saving everything within */
 		for (tmp = sbd.rglist.next; tmp != &sbd.rglist;
 		     tmp = tmp->next){
 			struct rgrp_list *rgd;
@@ -584,28 +814,37 @@
 			}
 			first = 1;
 			/* Save off the rg and bitmaps */
-			for (blk = rgd->ri.ri_addr;
-			     blk < rgd->ri.ri_data0; blk++)
-				save_block(sbd.device_fd, out_fd, blk);
+			for (block = rgd->ri.ri_addr;
+			     block < rgd->ri.ri_data0; block++) {
+				warm_fuzzy_stuff(block, FALSE, TRUE);
+				save_block(sbd.device_fd, out_fd, block);
+			}
 			/* Save off the other metadata: inodes, etc. */
-			while (!gfs2_next_rg_meta(rgd, &blk, first)) {
-				save_block(sbd.device_fd, out_fd, blk);
+			while (!gfs2_next_rg_meta(rgd, &block, first)) {
+				int blktype;
+
+				warm_fuzzy_stuff(block, FALSE, TRUE);
+				blktype = save_block(sbd.device_fd, out_fd,
+						     block);
+				if (blktype == GFS2_METATYPE_DI)
+					save_inode_data(out_fd);
 				first = 0;
 			}
 			gfs2_rgrp_relse(rgd, not_updated);
 		}
 	}
 	if (slow) {
-		for (blk = 0; blk < last_fs_block; blk++) {
-			save_block(sbd.device_fd, out_fd, blk);
+		for (block = 0; block < last_fs_block; block++) {
+			save_block(sbd.device_fd, out_fd, block);
 		}
 	}
+	/* Clean up */
 	if (blocklist)
 		gfs2_block_list_destroy(blocklist);
 	/* There may be a gap between end of file system and end of device */
 	/* so we tell the user that we've processed everything. */
-	blk = last_fs_block;
-	warm_fuzzy_stuff(blk, TRUE);
+	block = last_fs_block;
+	warm_fuzzy_stuff(block, TRUE, TRUE);
 	printf("\nMetadata saved to file %s.\n", out_fn);
 	free(savedata);
 	close(out_fd);
@@ -613,15 +852,17 @@
 	exit(0);
 }
 
-int restore_data(int fd, int in_fd)
+int restore_data(int fd, int in_fd, int printblocksonly)
 {
 	size_t rs;
 	uint64_t buf64, writes = 0;
 	uint16_t buf16;
 	int first = 1;
-	uint64_t max_fs_size;
 
-	do_lseek(fd, 0);
+	if (!printblocksonly)
+		do_lseek(fd, 0);
+	blks_saved = total_out = 0;
+	last_fs_block = 0;
 	while (TRUE) {
 		memset(savedata, 0, sizeof(struct saved_metablock));
 		rs = read(in_fd, &buf64, sizeof(uint64_t));
@@ -631,12 +872,14 @@
 			fprintf(stderr, "Error reading from file.\n");
 			return -1;
 		}
+		total_out += bufsize;
 		savedata->blk = be64_to_cpu(buf64);
-		if (savedata->blk >= max_fs_size) {
+		if (!printblocksonly &&
+		    last_fs_block && savedata->blk >= last_fs_block) {
 			fprintf(stderr, "Error: File system is too small to "
 				"restore this metadata.\n");
 			fprintf(stderr, "File system is %" PRIu64 " blocks, ",
-				max_fs_size);
+				last_fs_block);
 			fprintf(stderr, "Restore block = %" PRIu64 "\n",
 				savedata->blk);
 			return -1;
@@ -648,64 +891,100 @@
 			do_read(in_fd, savedata->buf, savedata->siglen);
 			if (first) {
 				gfs2_sb_in(&sbd.sd_sb, savedata->buf);
-				if (check_sb(&sbd.sd_sb)) {
+				sbd1 = (struct gfs_sb *)&sbd.sd_sb;
+				if (sbd1->sb_fs_format == GFS_FORMAT_FS &&
+				    sbd1->sb_header.mh_type ==
+				    GFS_METATYPE_SB &&
+				    sbd1->sb_header.mh_format ==
+				    GFS_FORMAT_SB &&
+				    sbd1->sb_multihost_format ==
+				    GFS_FORMAT_MULTI)
+					;
+				else if (check_sb(&sbd.sd_sb)) {
 					fprintf(stderr,"Error: Invalid superblock data.\n");
 					return -1;
 				}
 				bufsize = sbd.sd_sb.sb_bsize;
-				last_fs_block =
-					lseek(fd, 0, SEEK_END) / bufsize;
-				printf("There are %" PRIu64 " blocks of %" \
-				       PRIu64 "bytes in the destination file" \
-				       " system.\n\n", last_fs_block, bufsize);
+				if (!printblocksonly) {
+					last_fs_block =
+						lseek(fd, 0, SEEK_END) /
+						bufsize;
+					printf("There are %" PRIu64 " blocks of %" \
+					       PRIu64 " bytes in the destination" \
+					       " file system.\n\n",
+					       last_fs_block, bufsize);
+				}
 				first = 0;
 			}
-			do_lseek(fd, savedata->blk * bufsize);
-			do_write(fd, savedata->buf, bufsize);
-			writes++;
+			if (printblocksonly) {
+				print_gfs2("%d (l=0x%x): ", blks_saved,
+					   savedata->siglen);
+				block = savedata->blk;
+				display_block_type(savedata->buf, TRUE);
+			} else {
+				warm_fuzzy_stuff(savedata->blk, FALSE, FALSE);
+				if (savedata->blk >= last_fs_block) {
+					printf("Out of space on the destination "
+					       "device; quitting.\n");
+					break;
+				}
+				do_lseek(fd, savedata->blk * bufsize);
+				do_write(fd, savedata->buf, bufsize);
+				writes++;
+			}
+			blks_saved++;
 		} else {
 			fprintf(stderr, "Bad record length: %d for #%"
 				PRIu64".\n", savedata->siglen, savedata->blk);
 			return -1;
 		}
 	}
-	printf("%" PRIu64 " blocks restored.\n", writes);
+	if (!printblocksonly)
+		warm_fuzzy_stuff(savedata->blk, TRUE, FALSE);
 	return 0;
 }
 
-void restoremeta(const char *in_fn, const char *out_device)
+void complain(const char *complaint)
 {
-	int in_fd;
+	fprintf(stderr, "%s\n", complaint);
+	die("Format is: \ngfs2_edit restoremeta <file to restore> "
+	    "<dest file system>\n");
+}
+
+void restoremeta(const char *in_fn, const char *out_device,
+		 int printblocksonly)
+{
+	int in_fd, error;
 
+	termlines = 0;
 	if (!in_fn)
-		die("No source file specified.  Format is: \ngfs2_edit "
-		    "restoremeta <file to restore> <dest file system>\n");
-	if (!out_device)
-		die("No destination file system specified.  Format is: \n"
-		    "gfs2_edit restoremeta <file to restore> <dest file "
-		    "system>\n");
+		complain("No source file specified.");
+	if (!printblocksonly && !out_device)
+		complain("No destination file system specified.");
 	in_fd = open(in_fn, O_RDONLY);
 	if (in_fd < 0)
 		die("Can't open source file %s: %s\n",
 		    in_fn, strerror(errno));
 
-	fd = open(out_device, O_RDWR);
-	if (fd < 0)
-		die("Can't open destination file system %s: %s\n",
-		    out_device, strerror(errno));
-
+	if (!printblocksonly) {
+		sbd.device_fd = open(out_device, O_RDWR);
+		if (sbd.device_fd < 0)
+			die("Can't open destination file system %s: %s\n",
+			    out_device, strerror(errno));
+	}
 	savedata = malloc(sizeof(struct saved_metablock));
 	if (!savedata)
 		die("Can't allocate memory for the restore operation.\n");
 
-	blks_saved = total_out = 0;
-	if (restore_data(fd, in_fd) == 0)
-		printf("File %s restore successful.\n", in_fn);
-	else
-		printf("File %s restore error.\n", in_fn);
+	blks_saved = 0;
+	error = restore_data(sbd.device_fd, in_fd, printblocksonly);
+	printf("File %s %s %s.\n", in_fn,
+	       (printblocksonly ? "print" : "restore"),
+	       (error ? "error" : "successful"));
 	free(savedata);
 	close(in_fd);
-	close(fd);
+	if (!printblocksonly)
+		close(sbd.device_fd);
 
 	exit(0);
 }
--- cluster/gfs2/libgfs2/ondisk.c	2007/10/11 20:32:36	1.5.2.3
+++ cluster/gfs2/libgfs2/ondisk.c	2007/11/16 19:42:35	1.5.2.4
@@ -386,7 +386,7 @@
 
 	memset(buf, 0, GFS2_FNAMESIZE + 1);
 	memcpy(buf, name, de->de_name_len);
-	printf("  name = %s\n", buf);
+	print_it("  name", "%s", NULL, buf);
 }
 
 void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf)
@@ -462,7 +462,7 @@
 
 	memset(buf, 0, GFS2_EA_MAX_NAME_LEN + 1);
 	memcpy(buf, name, ea->ea_name_len);
-	printf("  name = %s\n", buf);
+	print_it("  name", "%s", NULL, buf);
 }
 
 void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf)
--- cluster/gfs2/libgfs2/ondisk.h	2006/06/14 13:55:11	1.2
+++ cluster/gfs2/libgfs2/ondisk.h	2007/11/16 19:42:35	1.2.2.1
@@ -35,6 +35,8 @@
 extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf);
 extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf);
 extern void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf);
+extern void gfs2_log_descriptor_in(struct gfs2_log_descriptor *ld, char *buf);
+extern void gfs2_log_descriptor_out(struct gfs2_log_descriptor *ld, char *buf);
 extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf);
 extern void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf);
 extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf);




More information about the Cluster-devel mailing list