This is the mail archive of the cluster-cvs@sourceware.org mailing list for the cluster.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cluster: RHEL5 - GFS2: gfs2_edit fixes for 5.4


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=ae88c56fccf59bf2e4fd7efc8505ffc552d534f7
Commit:        ae88c56fccf59bf2e4fd7efc8505ffc552d534f7
Parent:        8722e7de933138606b4e65a325e4884e95ff5ae5
Author:        Bob Peterson <rpeterso@redhat.com>
AuthorDate:    Tue Feb 17 11:54:50 2009 -0600
Committer:     Bob Peterson <rpeterso@redhat.com>
CommitterDate: Tue Feb 17 11:54:50 2009 -0600

GFS2: gfs2_edit fixes for 5.4

bz 483799

1. The ability for gfs2_edit to report on whether a given block is
   free, allocated data, or allocated metadata or unlinked metadata.
   This works on the interactive screen as well as -p blockalloc
   Values printed are: 0 (free), 1 (data), 2 (unlinked), 3 (meta).
2. The ability for gfs2_edit to report on the metadata block type.
   Use: -p <block> blocktype
   Valid block types are: 0 (clump), 1 (superblock),
   2 (Resource Group Header), 3 (Resource Group Bitmap),
   4 (Dinode), 5 (Indirect Block), 6 (Directory Leaf),
   7 (Journaled Data), 8 (Log Header), 9 (Log descriptor),
   10 (Ext. attrib), 11 (Eattr Data), 12 (Log Buffer), 13 (invalid),
   14 (Quota Change).
3. The ability for gfs2_edit to print out specific fields from
   a structure, such as an inode or rg.  -p <block> field <fieldname>
4. The ability for gfs2_edit to edit the file system through the
   command line, like: -p <block> field <fieldname> <newval>
5. The ability to search for blocks of a given metadata type, which
   is useful for digging through journals looking for evidence of
   something that's gone wrong.  In command-line mode, use:
   -p <block> find <sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc>
   In interactive mode, change the block number to "/sb", "/rg", etc.
6. The ability to edit fields in structure mode.  Right now, only
   dinode and rg structures are editable.  Others are ignored.
7. Fixed a bug whereby -p size went on to print other things.
8. The ability for gfs2_edit to print or change the metadata
   block type through the cli.  Use: -p <block> blocktype [newtype]
9. The ability for gfs2_edit to locate which RG or bitmap block
   a certain block is associated with.  (i.e. locate the RG that's
   prior to the specified block).  For RG use: -p <block> blockrg
   For bitmaps use: -p <block> blockbits
---
 gfs2/edit/gfs2hex.c    |   75 ++--
 gfs2/edit/hexedit.c    | 1071 +++++++++++++++++++++++++++++++++++++++---------
 gfs2/edit/hexedit.h    |   12 +-
 gfs2/fsck/fs_bits.h    |    5 -
 gfs2/libgfs2/fs_bits.c |  105 +-----
 gfs2/man/gfs2_edit.8   |  120 +++++-
 6 files changed, 1030 insertions(+), 358 deletions(-)

diff --git a/gfs2/edit/gfs2hex.c b/gfs2/edit/gfs2hex.c
index 8b18708..7538b81 100644
--- a/gfs2/edit/gfs2hex.c
+++ b/gfs2/edit/gfs2hex.c
@@ -41,12 +41,31 @@ extern struct gfs2_dinode di;
 extern int line, termlines;
 extern char edit_fmt[80];
 extern char estring[1024];
+extern char efield[64];
 extern int edit_mode INIT(0);
 extern int edit_row[DMODES], edit_col[DMODES];
 extern int edit_size[DMODES], last_entry_onscreen[DMODES];
 extern char edit_fmt[80];
 extern enum dsp_mode dmode INIT(HEX_MODE); /* display mode */
 
