All of lore.kernel.org
 help / color / mirror / Atom feed
From: rpeterso@sourceware.org <rpeterso@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] cluster/gfs2 edit/gfs2hex.c edit/hexedit.c edi ...
Date: 16 Nov 2007 19:42:36 -0000	[thread overview]
Message-ID: <20071116194236.28694.qmail@sourceware.org> (raw)

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@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);



                 reply	other threads:[~2007-11-16 19:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071116194236.28694.qmail@sourceware.org \
    --to=rpeterso@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.