+const char *block_type_str[15] = {
+	"Clump",
+	"Superblock",
+	"Resource Group Header",
+	"Resource Group Bitmap",
+	"Dinode",
+	"Indirect Block",
+	"Leaf",
+	"Journaled Data",
+	"Log Header",
+	"Log descriptor",
+	"Ext. attrib",
+	"Eattr Data",
+	"Log Buffer",
+	"Metatype 13",
+	"Quota Change",
+};
+
 void eol(int col) /* end of line */
 {
 	if (termlines) {
@@ -166,6 +185,7 @@ void print_it(const char *label, const char *fmt, const char *fmt2, ...)
 		if (termlines) {
 			refresh();
 			if (line == (edit_row[dmode] * lines_per_row[dmode]) + 4) {
+				strcpy(efield, label + 2); /* it's indented */
 				strcpy(estring, tmp_string);
 				strcpy(edit_fmt, fmt);
 				edit_size[dmode] = strlen(estring);
@@ -487,57 +507,46 @@ int display_gfs2(void)
 	{
 	case GFS2_MAGIC:
 		gfs2_meta_header_in(&mh, buf);
+		if (mh.mh_type > GFS2_METATYPE_QC)
+			print_gfs2("Unknown metadata type");
+		else
+			print_gfs2("%s:", block_type_str[mh.mh_type]);
+		eol(0);
 		
 		switch (mh.mh_type)
 		{
 		case GFS2_METATYPE_SB:
-			print_gfs2("Superblock:");
-			eol(0);
 			gfs2_sb_in(&sbd.sd_sb, buf);
 			gfs2_sb_print2(&sbd.sd_sb);
 			break;
-			
+
 		case GFS2_METATYPE_RG:
-			print_gfs2("Resource Group Header:");
-			eol(0);
 			gfs2_rgrp_in(&rg, buf);
 			gfs2_rgrp_print(&rg);
 			break;
-			
+
 		case GFS2_METATYPE_RB:
-			print_gfs2("Resource Group Bitmap:");
-			eol(0);
 			gfs2_meta_header_print(&mh);
 			break;
-			
+
 		case GFS2_METATYPE_DI:
-			print_gfs2("Dinode:");
-			eol(0);
 			gfs2_dinode_print(&di);
 			break;
-			
+
+		case GFS2_METATYPE_IN:
+			gfs2_meta_header_print(&mh);
+			break;
+
 		case GFS2_METATYPE_LF:
-			print_gfs2("Leaf:");
-			eol(0);
 			gfs2_leaf_in(&lf, buf);
 			gfs2_leaf_print(&lf);
 			break;
-			
-		case GFS2_METATYPE_IN:
-			print_gfs2("Indirect Block:");
-			eol(0);
-			gfs2_meta_header_print(&mh);
-			break;
-			
+
 		case GFS2_METATYPE_JD:
-			print_gfs2("Journaled File Block:");
-			eol(0);
 			gfs2_meta_header_print(&mh);
 			break;
-			
+
 		case GFS2_METATYPE_LH:
-			print_gfs2("Log Header:");
-			eol(0);
 			if (gfs1) {
 				gfs_log_header_in(&lh1, buf);
 				gfs_log_header_print(&lh1);
@@ -546,42 +555,30 @@ int display_gfs2(void)
 				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);
 			do_eattr_extended(buf);
 			break;
 			
 		case GFS2_METATYPE_ED:
-			print_gfs2("Eattr Data Block:");
-			eol(0);
 			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);
 			break;
 		}
 		break;
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index f62c705..2da61ce 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -44,6 +44,11 @@
 
 #define RGLIST_DUMMY_BLOCK -2
 
+const char *mtypes[] = {"none", "sb", "rg", "rb", "di", "in", "lf", "jd",
+			"lh", "ld", "ea", "ed", "lb", "13", "qc"};
+const char *allocdesc[] = {"Free ", "Data ", "Unlnk",
+			   "Meta ", "Resrv"};
+
 int display(int identify_only);
 extern void eol(int col);
 extern void do_leaf_extended(char *buf, struct iinfo *indir);
@@ -52,6 +57,113 @@ extern void savemeta(const char *out_fn, int slow);
 extern void restoremeta(const char *in_fn, const char *out_device,
 			int printblocksonly);
 
+/* for assigning numeric fields: */
+#define checkassign(strfield, struct, member, value) do {		\
+		if (strcmp(#member, strfield) == 0) {			\
+			struct->member = (typeof(struct->member)) value; \
+			return 0;					\
+		}							\
+	} while(0)
+
+/* for assigning string fields: */
+#define checkassigns(strfield, struct, member, val) do {		\
+		if (strcmp(#member, strfield) == 0) {			\
+			memcpy(struct->member, val, sizeof(struct->member)); \
+			return 0;					\
+		}							\
+	} while(0)
+
+/* for printing numeric fields: */
+#define checkprint(strfield, struct, member) do {		\
+		if (strcmp(#member, strfield) == 0) {		\
+			if (dmode == HEX_MODE)			\
+				printf("0x%llx\n",		\
+				       (unsigned long long)struct->member); \
+			else					\
+				printf("%llu\n",		\
+				       (unsigned long long)struct->member); \
+			return 0;				\
+		}						\
+	} while(0)
+
+/* for printing string fields: */
+#define checkprints(strfield, struct, member) do {		\
+		if (strcmp(#member, strfield) == 0) {		\
+			printf("%s\n", struct->member);		\
+			return 0;				\
+		}						\
+	} while(0)
+
+int gfs2_dinode_printval(struct gfs2_dinode *di, const char *strfield)
+{
+	checkprint(strfield, di, di_mode);
+	checkprint(strfield, di, di_uid);
+	checkprint(strfield, di, di_gid);
+	checkprint(strfield, di, di_nlink);
+	checkprint(strfield, di, di_size);
+	checkprint(strfield, di, di_blocks);
+	checkprint(strfield, di, di_atime);
+	checkprint(strfield, di, di_mtime);
+	checkprint(strfield, di, di_ctime);
+	checkprint(strfield, di, di_major);
+	checkprint(strfield, di, di_minor);
+	checkprint(strfield, di, di_goal_meta);
+	checkprint(strfield, di, di_goal_data);
+	checkprint(strfield, di, di_flags);
+	checkprint(strfield, di, di_payload_format);
+	checkprint(strfield, di, di_height);
+	checkprint(strfield, di, di_depth);
+	checkprint(strfield, di, di_entries);
+	checkprint(strfield, di, di_eattr);
+
+	return -1;
+}
+
+int gfs2_dinode_assignval(struct gfs2_dinode *di, const char *strfield,
+			  uint64_t value)
+{
+	checkassign(strfield, di, di_mode, value);
+	checkassign(strfield, di, di_uid, value);
+	checkassign(strfield, di, di_gid, value);
+	checkassign(strfield, di, di_nlink, value);
+	checkassign(strfield, di, di_size, value);
+	checkassign(strfield, di, di_blocks, value);
+	checkassign(strfield, di, di_atime, value);
+	checkassign(strfield, di, di_mtime, value);
+	checkassign(strfield, di, di_ctime, value);
+	checkassign(strfield, di, di_major, value);
+	checkassign(strfield, di, di_minor, value);
+	checkassign(strfield, di, di_goal_meta, value);
+	checkassign(strfield, di, di_goal_data, value);
+	checkassign(strfield, di, di_flags, value);
+	checkassign(strfield, di, di_payload_format, value);
+	checkassign(strfield, di, di_height, value);
+	checkassign(strfield, di, di_depth, value);
+	checkassign(strfield, di, di_entries, value);
+	checkassign(strfield, di, di_eattr, value);
+
+	return -1;
+}
+
+int gfs2_rgrp_printval(struct gfs2_rgrp *rg, const char *strfield)
+{
+	checkprint(strfield, rg, rg_flags);
+	checkprint(strfield, rg, rg_free);
+	checkprint(strfield, rg, rg_dinodes);
+
+	return -1;
+}
+
+int gfs2_rgrp_assignval(struct gfs2_rgrp *rg, const char *strfield,
+			uint64_t value)
+{
+	checkassign(strfield, rg, rg_flags, value);
+	checkassign(strfield, rg, rg_free, value);
+	checkassign(strfield, rg, rg_dinodes, value);
+
+	return -1;
+}
+
 /* ------------------------------------------------------------------------ */
 /* UpdateSize - screen size changed, so update it                           */
 /* ------------------------------------------------------------------------ */
@@ -348,6 +460,67 @@ int get_block_type(const char *lpBuffer)
 	return ret_type;
 }
 
+/*
+ * fs_get_bitmap - get value of FS bitmap
+ * @sdp: super block
+ * @blkno: block number relative to file system
+ *
+ * This function gets the value of a bit of the
+ * file system bitmap.
+ * Possible state values for a block in the bitmap are:
+ *  GFS_BLKST_FREE     (0)
+ *  GFS_BLKST_USED     (1)
+ *  GFS_BLKST_INVALID  (2)
+ *  GFS_BLKST_DINODE   (3)
+ *
+ * Returns: state on success, -1 on error
+ */
+int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
+					struct rgrp_list *rgd)
+{
+	int           buf, val;
+	uint32_t        rgrp_block;
+	struct gfs2_bitmap	*bits = NULL;
+	unsigned int  bit;
+	unsigned char *byte;
+	int local_rgd = 0;
+
+	if(gfs2_check_range(sdp, blkno))
+		return -1;
+	if(rgd == NULL) {
+		local_rgd = 1;
+		rgd = gfs2_blk2rgrpd(sdp, blkno);
+	}
+	if(rgd == NULL)
+		return -1;
+	if(gfs2_rgrp_read(sdp, rgd))
+		return -1;
+
+	rgrp_block = (uint32_t)(blkno - rgd->ri.ri_data0);
+
+	for(buf= 0; buf < rgd->ri.ri_length; buf++){
+		bits = &(rgd->bits[buf]);
+		if(rgrp_block < ((bits->bi_start + bits->bi_len)*GFS2_NBBY)){
+			break;
+		}
+	}
+
+	if(buf >= rgd->ri.ri_length){
+		gfs2_rgrp_relse(rgd, not_updated);
+		return -1;
+	}
+
+	byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
+		(rgrp_block/GFS2_NBBY - bits->bi_start);
+	bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
+
+	val = ((*byte >> bit) & GFS2_BIT_MASK);
+	if(local_rgd)
+		gfs2_rgrp_relse(rgd, not_updated);
+
+	return val;
+}
+
 /* ------------------------------------------------------------------------ */
 /* display_block_type                                                       */
 /* returns: metatype if block is a GFS2 structure block type                */
@@ -465,32 +638,41 @@ int display_block_type(const char *lpBuffer, int from_restore)
 	if (from_restore)
 		return ret_type;
 	if (termlines && dmode == HEX_MODE) {
-		/* calculate how much of the buffer we can fit on screen */
+		int type;
+		struct rgrp_list *rgd;
+
+		rgd = gfs2_blk2rgrpd(&sbd, block);
+		if (rgd) {
+			type = gfs2_get_bitmap(&sbd, block, rgd);
+			gfs2_rgrp_relse(rgd, not_updated);
+		} else
+			type = 4;
 		screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
 		if (!screen_chunk_size)
 			screen_chunk_size = 256;
-		print_gfs2("(p.%d of %d)", (offset / screen_chunk_size) + 1,
-				   (sbd.bsize % screen_chunk_size) > 0 ?
-				   sbd.bsize / screen_chunk_size + 1 : sbd.bsize /
-				   screen_chunk_size);
+		print_gfs2("(p.%d of %d--%s)",
+			   (offset / screen_chunk_size) + 1,
+			   (sbd.bsize % screen_chunk_size) > 0 ?
+			   sbd.bsize / screen_chunk_size + 1 : sbd.bsize /
+			   screen_chunk_size, allocdesc[type]);
 		/*eol(9);*/
 	}
 	if (block == sbd.sd_sb.sb_root_dir.no_addr)
-		print_gfs2("-------------------- Root directory ------------------");
+		print_gfs2("--------------- Root directory ------------------");
 	else if (!gfs1 && block == sbd.sd_sb.sb_master_dir.no_addr)
-		print_gfs2("------------------- Master directory -----------------");
+		print_gfs2("-------------- Master directory -----------------");
 	else if (!gfs1 && block == RGLIST_DUMMY_BLOCK)
-		print_gfs2("----------------------- RG List ----------------------");
+		print_gfs2("------------------ RG List ----------------------");
 	else {
 		if (gfs1) {
 			if (block == sbd1->sb_rindex_di.no_addr)
-				print_gfs2("--------------------- rindex file -------------------");
+				print_gfs2("---------------- rindex file -------------------");
 			else if (block == gfs1_quota_di.no_addr)
-				print_gfs2("--------------------- Quota file --------------------");
+				print_gfs2("---------------- Quota file --------------------");
 			else if (block == sbd1->sb_jindex_di.no_addr)
-				print_gfs2("-------------------- Journal Index ------------------");
+				print_gfs2("--------------- Journal Index ------------------");
 			else if (block == gfs1_license_di.no_addr)
-				print_gfs2("-------------------- License file -------------------");
+				print_gfs2("--------------- License file -------------------");
 		}
 		else {
 			int d;
@@ -498,17 +680,17 @@ int display_block_type(const char *lpBuffer, int from_restore)
 			for (d = 2; d < 8; d++) {
 				if (block == masterdir.dirent[d].block) {
 					if (!strncmp(masterdir.dirent[d].filename, "jindex", 6))
-						print_gfs2("-------------------- Journal Index ------------------");
+						print_gfs2("--------------- Journal Index ------------------");
 					else if (!strncmp(masterdir.dirent[d].filename, "per_node", 8))
-						print_gfs2("-------------------- Per-node Dir -------------------");
+						print_gfs2("--------------- Per-node Dir -------------------");
 					else if (!strncmp(masterdir.dirent[d].filename, "inum", 4))
-						print_gfs2("--------------------- Inum file ---------------------");
+						print_gfs2("---------------- Inum file ---------------------");
 					else if (!strncmp(masterdir.dirent[d].filename, "statfs", 6))
-						print_gfs2("--------------------- statfs file -------------------");
+						print_gfs2("---------------- statfs file -------------------");
 					else if (!strncmp(masterdir.dirent[d].filename, "rindex", 6))
-						print_gfs2("--------------------- rindex file -------------------");
+						print_gfs2("---------------- rindex file -------------------");
 					else if (!strncmp(masterdir.dirent[d].filename, "quota", 5))
-						print_gfs2("--------------------- Quota file --------------------");
+						print_gfs2("---------------- Quota file --------------------");
 				}
 			}
 		}
@@ -634,19 +816,10 @@ static int risize(void)
 /* ------------------------------------------------------------------------ */
 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.buf_list, block);
-	riinode = inode_get(&sbd, ribh);
 	printf("%lld RGs in this file system.\n",
-	       (unsigned long long)riinode->i_di.di_size / risize());
-	inode_put(riinode, not_updated);
+	       (unsigned long long)sbd.md.riinode->i_di.di_size / risize());
+	inode_put(sbd.md.riinode, not_updated);
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
 	exit(EXIT_SUCCESS);
 }
 
@@ -899,7 +1072,7 @@ void gfs_jindex_in(struct gfs_jindex *jindex, char *buf)
 /* ------------------------------------------------------------------------ */
 void gfs_jindex_print(struct gfs_jindex *ji)
 {
-        pv(ji, ji_addr, "%llu", "0x%llx");
+        pv((unsigned long long)ji, ji_addr, "%llu", "0x%llx");
         pv(ji, ji_nsegment, "%u", "0x%x");
         pv(ji, ji_pad, "%u", "0x%x");
 }
@@ -932,6 +1105,7 @@ int print_jindex(struct gfs2_inode *di)
 		     lines_per_row[dmode] <= termlines - start_line - 2)) {
 			if (edit_row[dmode] == print_entry_ndx) {
 				COLORS_HIGHLIGHT;
+				strcpy(efield, "ji_addr");
 				sprintf(estring, "%" PRIx64, ji.ji_addr);
 			}
 			print_gfs2("Journal #%d", print_entry_ndx);
@@ -952,8 +1126,15 @@ int print_jindex(struct gfs2_inode *di)
 int print_inum(struct gfs2_inode *di)
 {
 	uint64_t buf, inodenum;
+	int rc;
 	
-	if (gfs2_readi(di, (void *)&buf, 0, sizeof(buf)) != sizeof(buf)) {
+	rc = gfs2_readi(di, (void *)&buf, 0, sizeof(buf));
+	if (!rc) {
+		print_gfs2("The inum file is empty.");
+		eol(0);
+		return 0;
+	}
+	if (rc != sizeof(buf)) {
 		print_gfs2("Error reading inum file.");
 		eol(0);
 		return -1;
@@ -970,8 +1151,15 @@ int print_inum(struct gfs2_inode *di)
 int print_statfs(struct gfs2_inode *di)
 {
 	struct gfs2_statfs_change buf, sfc;
+	int rc;
 	
-	if (gfs2_readi(di, (void *)&buf, 0, sizeof(buf)) !=	sizeof(buf)) {
+	rc = gfs2_readi(di, (void *)&buf, 0, sizeof(buf));
+	if (!rc) {
+		print_gfs2("The statfs file is empty.");
+		eol(0);
+		return 0;
+	}
+	if (rc != sizeof(buf)) {
 		print_gfs2("Error reading statfs file.");
 		eol(0);
 		return -1;
@@ -1086,9 +1274,8 @@ int display_leaf(struct iinfo *ind)
 			eol(5);
 			if (termlines) {
 				if (edit_row[dmode] >=0 &&
-				    line - start_line - 1 == 
-				    edit_row[dmode] -
-				    start_row[dmode]) {
+				    line - start_line - 1 ==
+				    edit_row[dmode] - start_row[dmode]) {
 					COLORS_HIGHLIGHT;
 					sprintf(estring, "%"PRIx64,
 						ind->ii[0].dirent[d].block);
@@ -1262,10 +1449,20 @@ int display_indirect(struct iinfo *ind, int indblocks, int level, uint64_t start
 			more_indir = malloc(sizeof(struct iinfo));
 			tmpbuf = malloc(sbd.bsize);
 			if (tmpbuf) {
-				do_lseek(sbd.device_fd,
-					 ind->ii[pndx].block * sbd.bsize);
-				do_read(sbd.device_fd, tmpbuf,
-					sbd.bsize); /* read in the desired block */
+				lseek(sbd.device_fd,
+				      ind->ii[pndx].block * sbd.bsize,
+				      SEEK_SET);
+				/* read in the desired block */
+				if (read(sbd.device_fd, tmpbuf, sbd.bsize) !=
+				    sbd.bsize) {
+					fprintf(stderr, "bad read: %s from %s:"
+						"%d: block %lld (0x%llx)\n",
+						strerror(errno),
+						__FUNCTION__, __LINE__,
+						(unsigned long long)ind->ii[pndx].block,
+						(unsigned long long)ind->ii[pndx].block);
+					exit(-1);
+				}
 				memset(more_indir, 0, sizeof(struct iinfo));
 				if (S_ISDIR(di.di_mode)) {
 					do_leaf_extended(tmpbuf, more_indir);
@@ -1342,6 +1539,8 @@ int block_is_inum_file(void)
 /* ------------------------------------------------------------------------ */
 int block_is_statfs_file(void)
 {
+	if (gfs1 && block == gfs1_license_di.no_addr)
+		return TRUE;
 	if (!gfs1 && block == masterblock("statfs"))
 		return TRUE;
 	return FALSE;
@@ -1352,8 +1551,9 @@ int block_is_statfs_file(void)
 /* ------------------------------------------------------------------------ */
 int block_is_quota_file(void)
 {
-	if ((gfs1 && block == gfs1_quota_di.no_addr) ||
-	    (block == masterblock("quota")))
+	if (gfs1 && block == gfs1_quota_di.no_addr)
+		return TRUE;
+	if (!gfs1 && block == masterblock("quota"))
 		return TRUE;
 	return FALSE;
 }
@@ -1436,10 +1636,16 @@ int display_extended(void)
 /* ------------------------------------------------------------------------ */
 void read_superblock(int fd)
 {
+	int count;
+
 	sbd1 = (struct gfs_sb *)&sbd.sd_sb;
 	ioctl(fd, BLKFLSBUF, 0);
-	do_lseek(fd, 0x10 * 4096);
-	do_read(fd, buf, sbd.bsize); /* read in the desired block */
+	lseek(fd, 0x10 * 4096, SEEK_SET);
+	if (read(fd, buf, sbd.bsize) != sbd.bsize) {
+		fprintf(stderr, "bad read: %s from %s:%d: superblock\n",
+			strerror(errno), __FUNCTION__, __LINE__);
+		exit(-1);
+	}
 	memset(&sbd, 0, sizeof(struct gfs2_sbd));
 	sbd.device_fd = fd;
 	sbd.bsize = GFS2_DEFAULT_BSIZE;
@@ -1472,6 +1678,27 @@ void read_superblock(int fd)
 		sbd.bsize = GFS2_DEFAULT_BSIZE;
 	compute_constants(&sbd);
 	block = 0x10 * (GFS2_DEFAULT_BSIZE / sbd.bsize);
+	device_geometry(&sbd);
+	fix_device_geometry(&sbd);
+	if(gfs1) {
+		sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs_indirect)) /
+			sizeof(uint64_t);
+		sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs_dinode)) /
+			sizeof(uint64_t);
+		sbd.md.riinode = gfs2_load_inode(&sbd,
+						 sbd1->sb_rindex_di.no_addr);
+	} else {
+		sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs2_meta_header)) /
+			sizeof(uint64_t);
+		sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs2_dinode)) /
+			sizeof(uint64_t);
+		sbd.master_dir = gfs2_load_inode(&sbd,
+					    sbd.sd_sb.sb_master_dir.no_addr);
+		gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode);
+	}
+
+	sbd.fssize = sbd.device.length;
+	ri_update(&sbd, 0, &count);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -1480,8 +1707,17 @@ void read_superblock(int fd)
 void read_master_dir(void)
 {
 	ioctl(sbd.device_fd, BLKFLSBUF, 0);
-	do_lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * sbd.bsize);
-	do_read(sbd.device_fd, buf, sbd.bsize); /* read in the desired block */
+	lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * sbd.bsize,
+	      SEEK_SET);
+	if (read(sbd.device_fd, buf, sbd.bsize) != sbd.bsize) {
+		fprintf(stderr, "read error: %s from %s:%d: "
+			"master dir block %lld (0x%llx)\n",
+			strerror(errno), __FUNCTION__,
+			__LINE__,
+			(unsigned long long)sbd.sd_sb.sb_master_dir.no_addr,
+			(unsigned long long)sbd.sd_sb.sb_master_dir.no_addr);
+		exit(-1);
+	}
 	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));
@@ -1508,8 +1744,16 @@ int display(int identify_only)
 	if (block_in_mem != blk) { /* If we changed blocks from the last read */
 		dev_offset = blk * sbd.bsize;
 		ioctl(sbd.device_fd, BLKFLSBUF, 0);
-		do_lseek(sbd.device_fd, dev_offset);
-		do_read(sbd.device_fd, buf, sbd.bsize); /* read desired block */
+		lseek(sbd.device_fd, dev_offset, SEEK_SET);
+		if (read(sbd.device_fd, buf, sbd.bsize) != sbd.bsize) {
+			fprintf(stderr, "read error: %s from %s:%d: "
+				"offset %lld (0x%llx)\n",
+				strerror(errno), __FUNCTION__,
+				__LINE__,
+				(unsigned long long)dev_offset,
+				(unsigned long long)dev_offset);
+			exit(-1);
+		}
 		block_in_mem = blk; /* remember which block is in memory */
 	}
 	line = 1;
@@ -1679,6 +1923,145 @@ uint64_t find_journal_block(const char *journal, uint64_t *j_size)
 }
 
 /* ------------------------------------------------------------------------ */
+/* Find next metadata block of a given type AFTER a given point in the fs   */
+/*                                                                          */
+/* This is used to find blocks that aren't represented in the bitmaps, such */
+/* as the RGs and bitmaps or the superblock.                                */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype_slow(uint64_t startblk, int metatype, int print)
+{
+	uint64_t blk, last_fs_block;
+	int found = 0;
+	struct gfs2_buffer_head *bh;
+
+	last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize;
+	for (blk = startblk + 1; blk < last_fs_block; blk++) {
+		bh = bread(&sbd.buf_list, blk);
+		/* Can't use get_block_type here (returns false "none") */
+		if (bh->b_data[0] == 0x01 && bh->b_data[1] == 0x16 &&
+		    bh->b_data[2] == 0x19 && bh->b_data[3] == 0x70 &&
+		    bh->b_data[4] == 0x00 && bh->b_data[5] == 0x00 &&
+		    bh->b_data[6] == 0x00 && bh->b_data[7] == metatype) {
+			found = 1;
+			brelse(bh, not_updated);
+			break;
+		}
+		brelse(bh, not_updated);
+	}
+	if (!found)
+		blk = 0;
+	if (print) {
+		if (dmode == HEX_MODE)
+			printf("0x%llx\n", (unsigned long long)blk);
+		else
+			printf("%llu\n", (unsigned long long)blk);
+	}
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
+	if (print)
+		exit(0);
+	return blk;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find next "metadata in use" block AFTER a given point in the fs          */
+/*                                                                          */
+/* This version does its magic by searching the bitmaps of the RG.  After   */
+/* all, if we're searching for a dinode, we want a real allocated inode,    */
+/* not just some block that used to be an inode in a previous incarnation.  */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype_rg(uint64_t startblk, int metatype, int print)
+{
+	uint64_t blk;
+	int first = 1, found = 0;
+	struct rgrp_list *rgd;
+	struct gfs2_rindex *ri;
+	osi_list_t *tmp;
+
+	blk = 0;
+	/* Skip the rgs prior to the block we've been given */
+	for(tmp = sbd.rglist.next; tmp != &sbd.rglist; tmp = tmp->next){
+		rgd = osi_list_entry(tmp, struct rgrp_list, list);
+		ri = &rgd->ri;
+		if (first && startblk <= ri->ri_data0) {
+			startblk = ri->ri_data0;
+			break;
+		} else if (ri->ri_addr <= startblk &&
+			 startblk < ri->ri_data0 + ri->ri_data)
+			break;
+		else
+			rgd = NULL;
+		first = 0;
+	}
+	if (!rgd) {
+		if (print)
+			printf("0\n");
+		gfs2_rgrp_free(&sbd.rglist, not_updated);
+		if (print)
+			exit(-1);
+	}
+	for(; !found && tmp != &sbd.rglist; tmp = tmp->next){
+		rgd = osi_list_entry(tmp, struct rgrp_list, list);	
+		first = 1;
+		do {
+			if (gfs2_next_rg_metatype(&sbd, rgd, &blk, metatype,
+						  first))
+				break;
+			if (blk > startblk) {
+				found = 1;
+				break;
+			}
+			first = 0;
+		} while (blk <= startblk);
+	}
+	if (!found)
+		blk = 0;
+	if (print) {
+		if (dmode == HEX_MODE)
+			printf("0x%llx\n", (unsigned long long)blk);
+		else
+			printf("%llu\n", (unsigned long long)blk);
+	}
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
+	if (print)
+		exit(0);
+	return blk;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find next metadata block AFTER a given point in the fs                   */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype(const char *strtype, int print)
+{
+	int mtype = 0;
+	uint64_t startblk, blk = 0;
+
+	if (print)
+		startblk = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	else
+		startblk = block;
+
+	for (mtype = GFS2_METATYPE_NONE;
+	     mtype <= GFS2_METATYPE_QC; mtype++)
+		if (!strcasecmp(strtype, mtypes[mtype]))
+			break;
+	if (!strcmp(strtype, "dinode"))
+		mtype = GFS2_METATYPE_DI;
+	if (mtype >= GFS2_METATYPE_NONE && mtype <= GFS2_METATYPE_RB)
+		blk = find_metablockoftype_slow(startblk, mtype, print);
+	else if (mtype >= GFS2_METATYPE_DI && mtype <= GFS2_METATYPE_QC)
+		blk = find_metablockoftype_rg(startblk, mtype, print);
+	else if (print) {
+		fprintf(stderr, "Error: metadata type not "
+			"specified: must be one of:\n");
+		fprintf(stderr, "sb rg rb di in lf jd lh ld"
+			" ea ed lb 13 qc\n");
+		gfs2_rgrp_free(&sbd.rglist, not_updated);
+		exit(-1);
+	}
+	return blk;
+}
+
+/* ------------------------------------------------------------------------ */
 /* Check if the word is a keyword such as "sb" or "rindex"                  */
 /* Returns: block number if it is, else 0                                   */
 /* ------------------------------------------------------------------------ */
@@ -1733,7 +2116,9 @@ uint64_t check_keywords(const char *kword)
 		uint64_t j_size;
 
 		blk = find_journal_block(kword, &j_size);
-	} else if (kword[0]=='0' && kword[1]=='x') /* hex addr */
+	} else if (kword[0]=='/') /* search */
+		blk = find_metablockoftype(&kword[1], 0);
+	else if (kword[0]=='0' && kword[1]=='x') /* hex addr */
 		sscanf(kword, "%"SCNx64, &blk);/* retrieve in hex */
 	else
 		sscanf(kword, "%" PRIu64, &blk); /* retrieve decimal */
@@ -1752,7 +2137,7 @@ uint64_t goto_block(void)
 	memset(string, 0, sizeof(string));
 	sprintf(string,"%"PRId64, block);
 	if (bobgets(string, 1, 7, 16, &ch)) {
-		if (isalnum(string[0]))
+		if (isalnum(string[0]) || string[0] == '/')
 			temp_blk = check_keywords(string);
 		else if (string[0] == '+') {
 			if (string[1] == '0' && string[2] == 'x')
@@ -1844,8 +2229,17 @@ void hex_edit(int *exitch)
 					ch += (estring[i+1] - 'A' + 0x0a);
 				buf[offset + hexoffset] = ch;
 			}
-			do_lseek(sbd.device_fd, dev_offset);
-			do_write(sbd.device_fd, buf, sbd.bsize);
+			lseek(sbd.device_fd, dev_offset, SEEK_SET);
+			if (write(sbd.device_fd, buf, sbd.bsize) !=
+			    sbd.bsize) {
+				fprintf(stderr, "write error: %s from %s:%d: "
+					"offset %lld (0x%llx)\n",
+					strerror(errno),
+					__FUNCTION__, __LINE__,
+					(unsigned long long)dev_offset,
+					(unsigned long long)dev_offset);
+				exit(-1);
+			}
 			fsync(sbd.device_fd);
 		}
 	}
@@ -1944,6 +2338,196 @@ void jump(void)
 }
 
 /* ------------------------------------------------------------------------ */
+/* print block type                                                         */
+/* ------------------------------------------------------------------------ */
+void print_block_type(uint64_t block, int type, const char *additional)
+{
+	if (type <= GFS2_METATYPE_QC)
+		printf("%d (Block %lld is type %d: %s%s)\n", type,
+		       (unsigned long long)block, type, block_type_str[type],
+		       additional);
+	else
+		printf("%d (Block %lld is type %d: unknown%s)\n", type,
+		       (unsigned long long)block, type, additional);
+}
+
+/* ------------------------------------------------------------------------ */
+/* find_print block type                                                    */
+/* ------------------------------------------------------------------------ */
+void find_print_block_type(void)
+{
+	uint64_t block;
+	struct gfs2_buffer_head *bh;
+	int type;
+
+	block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	bh = bread(&sbd.buf_list, block);
+	type = get_block_type(bh->b_data);
+	print_block_type(block, type, "");
+	brelse(bh, NOT_UPDATED);
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
+	exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find and print the resource group associated with a given block          */
+/* ------------------------------------------------------------------------ */
+void find_print_block_rg(int bitmap)
+{
+	uint64_t block, rgblock;
+	int i;
+	struct rgrp_list *rgd;
+
+	block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	if (block == sbd.sb_addr)
+		printf("0 (the superblock is not in the bitmap)\n");
+	else {
+		rgd = gfs2_blk2rgrpd(&sbd, block);
+		if (rgd) {
+			rgblock = rgd->ri.ri_addr;
+			if (bitmap) {
+				struct gfs2_bitmap *bits = NULL;
+
+				for (i = 0; i < rgd->ri.ri_length; i++) {
+					bits = &(rgd->bits[i]);
+					if (block - rgd->ri.ri_data0 <
+					    ((bits->bi_start + bits->bi_len) *
+					     GFS2_NBBY)) {
+						break;
+					}
+				}
+				if (i < rgd->ri.ri_length)
+					rgblock += i;
+
+			}
+			if (dmode == HEX_MODE)
+				printf("0x%llx\n",(unsigned long long)rgblock);
+			else
+				printf("%llu\n", (unsigned long long)rgblock);
+		} else {
+			printf("-1 (block invalid or part of an rgrp).\n");
+		}
+	}
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
+	exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* find/change/print block allocation (what the bitmap says about block)    */
+/* ------------------------------------------------------------------------ */
+void find_change_block_alloc(int *newval)
+{
+	uint64_t block;
+	int type;
+	struct rgrp_list *rgd;
+
+	if (newval &&
+	    (*newval < GFS2_BLKST_FREE || *newval > GFS2_BLKST_DINODE)) {
+		int i;
+
+		printf("Error: value %d is not valid.\nValid values are:\n",
+		       *newval);
+		for (i = GFS2_BLKST_FREE; i <= GFS2_BLKST_DINODE; i++)
+			printf("%d - %s\n", i, allocdesc[i]);
+		gfs2_rgrp_free(&sbd.rglist, not_updated);
+		exit(-1);
+	}
+	block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	if (block == sbd.sb_addr)
+		printf("3 (the superblock is not in the bitmap)\n");
+	else {
+		if (newval) {
+			if (gfs2_set_bitmap(&sbd, block, *newval))
+				printf("-1 (block invalid or part of an rgrp).\n");
+			else
+				printf("%d\n", *newval);
+		} else {
+			rgd = gfs2_blk2rgrpd(&sbd, block);
+			if (rgd) {
+				type = gfs2_get_bitmap(&sbd, block, rgd);
+				printf("%d (%s)\n", type, allocdesc[type]);
+				gfs2_rgrp_relse(rgd, not_updated);
+			} else {
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				printf("-1 (block invalid or part of an rgrp).\n");
+				exit(-1);
+			}
+		}
+	}
+	gfs2_rgrp_free(&sbd.rglist, (newval) ? updated : not_updated);
+	if (newval)
+		bcommit(&sbd.nvbuf_list);
+	exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* process request to print a certain field from a previously pushed block  */
+/* ------------------------------------------------------------------------ */
+void process_field(const char *field, uint64_t *newval, int print_field)
+{
+	uint64_t block;
+	struct gfs2_buffer_head *bh;
+	int type;
+	struct gfs2_rgrp rg;
+
+	block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	bh = bread(&sbd.buf_list, block);
+	type = get_block_type(bh->b_data);
+	switch (type) {
+	case GFS2_METATYPE_SB:
+		if (print_field)
+			print_block_type(block, type,
+					 " which is not implemented");
+		break;
+	case GFS2_METATYPE_RG:
+		gfs2_rgrp_in(&rg, bh->b_data);
+		if (newval) {
+			gfs2_rgrp_assignval(&rg, field, *newval);
+			gfs2_rgrp_out(&rg, bh->b_data);
+			if (print_field)
+				gfs2_rgrp_printval(&rg, field);
+		} else {
+			if (print_field && gfs2_rgrp_printval(&rg, field))
+				printf("Field '%s' not found.\n", field);
+		}
+		break;
+	case GFS2_METATYPE_RB:
+		if (print_field)
+			print_block_type(block, type,
+					 " which is not implemented");
+		break;
+	case GFS2_METATYPE_DI:
+		gfs2_dinode_in(&di, bh->b_data);
+		if (newval) {
+			gfs2_dinode_assignval(&di, field, *newval);
+			gfs2_dinode_out(&di, bh->b_data);
+			if (print_field)
+				gfs2_dinode_printval(&di, field);
+		} else {
+			if (print_field && gfs2_dinode_printval(&di, field))
+				printf("Field '%s' not found.\n", field);
+		}
+		break;
+	case GFS2_METATYPE_IN:
+	case GFS2_METATYPE_LF:
+	case GFS2_METATYPE_JD:
+	case GFS2_METATYPE_LH:
+	case GFS2_METATYPE_LD:
+	case GFS2_METATYPE_EA:
+	case GFS2_METATYPE_ED:
+	case GFS2_METATYPE_LB:
+	case GFS2_METATYPE_QC:
+	default:
+		if (print_field)
+			print_block_type(block, type,
+					 " which is not implemented");
+		break;
+	}
+	brelse(bh, newval ? UPDATED : NOT_UPDATED);
+	bcommit(&sbd.buf_list);
+}
+
+/* ------------------------------------------------------------------------ */
 /* interactive_mode - accept keystrokes from user and display structures    */
 /* ------------------------------------------------------------------------ */
 void interactive_mode(void)
@@ -1977,10 +2561,20 @@ void interactive_mode(void)
 			else {
 				if (dmode == HEX_MODE)
 					hex_edit(&ch);
-				else if (dmode == GFS2_MODE)
+				else if (dmode == GFS2_MODE) {
+					uint64_t val;
+
 					bobgets(estring, edit_row[dmode]+4, 24,
-						edit_size[dmode], &ch);
-				else
+						10, &ch);
+					if (estring[0] == '0' &&
+					    estring[1] == 'x')
+						sscanf(estring, "%"SCNx64,
+						       &val);
+					else
+						val = (uint64_t)atoll(estring);
+					process_field(efield, &val, 0);
+					block_in_mem = -1;
+				} else
 					bobgets(estring, edit_row[dmode]+6, 14,
 						edit_size[dmode], &ch);
 			}
@@ -2226,10 +2820,10 @@ 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");
+	pv((unsigned long long)lh, lh_first, "%llu", "%llx");
+	pv((unsigned long long)lh, lh_sequence, "%llu", "%llx");
+	pv((unsigned long long)lh, lh_tail, "%llu", "%llx");
+	pv((unsigned long long)lh, lh_last_dump, "%llu", "%llx");
 }
 
 /* ------------------------------------------------------------------------ */
@@ -2289,8 +2883,8 @@ int fsck_readi(struct gfs2_inode *ip, void *buf, uint64_t offset,
 	if (!size)
 		return 0;
 	if (isdir) {
-		lblock = offset;
-		o = do_div(lblock, sdp->sd_jbsize);
+		o = offset % sdp->sd_jbsize;
+		lblock = offset / sdp->sd_jbsize;
 	} else {
 		lblock = offset >> sdp->sd_sb.sb_bsize_shift;
 		o = offset & (sdp->bsize - 1);
@@ -2474,7 +3068,7 @@ void dump_journal(const char *journal)
 /* ------------------------------------------------------------------------ */
 void usage(void)
 {
-	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /dev/device\n\n");
+	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks][blocktype][blockalloc [val]][blockbits][blockrg][find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc][field <f>[val]] /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,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
@@ -2500,6 +3094,20 @@ void usage(void)
 	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,"     0x1234 - prints the specified block\n");
+	fprintf(stderr,"-p   <block> blocktype - prints the type "
+		"of the specified block\n");
+	fprintf(stderr,"-p   <block> blockrg - prints the resource group "
+		"block corresponding to the specified block\n");
+	fprintf(stderr,"-p   <block> blockbits - prints the block with "
+		"the bitmap corresponding to the specified block\n");
+	fprintf(stderr,"-p   <block> blockalloc [0|1|2|3] - print or change "
+		"the allocation type of the specified block\n");
+	fprintf(stderr,"-p   <block> field [new_value] - prints or change the "
+		"structure field\n");
+	fprintf(stderr,"-p   <b> find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|"
+		"13|qc - find block of given type after block <b>\n");
+	fprintf(stderr,"     <b> specifies the starting block for search\n");
 	fprintf(stderr,"-s   specifies a starting block such as root, rindex, quota, inum.\n");
 	fprintf(stderr,"-x   print in hexmode.\n");
 	fprintf(stderr,"-h   prints this help.\n\n");
@@ -2514,6 +3122,16 @@ void usage(void)
 	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 print out the metadata type of block 1234\n");
+	fprintf(stderr,"     gfs2_edit -p 1234 blocktype /dev/roth_vg/roth_lb\n");
+	fprintf(stderr,"   To print out the allocation type of block 2345\n");
+	fprintf(stderr,"     gfs2_edit -p 2345 blockalloc /dev/vg/lv\n");
+	fprintf(stderr,"   To change the allocation type of block 2345 to a 'free block'\n");
+	fprintf(stderr,"     gfs2_edit -p 2345 blockalloc 0 /dev/vg/lv\n");
+	fprintf(stderr,"   To print out the file size of the dinode at block 0x118\n");
+	fprintf(stderr,"     gfs2_edit -p 0x118 field di_size /dev/roth_vg/roth_lb\n");
+	fprintf(stderr,"   To find any dinode higher than the quota file dinode:\n");
+	fprintf(stderr,"     gfs2_edit -p quota find di /dev/x/y\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");
@@ -2521,6 +3139,55 @@ void usage(void)
 }/* usage */
 
 /* ------------------------------------------------------------------------ */
+/* parameterpass1 - pre-processing for command-line parameters              */
+/* ------------------------------------------------------------------------ */
+void parameterpass1(int argc, char *argv[], int i)
+{
+	if (!strcasecmp(argv[i], "-V")) {
+		printf("%s version %s (built %s %s)\n",
+		       prog_name, GFS2_RELEASE_NAME,
+		       __DATE__, __TIME__);
+		printf("%s\n", REDHAT_COPYRIGHT);
+		exit(0);
+	}
+	else if (!strcasecmp(argv[i], "-h") ||
+		 !strcasecmp(argv[i], "-help") ||
+		 !strcasecmp(argv[i], "-usage")) {
+		usage();
+		exit(0);
+	}
+	else if (!strcasecmp(argv[i], "-c")) {
+		i++;
+		color_scheme = atoi(argv[i]);
+	}
+	else if (!strcasecmp(argv[i], "-p") ||
+		 !strcasecmp(argv[i], "-print")) {
+		termlines = 0; /* initial value--we'll figure
+				  it out later */
+		dmode = GFS2_MODE;
+	}
+	else if (!strcasecmp(argv[i], "savemeta"))
+		termlines = 0;
+	else if (!strcasecmp(argv[i], "savemetaslow"))
+		termlines = 0;
+	else if (!strcasecmp(argv[i], "savergs"))
+		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], 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]);
+}
+
+/* ------------------------------------------------------------------------ */
 /* process_parameters - process commandline parameters                      */
 /* pass - we make two passes through the parameters; the first pass gathers */
 /*        normals parameters, device name, etc.  The second pass is for     */
@@ -2529,156 +3196,163 @@ void usage(void)
 void process_parameters(int argc, char *argv[], int pass)
 {
 	int i;
+	uint64_t keyword_blk;
 
 	if (argc < 2) {
 		usage();
 		die("no device specified\n");
 	}
 	for (i = 1; i < argc; i++) {
-		if (!pass) {
-			if (!strcasecmp(argv[i], "-V")) {
-				printf("%s version %s (built %s %s)\n", prog_name,
-					   GFS2_RELEASE_NAME, __DATE__, __TIME__);
-				printf("%s\n", REDHAT_COPYRIGHT);
-				exit(0);
+		if (!pass) { /* first pass */
+			parameterpass1(argc, argv, i);
+			continue;
+		}
+		/* second pass */
+		if (!strcasecmp(argv[i], "-s")) {
+			i++;
+			if (i >= argc - 1) {
+				printf("Error: starting block not specified "
+				       "with -s.\n");
+				printf("%s -s [starting block | keyword] "
+				       "<device>\n", argv[0]);
+				printf("For example: %s -s \"rg 3\" "
+				       "/dev/exxon_vg/exxon_lv\n", argv[0]);
+				exit(EXIT_FAILURE);
 			}
-			else if (!strcasecmp(argv[i], "-h") ||
-					 !strcasecmp(argv[i], "-help") ||
-					 !strcasecmp(argv[i], "-usage")) {
-				usage();
+			starting_blk = check_keywords(argv[i]);
+			continue;
+		}
+		if (termlines || strchr(argv[i],'/')) /* if print or slash */
+			continue;
+			
+		if (!strncmp(argv[i], "journal", 7) &&
+		    isdigit(argv[i][7])) {
+			dump_journal(argv[i]);
+			continue;
+		}
+		keyword_blk = check_keywords(argv[i]);
+		if (keyword_blk)
+			push_block(keyword_blk);
+		else if (!strcasecmp(argv[i], "-x"))
+			dmode = HEX_MODE;
+		else if (argv[i][0] == '-') /* if it starts with a dash */
+			; /* ignore it--meant for pass == 0 */
+		else if (!strcmp(argv[i], "identify"))
+			identify = TRUE;
+		else if (!strcmp(argv[i], "size")) {
+			printf("Device size: %" PRIu64 " (0x%" PRIx64 ")\n",
+			       max_block, max_block);
+			exit(EXIT_SUCCESS);
+		} else if (!strcmp(argv[i], "rgcount"))
+			rgcount();
+		else if (!strcmp(argv[i], "field")) {
+			uint64_t newval;
+
+			i++;
+			if (i >= argc - 1) {
+				printf("Error: field not specified.\n");
+				printf("Format is: %s -p <block> field "
+				       "<field> [newvalue]\n", argv[0]);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				exit(EXIT_FAILURE);
+			}
+			if (isdigit(argv[i + 1][0])) {
+				if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
+					sscanf(argv[i + 1], "%"SCNx64,
+					       &newval);
+				else
+					newval = (uint64_t)atoll(argv[i + 1]);
+				process_field(argv[i], &newval, 1);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				exit(0);
+			} else {
+				process_field(argv[i], NULL, 1);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
 				exit(0);
 			}
-			else if (!strcasecmp(argv[i], "-c")) {
-				i++;
-				color_scheme = atoi(argv[i]);
+		} else if (!strcmp(argv[i], "blocktype")) {
+			find_print_block_type();
+		} else if (!strcmp(argv[i], "blockrg")) {
+			find_print_block_rg(0);
+		} else if (!strcmp(argv[i], "blockbits")) {
+			find_print_block_rg(1);
+		} else if (!strcmp(argv[i], "blockalloc")) {
+			if (isdigit(argv[i + 1][0])) {
+				int newval;
+
+				if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
+					sscanf(argv[i + 1], "%x", &newval);
+				else
+					newval = (uint64_t)atoi(argv[i + 1]);
+				find_change_block_alloc(&newval);
+			} else {
+				find_change_block_alloc(NULL);
 			}
-			else if (!strcasecmp(argv[i], "-p") ||
-					 !strcasecmp(argv[i], "-print")) {
-				termlines = 0; /* initial value--we'll figure it out later */
-				dmode = GFS2_MODE;
+		} else if (!strcmp(argv[i], "find")) {
+			find_metablockoftype(argv[i + 1], 1);
+		} 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]);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				exit(EXIT_FAILURE);
 			}
-			else if (!strcasecmp(argv[i], "savemeta"))
-				termlines = 0;
-			else if (!strcasecmp(argv[i], "savemetaslow"))
-				termlines = 0;
-			else if (!strcasecmp(argv[i], "savergs"))
-				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], 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 */
-			if (!strcasecmp(argv[i], "-s")) {
-				i++;
-				if (i >= argc - 1) {
-					printf("Error: starting block not specified with -s.\n");
-					printf("%s -s [starting block | keyword] <device>\n",
-					       argv[0]);
-					printf("For example: %s -s \"rg 3\" /dev/exxon_vg/exxon_lv\n",
-					       argv[0]);
-					exit(EXIT_FAILURE);
-				}
-				starting_blk = check_keywords(argv[i]);
+			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]);
 			}
-			else if (!termlines && !strchr(argv[i],'/')) { /* if print, no slash */
-				uint64_t keyword_blk;
-
-				if (!strncmp(argv[i], "journal", 7) &&
-				    isdigit(argv[i][7])) {
-					dump_journal(argv[i]);
-					continue;
-				}
-				keyword_blk = check_keywords(argv[i]);
-				if (keyword_blk) {
-					push_block(keyword_blk);
-				}
-				else if (!strcasecmp(argv[i], "-x"))
-					dmode = HEX_MODE;
-				else if (argv[i][0] == '-') /* if it starts with a dash */
-					; /* ignore it--meant for pass == 0 */
-				else if (!strcmp(argv[i], "identify"))
-					identify = TRUE;
-				else if (!strcmp(argv[i], "size"))
-					printf("Device size: %" PRIu64 " (0x%" PRIx64 ")\n",
-						   max_block, max_block);
-				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], 0);
-				else if (!strcasecmp(argv[i], "savemetaslow"))
-					savemeta(argv[i+2], 1);
-				else if (!strcasecmp(argv[i], "savergs"))
-					savemeta(argv[i+2], 2);
-				else if (isdigit(argv[i][0])) { /* decimal addr */
-					sscanf(argv[i], "%"SCNd64, &temp_blk);
-					push_block(temp_blk);
-				}
-				else {
-					fprintf(stderr,"I don't know what '%s' means.\n", argv[i]);
-					usage();
-					exit(0);
-				}
+			set_rgrp_flags(rg, new_flags, set, FALSE);
+			gfs2_rgrp_free(&sbd.rglist, not_updated);
+			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]);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				exit(EXIT_FAILURE);
+			}
+			rg = atoi(argv[i]);
+			if (!strcasecmp(argv[i + 1], "find")) {
+				temp_blk = get_rg_addr(rg);
+				push_block(temp_blk);
+			} else {
+				set_rgrp_flags(rg, 0, FALSE, TRUE);
+				gfs2_rgrp_free(&sbd.rglist, not_updated);
+				exit(EXIT_SUCCESS);
 			}
 		}
+		else if (!strcasecmp(argv[i], "savemeta"))
+			savemeta(argv[i+2], 0);
+		else if (!strcasecmp(argv[i], "savemetaslow"))
+			savemeta(argv[i+2], 1);
+		else if (!strcasecmp(argv[i], "savergs"))
+			savemeta(argv[i+2], 2);
+		else if (isdigit(argv[i][0])) { /* decimal addr */
+			sscanf(argv[i], "%"SCNd64, &temp_blk);
+			push_block(temp_blk);
+		} else {
+			fprintf(stderr,"I don't know what '%s' means.\n",
+				argv[i]);
+			usage();
+			exit(EXIT_FAILURE);
+		}
 	} /* for */
 }/* process_parameters */
 
@@ -2768,5 +3442,6 @@ int main(int argc, char *argv[])
 		free(buf);
 	if (indirect)
 		free(indirect);
+	gfs2_rgrp_free(&sbd.rglist, not_updated);
  	exit(EXIT_SUCCESS);
 }
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index d3a3a9f..a3f2b5d 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -73,6 +73,7 @@ EXTERN int edit_mode INIT(0);
 EXTERN int line;
 EXTERN char edit_fmt[80];
 EXTERN char estring[1024]; /* edit string */
+EXTERN char efield[64];
 EXTERN uint64_t dev_offset INIT(0);
 EXTERN uint64_t max_block INIT(0);
 EXTERN char *buf INIT(NULL);
@@ -103,6 +104,7 @@ EXTERN int gfs1 INIT(0);
 EXTERN int editing INIT(0);
 EXTERN uint64_t temp_blk;
 EXTERN uint64_t starting_blk;
+EXTERN const char *block_type_str[15];
 
 struct gfs_jindex {
         uint64_t ji_addr;       /* starting block of the journal */
@@ -249,16 +251,6 @@ EXTERN enum dsp_mode dmode INIT(HEX_MODE);
 
 /*  Memory macros  */
 
-#define type_zalloc(ptr, type, count) \
-{ \
-  (ptr) = (type *)malloc(sizeof(type) * (count)); \
-  if ((ptr)) \
-    memset((char *)(ptr), 0, sizeof(type) * (count)); \
-  else \
-    die("unable to allocate memory on line %d of file %s\n", \
-	__LINE__, __FILE__); \
-}
-
 #define type_alloc(ptr, type, count) \
 { \
   (ptr) = (type *)malloc(sizeof(type) * (count)); \
diff --git a/gfs2/fsck/fs_bits.h b/gfs2/fsck/fs_bits.h
index 10addf6..15d6679 100644
--- a/gfs2/fsck/fs_bits.h
+++ b/gfs2/fsck/fs_bits.h
@@ -39,9 +39,4 @@ uint32_t gfs2_blkalloc_internal(struct rgrp_list *rgd, uint32_t goal,
 								unsigned char old_state,
 								unsigned char new_state, int do_it);
 
-/* functions with blk #'s that are file system relative */
-int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
-					struct rgrp_list *rgd);
-int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state);
-
 #endif /* __FS_BITS_H__ */
diff --git a/gfs2/libgfs2/fs_bits.c b/gfs2/libgfs2/fs_bits.c
index 024426f..4cd41b4 100644
--- a/gfs2/libgfs2/fs_bits.c
+++ b/gfs2/libgfs2/fs_bits.c
@@ -17,32 +17,6 @@
 
 #include "libgfs2.h"
 
-/**
- * fs_setbit - Set a bit in the bitmaps
- * @buffer: the buffer that holds the bitmaps
- * @buflen: the length (in bytes) of the buffer
- * @block: the block to set
- * @new_state: the new state of the block
- *
- */
-static void gfs2_setbit(unsigned char *buffer, unsigned int buflen,
-						uint32_t block, unsigned char new_state)
-{
-	unsigned char *byte, *end, cur_state;
-	unsigned int bit;
-
-	byte = buffer + (block / GFS2_NBBY);
-	bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
-	end = buffer + buflen;
-
-	if(byte < end) {
-		cur_state = (*byte >> bit) & GFS2_BIT_MASK;
-
-		*byte ^= cur_state << bit;
-		*byte |= new_state << bit;
-	}
-}
-
 uint32_t gfs2_bitfit_core(struct gfs2_sbd *sbp, uint64_t goal, uint64_t start,
 						  uint64_t len, unsigned char old_state,
 						  struct gfs2_block_list *bl)
@@ -179,68 +153,6 @@ int gfs2_check_range(struct gfs2_sbd *sdp, uint64_t blkno)
 }
 
 /*
- * fs_get_bitmap - get value of FS bitmap
- * @sdp: super block
- * @blkno: block number relative to file system
- *
- * This function gets the value of a bit of the
- * file system bitmap.
- * Possible state values for a block in the bitmap are:
- *  GFS_BLKST_FREE     (0)
- *  GFS_BLKST_USED     (1)
- *  GFS_BLKST_INVALID  (2)
- *  GFS_BLKST_DINODE   (3)
- *
- * Returns: state on success, -1 on error
- */
-int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
-					struct rgrp_list *rgd)
-{
-	int           buf, val;
-	uint32_t        rgrp_block;
-	struct gfs2_bitmap	*bits = NULL;
-	unsigned int  bit;
-	unsigned char *byte;
-	int local_rgd = 0;
-
-	if(gfs2_check_range(sdp, blkno))
-		return -1;
-	if(rgd == NULL) {
-		local_rgd = 1;
-		rgd = gfs2_blk2rgrpd(sdp, blkno);
-	}
-	if(rgd == NULL)
-		return -1;
-	if(gfs2_rgrp_read(sdp, rgd))
-		return -1;
-
-	rgrp_block = (uint32_t)(blkno - rgd->ri.ri_data0);
-
-	for(buf= 0; buf < rgd->ri.ri_length; buf++){
-		bits = &(rgd->bits[buf]);
-		if(rgrp_block < ((bits->bi_start + bits->bi_len)*GFS2_NBBY)){
-			break;
-		}
-	}
-
-	if(buf >= rgd->ri.ri_length){
-		gfs2_rgrp_relse(rgd, not_updated);
-		return -1;
-	}
-
-	byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
-		(rgrp_block/GFS2_NBBY - bits->bi_start);
-	bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
-
-	val = ((*byte >> bit) & GFS2_BIT_MASK);
-	if(local_rgd)
-		gfs2_rgrp_relse(rgd, not_updated);
-
-	return val;
-}
-
-
-/*
  * fs_set_bitmap
  * @sdp: super block
  * @blkno: block number relative to file system
@@ -257,12 +169,12 @@ int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state)
 	uint32_t        rgrp_block;
 	struct gfs2_bitmap *bits = NULL;
 	struct rgrp_list *rgd;
+	unsigned char *byte, cur_state;
+	unsigned int bit;
 
 	/* FIXME: should GFS2_BLKST_INVALID be allowed */
-	if((state != GFS2_BLKST_FREE) && (state != GFS2_BLKST_USED) &&
-	   (state != GFS2_BLKST_DINODE)){
+	if ((state < GFS2_BLKST_FREE) || (state > GFS2_BLKST_DINODE))
 		return -1;
-	}
 
 	rgd = gfs2_blk2rgrpd(sdp, blkno);
 
@@ -278,9 +190,14 @@ int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state)
 			break;
 	}
 
-	gfs2_setbit((unsigned char *)rgd->bh[buf]->b_data + bits->bi_offset,
-				bits->bi_len, (rgrp_block - (bits->bi_start * GFS2_NBBY)),
-				state);
+	byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
+		(rgrp_block/GFS2_NBBY - bits->bi_start);
+	bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
+
+	cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+	*byte ^= cur_state << bit;
+	*byte |= state << bit;
+
 	gfs2_rgrp_relse(rgd, updated);
 	return 0;
 }
diff --git a/gfs2/man/gfs2_edit.8 b/gfs2/man/gfs2_edit.8
index 36a6018..a14f2b4 100644
--- a/gfs2/man/gfs2_edit.8
+++ b/gfs2/man/gfs2_edit.8
@@ -3,7 +3,7 @@
 .TH gfs2_edit 8
 
 .SH NAME
-gfs2_edit - Display, print or edit GFS2 internal structures.
+gfs2_edit - Display, print or edit GFS2 or GFS internal structures.
 
 .SH SYNOPSIS
 .B gfs2_edit
@@ -21,12 +21,12 @@ These options should be used with great care.
 
 .SH OPTIONS
 .TP
-\fB-p\fP [\fIstructure\fR | \fIblock\fR]
+\fB-p\fP [\fIstruct\fR | \fIblock\fR] [\fIblocktype\fR] [\fIblockalloc [val]\fR] [\fIblockbits\fR] [\fIblockrg\fR] [\fIfind sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc\fR] [\fIfield <field> [val]\fR]
 Print a gfs2 data structure in human-readable format to stdout.
 You can enter either a block number or a data structure name.  Block numbers
 may be specified in hex (e.g., 0x10) or decimal (e.g., 16).
 
-You can specify the following data structure names with the -p option.
+You can specify the following well-known locations with the -p option.
 
 \fIsb\fR, \fIsuperblock\fR - Print the superblock.
 
@@ -69,14 +69,64 @@ If you specify -p without a block or structure name, gfs2_edit prints the
 superblock.
 
 You can specify more than one data structure with a single -p option.
-For example, "gfs2_edit -p inum statfs /dev/sda1" prints the system inum
+For example, \fBgfs2_edit -p inum statfs /dev/sda1\fP prints the system inum
 file and the system statfs file on /dev/sda1.
 
-.TP
-\fB-p\fs [\fIstructure\fR | \fIblock\fR]
-Specify a starting block for interactive mode.  Any of the keywords found
-in the -p option may be specified.  If you want to start on a particular
-resource group, specify it in quotes, e.g. -p "rg 3"
+Optionally, you may specify the keyword \fIblocktype\fR to print out the
+gfs2 block type for the specified block.  Valid gfs2 block types are:
+0 (Clump), 1 (Superblock), 2 (Resource Group Header), 3 (Resource Group
+Bitmap), 4 (Dinode), 5 (Indirect Block), 6 (Leaf), 7 (Journaled data),
+8 (Log Header), 9 (Log descriptor), 10 (Extended attribute),
+11 (Eattr Data), 12 (Log Buffer), 13 (Invalid), and 14 (Quota Change).
+
+Optionally, you may specify the keyword \fIblockalloc\fR with an
+optional value to assign.  If no value is specified, the blockalloc
+keyword will print the block allocation type for the specified block.
+Valid block allocation types are: 0 (Free block), 1 (Data block),
+2 (Unlinked block), and 3 (Metadata block).  If a value from 0 to 3 is
+specified, the resource group bitmap will be changed to the new value.
+This may be used, for example, to artificially free or allocate a block
+in order to test gfs2_fsck's ability to detect and fix the problem.
+
+Optionally, you may specify the keyword \fIblockbits\fR.  This option
+will locate and print the block containing the bitmap corresponding to
+the specified block.
+
+Optionally, you may specify the keyword \fIblockrg\fR.  This option
+will locate and print the block number of the resource group that holds
+information about the specified block.
+
+You may also use gfs2_edit to find the next occurrence of a metadata
+block of a certain type.  Valid metadata types are: \fInone\fR (unused
+metadata clump block), \fIsb\fR (superblock), \fIrg\fR (resource group),
+\fIrb\fR (rg bitmap), \fIdi\fR (disk inode aka dinode), \fIin\fR (indirect
+block list), \fIlf\fR (directory leaf), \fIjd\fR (journaled data),
+\fIlh\fR (journal log header), \fIld\fR (journal log descriptor),
+\fIea\fR (extended attribute), \fIed\fR (ea data block), \fIlb\fR (log buffer),
+\fI13\fR (unused block type 13), \fIqc\fR (quota change).
+The block AFTER the one specified with -p is the starting point for
+the search.  For example, if you specify \fBgfs2_edit -p rg 12 find rg
+/dev/your/device\fP, it will find the rg that follows rg 12 (normally,
+this would be rg 13).  Note, however, that since metadata often appears
+in the journals, it could be a copy of a different RG, inside a journal.
+Also note that gfs2_edit will only find \fBallocated\fR metadata blocks
+unless the type specified is none, sb, rg or rb.  In other words, if you
+try to find a disk inode, it will only find an allocated dinode, not a
+deallocated one.
+
+Optionally, you may specify the keyword \fIfield\fR followed by a
+valid metadata field name.  Right now, only the fields in disk inodes
+and resource groups are allowed.  If no value is specified after the
+field, the value of the field will be printed to stdout.  If a value
+is specified, the field's value will be changed.  This may be used,
+for example, to artificially change the di_size field for an inode
+in order to test gfs2_fsck's ability to detect and fix the problem.
+
+.TP
+\fB-s\fs [\fIstructure\fR | \fIblock\fR]
+Specify a starting block for interactive mode.  Any of the well-known
+locations found in the -p option may be specified.  If you want to start
+on a particular resource group, specify it in quotes, e.g. -s "rg 3"
 .TP
 \fB-h, -help, -usage\fP
 Print help information.
@@ -245,9 +295,20 @@ not roll you back up.
 \fB<enter>\fP - Edit value
 The \fB<enter>\fP key causes you to go from display mode to edit mode.
 If you are in hex mode and you hit enter, you can type new hex values
-at the cursor's current location.  Note: Currently hitting \fB<enter>\fP
-in structure mode allows you to enter a new value, but it will not actually
-change the value on disk.  That is a future feature.
+at the cursor's current location.  Note: pressing \fB<enter>\fP
+in structure mode allows you to enter a new value, with the following
+restrictions:  For gfs2 disk inodes and resource groups, it will
+actually change the value on disk. However, inode numbers may not be
+changed.  For all other structures, the values entered are ignored.
+
+If you use the up arrow key to highlight the block number, then press
+\fB<enter>\fP, you may then enter a new block number, or any of the
+well-known block locations listed above (e.g. sb, rindex, inum, rg 17,
+etc.) and gfs2_edit will jump to the block specified.  If you specify
+a slash character followed by a metadata type, gfs2_edit will search for
+the next occurrence of that metadata block type, and jump there.  It
+will take you to block 0 if it does not find any more blocks of the
+specified metadata type.
 
 .TP
 \fB<home>\fP
@@ -315,6 +376,41 @@ Print the rg_flags value for the fourth Resource Group on /dev/sdb1.
 gfs2_edit rgflags 3 8 /dev/sdb1
 Set the GFS2_RGF_NOALLOC flag on for the fourth Resource Group on /dev/sdb1.
 
+.TP
+gfs2_edit -p 25 blockalloc /dev/roth_vg/roth_lv
+Print the block allocation type of block 25.
+May produce this output:
+3 (Metadata)
+
+.TP
+gfs2_edit -p 25 blockalloc 1 /dev/roth_vg/roth_lv
+Change the block allocation type of block 25 to data.
+May produce this output:
+1
+
+.TP
+gfs2_edit -p 25 blocktype /dev/roth_vg/roth_lv
+Print the metadata block type of block 25.
+May produce this output:
+4 (Block 25 is type 4: Dinode)
+
+.TP
+gfs2_edit -p 25 field di_size /dev/roth_vg/roth_lv
+Print the di_size field of block 25.
+May produce this output:
+134217728
+
+.TP
+gfs2_edit -x -p 25 field di_size /dev/roth_vg/roth_lv
+Print the di_size field of block 25, in hexidecimal.
+May produce this output:
+0x8000000
+
+.TP
+gfs2_edit -p 25 field di_size 0x4000 /dev/roth_vg/roth_lv
+Change the di_size field of block 25 to the hexidecimal value 0x4000.
+May produce this output:
+16384
 .SH KNOWN BUGS
 .TP
 The directory code does not work well.  It might be confused


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]