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 Project branch, RHEL5, updated. cmirror_1_1_15-173-gfd23d8d


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Cluster Project".

http://sources.redhat.com/git/gitweb.cgi?p=cluster.git;a=commitdiff;h=fd23d8d2b677fc3116e0fa0ce53b73feea47a06f

The branch, RHEL5 has been updated
       via  fd23d8d2b677fc3116e0fa0ce53b73feea47a06f (commit)
       via  9ec515f67398d63f49724ac1f6f48f5c11a99cec (commit)
       via  697309e6e6039884b733999cade1e847f4c6eb70 (commit)
       via  b54e95b76d01e12c463553ed464a990da1962f0d (commit)
       via  9e261bb6f8edfb1c9db5a30d3bd98375533ef357 (commit)
       via  5f4cd5a9ca316478a17ccdc078dd78f3c511f0ce (commit)
       via  3f95fdad6c0884257c5e247d3319bbf8171ffc85 (commit)
       via  ddbca2d904b28c1c5e1530c7f15543390c1262d3 (commit)
       via  2554501b13047ddd42650eb2dd9875ca57bf0489 (commit)
       via  e8a2e811800d074d8725cc239dafaf2f7ac04783 (commit)
      from  613d97438673200c87e4b07e3c4ee659c01acf65 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit fd23d8d2b677fc3116e0fa0ce53b73feea47a06f
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Thu Jul 24 10:15:23 2008 -0500

    gfs2_fsck dupl. blocks between EA and data

commit 9ec515f67398d63f49724ac1f6f48f5c11a99cec
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Thu Jul 24 09:49:33 2008 -0500

    RGRepair: Account for RG blocks inside journals

commit 697309e6e6039884b733999cade1e847f4c6eb70
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 17:36:42 2008 -0500

    Better error reporting in gfs2_fsck

commit b54e95b76d01e12c463553ed464a990da1962f0d
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 17:18:13 2008 -0500

    Shrink memory 3: smaller link counts in inode_info

commit 9e261bb6f8edfb1c9db5a30d3bd98375533ef357
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Thu Jul 24 09:45:16 2008 -0500

    Shrink memory 2: get rid of 3 huge in-core bitmaps

commit 5f4cd5a9ca316478a17ccdc078dd78f3c511f0ce
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 14:46:55 2008 -0500

    Shrink memory 1: eliminate b_size from pseudo-buffer-heads

commit 3f95fdad6c0884257c5e247d3319bbf8171ffc85
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 14:17:52 2008 -0500

    Deleted unused function print_map

commit ddbca2d904b28c1c5e1530c7f15543390c1262d3
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 14:15:16 2008 -0500

    Fix some bad references to gfs_tool and gfs_fsck

commit 2554501b13047ddd42650eb2dd9875ca57bf0489
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 14:09:19 2008 -0500

    gfs_fsck crosswrite for block number sanity checking

commit e8a2e811800d074d8725cc239dafaf2f7ac04783
Author: Bob Peterson <rpeterso@redhat.com>
Date:   Wed Jul 23 14:03:50 2008 -0500

    Speed up userspace bitmap manipulation code.

-----------------------------------------------------------------------

Summary of changes:
 gfs2/edit/savemeta.c      |    9 +-
 gfs2/fsck/eattr.c         |   21 ++-
 gfs2/fsck/eattr.h         |   20 +-
 gfs2/fsck/fs_recovery.c   |    4 +-
 gfs2/fsck/fsck.h          |    5 +-
 gfs2/fsck/initialize.c    |   10 +-
 gfs2/fsck/lost_n_found.c  |    5 +-
 gfs2/fsck/main.c          |   35 +----
 gfs2/fsck/metawalk.c      |  177 +++++++++++++-------
 gfs2/fsck/metawalk.h      |   16 ++-
 gfs2/fsck/pass1.c         |  405 +++++++++++++++++++++++++++++----------------
 gfs2/fsck/pass1b.c        |   95 +++++------
 gfs2/fsck/pass1c.c        |   69 +++++---
 gfs2/fsck/pass2.c         |   61 ++++---
 gfs2/fsck/pass3.c         |   20 ++-
 gfs2/fsck/pass4.c         |   11 +-
 gfs2/fsck/pass5.c         |    2 +-
 gfs2/fsck/rgrepair.c      |   58 ++++++-
 gfs2/libgfs2/bitmap.c     |   79 +++++++--
 gfs2/libgfs2/block_list.c |  232 ++++++++++++--------------
 gfs2/libgfs2/buf.c        |    1 -
 gfs2/libgfs2/fs_bits.c    |    2 +-
 gfs2/libgfs2/fs_ops.c     |   38 +++--
 gfs2/libgfs2/libgfs2.h    |   93 +++++++----
 gfs2/libgfs2/recovery.c   |    2 +-
 gfs2/libgfs2/rgrp.c       |    8 +
 26 files changed, 893 insertions(+), 585 deletions(-)

diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index cff2f30..f298dd7 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -554,7 +554,7 @@ void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 		     sizeof(struct gfs2_dinode));
 
 	for (ptr = (uint64_t *)(mybh->b_data + head_size);
-	     (char *)ptr < (mybh->b_data + mybh->b_size); ptr++) {
+	     (char *)ptr < (mybh->b_data + sbd.bsize); ptr++) {
 		if (!*ptr)
 			continue;
 		indir_block = be64_to_cpu(*ptr);
@@ -805,7 +805,8 @@ void savemeta(const char *out_fn, int saveoption)
 		fflush(stdout);
 	}
 	if (!slow) {
-		blocklist = gfs2_block_list_create(last_fs_block + 1, &memreq);
+		blocklist = gfs2_block_list_create(&sbd, last_fs_block + 1,
+						   &memreq);
 		if (!blocklist)
 			slow = TRUE;
 	}
@@ -844,7 +845,7 @@ void savemeta(const char *out_fn, int saveoption)
 			log_debug("RG at %"PRIu64" is %u long\n",
 				  rgd->ri.ri_addr, rgd->ri.ri_length);
 			for (i = 0; i < rgd->ri.ri_length; i++) {
-				if(gfs2_block_set(blocklist,
+				if(gfs2_block_set(&sbd, blocklist,
 						  rgd->ri.ri_addr + i,
 						  gfs2_meta_other))
 					break;
@@ -879,7 +880,7 @@ void savemeta(const char *out_fn, int saveoption)
 	}
 	/* Clean up */
 	if (blocklist)
-		gfs2_block_list_destroy(blocklist);
+		gfs2_block_list_destroy(&sbd, 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. */
 	block = last_fs_block;
diff --git a/gfs2/fsck/eattr.c b/gfs2/fsck/eattr.c
index 42753ca..5f43ba6 100644
--- a/gfs2/fsck/eattr.c
+++ b/gfs2/fsck/eattr.c
@@ -21,7 +21,7 @@ static int clear_blk_nodup(struct gfs2_sbd *sbp, uint64_t block)
 {
 	struct gfs2_block_query q;
 
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(sbp, bl, block, &q)) {
 		stack;
 		return -1;
 	}
@@ -31,7 +31,7 @@ static int clear_blk_nodup(struct gfs2_sbd *sbp, uint64_t block)
 		return 1;
 	}
 
-	gfs2_block_set(bl, block, gfs2_block_free);
+	gfs2_block_set(sbp, bl, block, gfs2_block_free);
 
 	return 0;
 
@@ -39,22 +39,20 @@ static int clear_blk_nodup(struct gfs2_sbd *sbp, uint64_t block)
 
 int clear_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 		      uint64_t parent, struct gfs2_buffer_head **bh,
-		      void *private)
+		      enum update_flags *want_updated, void *private)
 {
+	*want_updated = not_updated;
 	return clear_blk_nodup(ip->i_sbd, block);
 }
 
-
 int clear_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 		     uint64_t parent, struct gfs2_buffer_head **bh,
-		     void *private)
+		     enum update_flags *want_updated, void *private)
 {
-
+	*want_updated = not_updated;
 	return clear_blk_nodup(ip->i_sbd, block);
-
 }
 
-
 int clear_eattr_entry (struct gfs2_inode *ip,
 		       struct gfs2_buffer_head *leaf_bh,
 		       struct gfs2_ea_header *ea_hdr,
@@ -101,11 +99,14 @@ int clear_eattr_entry (struct gfs2_inode *ip,
 }
 
 int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
-			 struct gfs2_buffer_head *leaf_bh, struct gfs2_ea_header *ea_hdr,
-			 struct gfs2_ea_header *ea_hdr_prev, void *private)
+			 struct gfs2_buffer_head *leaf_bh,
+			 struct gfs2_ea_header *ea_hdr,
+			 struct gfs2_ea_header *ea_hdr_prev,
+			 enum update_flags *want_updated, void *private)
 {
 	uint64_t block = be64_to_cpu(*ea_data_ptr);
 
+	*want_updated = not_updated;
 	return clear_blk_nodup(ip->i_sbd, block);
 
 }
diff --git a/gfs2/fsck/eattr.h b/gfs2/fsck/eattr.h
index 75991c0..674ee27 100644
--- a/gfs2/fsck/eattr.h
+++ b/gfs2/fsck/eattr.h
@@ -13,21 +13,21 @@
 #ifndef _EATTR_H
 #define _EATTR_H
 
-int clear_eattr_indir(struct gfs2_inode *ip, uint64_t block,
-					  uint64_t parent, struct gfs2_buffer_head **bh,
-					  void *private);
-int clear_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-					 uint64_t parent, struct gfs2_buffer_head **bh,
-					 void *private);
+int clear_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
+		      struct gfs2_buffer_head **bh,
+		      enum update_flags *want_updated, void *private);
+int clear_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
+		     struct gfs2_buffer_head **bh,
+		     enum update_flags *want_updated, void *private);
 int clear_eattr_entry (struct gfs2_inode *ip,
 					   struct gfs2_buffer_head *leaf_bh,
 					   struct gfs2_ea_header *ea_hdr,
 					   struct gfs2_ea_header *ea_hdr_prev,
 					   void *private);
 int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
-						 struct gfs2_buffer_head *leaf_bh,
-						 struct gfs2_ea_header *ea_hdr,
-						 struct gfs2_ea_header *ea_hdr_prev,
-						 void *private);
+			 struct gfs2_buffer_head *leaf_bh,
+			 struct gfs2_ea_header *ea_hdr,
+			 struct gfs2_ea_header *ea_hdr_prev,
+			 enum update_flags *want_updated, void *private);
 
 #endif /* _EATTR_H */
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 3b25dc6..b21760b 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -134,7 +134,7 @@ static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
 			return error;
 
 		bh_ip = bget(sdp, blkno);
-		memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+		memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
 
 		check_magic = ((struct gfs2_meta_header *)
 			       (bh_ip->b_data))->mh_magic;
@@ -231,7 +231,7 @@ static int databuf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
 			return error;
 
 		bh_ip = bget(sdp, blkno);
-		memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+		memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
 
 		/* Unescape */
 		if (esc) {
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 6220963..e36c3b8 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -25,9 +25,9 @@ struct inode_info
 {
         osi_list_t list;
         uint64_t   inode;
-        uint32_t   link_count;   /* the number of links the inode
+        uint16_t   link_count;   /* the number of links the inode
                                   * thinks it has */
-        uint32_t   counted_links; /* the number of links we've found */
+        uint16_t   counted_links; /* the number of links we've found */
 };
 
 struct dir_info
@@ -89,6 +89,5 @@ extern uint64_t last_fs_block, last_reported_block;
 extern int skip_this_pass, fsck_abort, fsck_query;
 extern uint64_t last_data_block;
 extern uint64_t first_data_block;
-extern osi_list_t dup_list;
 
 #endif /* _FSCK_H */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index d759b09..7d957ee 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -122,7 +122,7 @@ static void empty_super_block(struct gfs2_sbd *sdp)
 		}
 	}
 
-	gfs2_block_list_destroy(bl);
+	gfs2_block_list_destroy(sdp, bl);
 }
 
 
@@ -277,11 +277,11 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
 		goto fail;
 	}
 
-	bl = gfs2_block_list_create(last_fs_block+1, &addl_mem_needed);
+	bl = gfs2_block_list_create(sdp, last_fs_block+1, &addl_mem_needed);
 	if (!bl) {
 		log_crit("This system doesn't have enough memory + swap space to fsck this file system.\n");
 		log_crit("Additional memory needed is approximately: %ldMB\n", addl_mem_needed / 1048576);
-		log_crit("Please increase your swap space by that amount and run gfs_fsck again.\n");
+		log_crit("Please increase your swap space by that amount and run gfs2_fsck again.\n");
 		goto fail;
 	}
 	return 0;
@@ -385,8 +385,8 @@ static void destroy_sbp(struct gfs2_sbd *sbp)
 {
 	if(!opts.no) {
 		if(block_mounters(sbp, 0)) {
-			log_warn("Unable to unblock other mounters - manual intevention required\n");
-			log_warn("Use 'gfs_tool sb <device> proto' to fix\n");
+			log_warn("Unable to unblock other mounters - manual intervention required\n");
+			log_warn("Use 'gfs2_tool sb <device> proto' to fix\n");
 		}
 		log_info("Syncing the device.\n");
 		fsync(sbp->device_fd);
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index e836539..3990e44 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -45,7 +45,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 		log_info("Locating/Creating lost and found directory\n");
 
         lf_dip = createi(ip->i_sbd->md.rooti, "lost+found", S_IFDIR | 0700, 0);
-		if(gfs2_block_check(bl, lf_dip->i_di.di_num.no_addr, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, lf_dip->i_di.di_num.no_addr, &q)) {
 			stack;
 			return -1;
 		}
@@ -58,7 +58,8 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 			 * directory or just found an old one, and we
 			 * used that instead of the block_type to run
 			 * this */
-			gfs2_block_set(bl, lf_dip->i_di.di_num.no_addr, gfs2_inode_dir);
+			gfs2_block_set(ip->i_sbd, bl,
+				       lf_dip->i_di.di_num.no_addr, gfs2_inode_dir);
 			increment_link(ip->i_sbd,
 						   ip->i_sbd->md.rooti->i_di.di_num.no_addr);
 			increment_link(ip->i_sbd, lf_dip->i_di.di_num.no_addr);
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 8ee1de3..928cd1c 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -35,7 +35,6 @@ int skip_this_pass = FALSE, fsck_abort = FALSE;
 const char *pass = "";
 uint64_t last_data_block;
 uint64_t first_data_block;
-osi_list_t dup_list;
 char *prog_name = "gfs2_fsck"; /* needed by libgfs2 */
 
 /* This function is for libgfs2's sake.                                      */
@@ -49,29 +48,6 @@ void print_it(const char *label, const char *fmt, const char *fmt2, ...)
 	va_end(args);
 }
 
-void print_map(struct gfs2_block_list *il, int count)
-{
-	int i, j;
-	struct gfs2_block_query k;
-
-	log_info("Printing map of blocks - 80 blocks per row\n");
-	j = 0;
-	for(i = 0; i < count; i++) {
-		if(j > 79) {
-			log_info("\n");
-			j = 0;
-		}
-		else if(!(j %10) && j != 0) {
-			log_info(" ");
-		}
-		j++;
-		gfs2_block_check(il, i, &k);
-		log_info("%X", k.block_type);
-
-	}
-	log_info("\n");
-}
-
 void usage(char *name)
 {
 	printf("Usage: %s [-hnqvVy] <device> \n", basename(name));
@@ -149,7 +125,7 @@ void interrupt(int sig)
 			PRIu64 "\n", last_reported_block, last_fs_block);
 	
 	response = generic_interrupt("gfs2_fsck", pass, progress,
-				     "Do you want to abort gfs_fsck, skip " \
+				     "Do you want to abort gfs2_fsck, skip " \
 				     "the rest of this pass or continue " \
 				     "(a/s/c)?", "asc");
 	if(tolower(response) == 's') {
@@ -182,7 +158,7 @@ int check_system_inode(struct gfs2_inode *sysinode, const char *filename,
 		
 		/* FIXME: check this block's validity */
 
-		if(gfs2_block_check(bl, iblock, &ds.q)) {
+		if(gfs2_block_check(sysinode->i_sbd, bl, iblock, &ds.q)) {
 			log_crit("Can't get %s inode block %" PRIu64 " (0x%"
 				 PRIx64 ") from block list\n", filename,
 				 iblock, iblock);
@@ -194,7 +170,8 @@ int check_system_inode(struct gfs2_inode *sysinode, const char *filename,
 		/* Just reuse the inode and fix the bitmap.         */
 		if (ds.q.block_type == gfs2_block_free) {
 			log_info("The inode exists but the block is not marked 'in use'; fixing it.\n");
-			gfs2_block_set(bl, sysinode->i_di.di_num.no_addr,
+			gfs2_block_set(sysinode->i_sbd, bl,
+				       sysinode->i_di.di_num.no_addr,
 				       mark);
 			ds.q.block_type = mark;
 			if (mark == gfs2_inode_dir)
@@ -213,7 +190,8 @@ int check_system_inode(struct gfs2_inode *sysinode, const char *filename,
 		if (query(&opts, "Create new %s system inode? (y/n) ",
 			  filename)) {
 			builder(sysinode->i_sbd);
-			gfs2_block_set(bl, sysinode->i_di.di_num.no_addr,
+			gfs2_block_set(sysinode->i_sbd, bl,
+				       sysinode->i_di.di_num.no_addr,
 				       mark);
 			ds.q.block_type = mark;
 			if (mark == gfs2_inode_dir)
@@ -402,7 +380,6 @@ int main(int argc, char **argv)
 	inode_put(sbp->master_dir, update_sys_files);
 	if (lf_dip)
 		inode_put(lf_dip, update_sys_files);
-/*	print_map(sbp->bl, sbp->last_fs_block); */
 
 	if (!opts.no)
 		log_notice("Writing changes to disk\n");
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index ac7e8f0..bb9f195 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -113,13 +113,14 @@ int dirent_repair(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 	/* If this is a sentinel, just fix the length and move on */
 	if (first && !de->de_inum.no_formal_ino) { /* Is it a sentinel? */
 		if (type == DIR_LINEAR)
-			de->de_rec_len = bh->b_size -
+			de->de_rec_len = ip->i_sbd->bsize -
 				sizeof(struct gfs2_dinode);
 		else
-			de->de_rec_len = bh->b_size - sizeof(struct gfs2_leaf);
+			de->de_rec_len = ip->i_sbd->bsize -
+				sizeof(struct gfs2_leaf);
 	}
 	else {
-		bh_end = bh->b_data + bh->b_size;
+		bh_end = bh->b_data + ip->i_sbd->bsize;
 		/* first, figure out a probable name length */
 		p = (char *)dent + sizeof(struct gfs2_dirent);
 		while (*p &&         /* while there's a non-zero char and */
@@ -142,8 +143,8 @@ int dirent_repair(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 }
 
 int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
-				  int index, int type, int *update, uint16_t *count,
-				  struct metawalk_fxns *pass)
+		  int index, int type, enum update_flags *update,
+		  uint16_t *count, struct metawalk_fxns *pass)
 {
 	struct gfs2_leaf *leaf = NULL;
 	struct gfs2_dirent *dent;
@@ -153,7 +154,7 @@ int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 	char *filename;
 	int first = 1;
 
-	bh_end = bh->b_data + bh->b_size;
+	bh_end = bh->b_data + ip->i_sbd->bsize;
 
 	if(type == DIR_LINEAR) {
 		dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
@@ -191,7 +192,7 @@ int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 						  first))
 					break;
 				else
-					*update = 1;
+					*update = updated;
 			}
 			else {
 				log_err("Corrupt directory entry ignored, "
@@ -224,8 +225,10 @@ int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 				first = 0;
 			}
 			else {
-				error = pass->check_dentry(ip, dent, prev, bh, filename,
-							   update, count, pass->private);
+				error = pass->check_dentry(ip, dent, prev, bh,
+							   filename, update,
+							   count,
+							   pass->private);
 				if(error < 0) {
 					stack;
 					return -1;
@@ -277,7 +280,8 @@ void warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
 }
 
 /* Checks exhash directory entries */
-int check_leaf(struct gfs2_inode *ip, int *update, struct metawalk_fxns *pass)
+int check_leaf(struct gfs2_inode *ip, enum update_flags *update,
+	       struct metawalk_fxns *pass)
 {
 	int error;
 	struct gfs2_leaf leaf, oldleaf;
@@ -401,8 +405,9 @@ int check_leaf(struct gfs2_inode *ip, int *update, struct metawalk_fxns *pass)
 
 			if(pass->check_dentry &&
 			   S_ISDIR(ip->i_di.di_mode)) {
-				error = check_entries(ip, lbh, index, DIR_EXHASH, update,
-									  &count, pass);
+				error = check_entries(ip, lbh, index,
+						      DIR_EXHASH, update,
+						      &count, pass);
 
 				/* Since the buffer possibly got
 				 * updated directly, release it now,
@@ -456,8 +461,9 @@ int check_leaf(struct gfs2_inode *ip, int *update, struct metawalk_fxns *pass)
 }
 
 static int check_eattr_entries(struct gfs2_inode *ip,
-							   struct gfs2_buffer_head *bh,
-							   struct metawalk_fxns *pass)
+			       struct gfs2_buffer_head *bh,
+			       struct metawalk_fxns *pass,
+			       enum update_flags *update_it)
 {
 	struct gfs2_ea_header *ea_hdr, *ea_hdr_prev = NULL;
 	uint64_t *ea_data_ptr = NULL;
@@ -465,6 +471,7 @@ static int check_eattr_entries(struct gfs2_inode *ip,
 	int error = 0;
 	uint32_t offset = (uint32_t)sizeof(struct gfs2_meta_header);
 
+	*update_it = 0;
 	if(!pass->check_eattr_entry) {
 		return 0;
 	}
@@ -479,29 +486,46 @@ static int check_eattr_entries(struct gfs2_inode *ip,
 			stack;
 			return -1;
 		}
-		if(error == 0) {
-			if(pass->check_eattr_extentry && ea_hdr->ea_num_ptrs) {
-				ea_data_ptr = ((uint64_t *)((char *)ea_hdr +
-							    sizeof(struct gfs2_ea_header) +
-							    ((ea_hdr->ea_name_len + 7) & ~7)));
-
-				/* It is possible when a EA is shrunk
-				** to have ea_num_ptrs be greater than
-				** the number required for ** data.
-				** In this case, the EA ** code leaves
-				** the blocks ** there for **
-				** reuse...........  */
-				for(i = 0; i < ea_hdr->ea_num_ptrs; i++){
-					if(pass->check_eattr_extentry(ip,
-								      ea_data_ptr,
-								      bh, ea_hdr,
-								      ea_hdr_prev,
-								      pass->private)) {
-						stack;
+		if(error == 0 && pass->check_eattr_extentry &&
+		   ea_hdr->ea_num_ptrs) {
+			uint32_t tot_ealen = 0;
+			struct gfs2_sbd *sdp = ip->i_sbd;
+
+			ea_data_ptr = ((uint64_t *)((char *)ea_hdr +
+						    sizeof(struct gfs2_ea_header) +
+						    ((ea_hdr->ea_name_len + 7) & ~7)));
+
+			/* It is possible when a EA is shrunk
+			** to have ea_num_ptrs be greater than
+			** the number required for ** data.
+			** In this case, the EA ** code leaves
+			** the blocks ** there for **
+			** reuse...........  */
+
+			for(i = 0; i < ea_hdr->ea_num_ptrs; i++){
+				if(pass->check_eattr_extentry(ip,
+							      ea_data_ptr,
+							      bh, ea_hdr,
+							      ea_hdr_prev,
+							      update_it,
+							      pass->private)) {
+					if (query(&opts, "Repair the bad EA? "
+						  "(y/n) ")) {
+						ea_hdr->ea_num_ptrs = i;
+						ea_hdr->ea_data_len =
+							cpu_to_be32(tot_ealen);
+						*ea_data_ptr = 0;
+						*update_it = 1;
+						/* Endianness doesn't matter
+						   in this case because it's
+						   a single byte. */
 						return -1;
 					}
-					ea_data_ptr++;
+					log_err("The bad EA was not fixed.\n");
 				}
+				tot_ealen += sdp->sd_sb.sb_bsize -
+					sizeof(struct gfs2_meta_header);
+				ea_data_ptr++;
 			}
 		}
 		offset += be32_to_cpu(ea_hdr->ea_rec_len);
@@ -526,15 +550,18 @@ static int check_eattr_entries(struct gfs2_inode *ip,
  * Returns: 0 on success, -1 if removal is needed
  */
 static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
-							uint64_t parent, struct metawalk_fxns *pass)
+			    uint64_t parent, enum update_flags *want_updated,
+			    struct metawalk_fxns *pass)
 {
 	struct gfs2_buffer_head *bh = NULL;
 	int error = 0;
+
 	log_debug("Checking EA leaf block #%"PRIu64" (0x%" PRIx64 ").\n",
 			  block, block);
 
 	if(pass->check_eattr_leaf) {
-		error = pass->check_eattr_leaf(ip, block, parent, &bh, pass->private);
+		error = pass->check_eattr_leaf(ip, block, parent, &bh,
+					       want_updated, pass->private);
 		if(error < 0) {
 			stack;
 			return -1;
@@ -542,9 +569,9 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
 		if(error > 0) {
 			return 1;
 		}
-		check_eattr_entries(ip, bh, pass);
+		check_eattr_entries(ip, bh, pass, want_updated);
 		if (bh)
-			brelse(bh, not_updated);
+			brelse(bh, *want_updated);
 	}
 
 	return 0;
@@ -558,6 +585,7 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
  * Returns: 0 on success -1 on error
  */
 static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
+				enum update_flags *want_updated,
 				struct metawalk_fxns *pass){
 	int error = 0;
 	uint64_t *ea_leaf_ptr, *end;
@@ -565,12 +593,18 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
 	struct gfs2_buffer_head *indirect_buf = NULL;
 	struct gfs2_sbd *sdp = ip->i_sbd;
 
+	*want_updated = not_updated;
 	log_debug("Checking EA indirect block #%"PRIu64" (0x%" PRIx64 ").\n",
 			  indirect, indirect);
 
-	if (pass->check_eattr_indir &&
-	    !pass->check_eattr_indir(ip, indirect, ip->i_di.di_num.no_addr,
-				     &indirect_buf, pass->private)) {
+	if (!pass->check_eattr_indir)
+		return 0;
+	error = pass->check_eattr_indir(ip, indirect, ip->i_di.di_num.no_addr,
+					&indirect_buf, want_updated,
+					pass->private);
+	if (!error) {
+		int leaf_pointers = 0, leaf_pointer_errors = 0;
+
 		ea_leaf_ptr = (uint64_t *)(indirect_buf->b_data
 								   + sizeof(struct gfs2_meta_header));
 		end = ea_leaf_ptr + ((sdp->sd_sb.sb_bsize
@@ -578,13 +612,34 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
 
 		while(*ea_leaf_ptr && (ea_leaf_ptr < end)){
 			block = be64_to_cpu(*ea_leaf_ptr);
-			/* FIXME: should I call check_leaf_eattr if we
-			 * find a dup? */
-			error = check_leaf_eattr(ip, block, indirect, pass);
+			leaf_pointers++;
+			error = check_leaf_eattr(ip, block, indirect,
+						 want_updated, pass);
+			if (error)
+				leaf_pointer_errors++;
 			ea_leaf_ptr++;
 		}
-		brelse(indirect_buf, not_updated);
+		if (pass->finish_eattr_indir) {
+			int indir_ok = 1;
+
+			if (leaf_pointer_errors == leaf_pointers)
+				indir_ok = 0;
+			pass->finish_eattr_indir(ip, indir_ok, want_updated,
+						 pass->private);
+			if (!indir_ok) {
+				if (*want_updated)
+					gfs2_set_bitmap(sdp, indirect,
+							GFS2_BLKST_FREE);
+				gfs2_block_clear(sdp, bl, indirect,
+						 gfs2_indir_blk);
+				gfs2_block_set(sdp, bl, indirect,
+					       gfs2_block_free);
+				error = 1;
+			}
+		}
 	}
+	if (indirect_buf)
+		brelse(indirect_buf, not_updated);
 
 	return error;
 }
@@ -595,7 +650,8 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
  *
  * Returns: 0 on success, -1 on error
  */
-int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
+int check_inode_eattr(struct gfs2_inode *ip, enum update_flags *want_updated,
+		      struct metawalk_fxns *pass)
 {
 	int error = 0;
 
@@ -604,15 +660,16 @@ int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	}
 
 	log_debug("Extended attributes exist for inode #%" PRIu64 " (0x%" PRIx64
-			  ").\n", ip->i_di.di_num.no_formal_ino,
-			  ip->i_di.di_num.no_formal_ino);
+		  ").\n", ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 
 	if(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT){
-		if((error = check_indirect_eattr(ip, ip->i_di.di_eattr, pass)))
+		if((error = check_indirect_eattr(ip, ip->i_di.di_eattr,
+						 want_updated, pass)))
 			stack;
 	} else {
 		if((error = check_leaf_eattr(ip, ip->i_di.di_eattr,
-					     ip->i_di.di_num.no_addr, pass)))
+					     ip->i_di.di_num.no_addr,
+					     want_updated, pass)))
 			stack;
 	}
 
@@ -656,7 +713,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
 				     sizeof(struct gfs2_dinode));
 
 			for (ptr = (uint64_t *)(bh->b_data + head_size);
-			     (char *)ptr < (bh->b_data + bh->b_size);
+			     (char *)ptr < (bh->b_data + ip->i_sbd->bsize);
 			     ptr++) {
 				nbh = NULL;
 		
@@ -715,7 +772,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 	uint64_t block, *ptr;
 	uint32_t height = ip->i_di.di_height;
 	int  i, head_size;
-	int update = 0;
+	enum update_flags update = not_updated;
 	int error = 0;
 
 	if (!height)
@@ -746,7 +803,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 			     sizeof(struct gfs2_dinode));
 		ptr = (uint64_t *)(bh->b_data + head_size);
 
-		for ( ; (char *)ptr < (bh->b_data + bh->b_size); ptr++)	{
+		for ( ; (char *)ptr < (bh->b_data + ip->i_sbd->bsize); ptr++) {
 			if (!*ptr)
 				continue;
 
@@ -790,7 +847,7 @@ end:
 
 /* Checks stuffed inode directories */
 int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
-					 int *update, struct metawalk_fxns *pass)
+		     enum update_flags *update, struct metawalk_fxns *pass)
 {
 	int error = 0;
 	uint16_t count = 0;
@@ -809,7 +866,7 @@ int check_dir(struct gfs2_sbd *sbp, uint64_t block, struct metawalk_fxns *pass)
 {
 	struct gfs2_buffer_head *bh;
 	struct gfs2_inode *ip;
-	int update = 0;
+	enum update_flags update = not_updated;
 	int error = 0;
 
 	bh = bread(sbp, block);
@@ -837,10 +894,10 @@ int check_dir(struct gfs2_sbd *sbp, uint64_t block, struct metawalk_fxns *pass)
 }
 
 static int remove_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
-						 struct gfs2_dirent *prev_de,
-						 struct gfs2_buffer_head *bh,
-						 char *filename, int *update,
-						 uint16_t *count, void *private)
+			 struct gfs2_dirent *prev_de,
+			 struct gfs2_buffer_head *bh,
+			 char *filename, enum update_flags *update,
+			 uint16_t *count, void *private)
 {
 	/* the metawalk_fxn's private field must be set to the dentry
 	 * block we want to clear */
@@ -877,7 +934,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
 	remove_dentry_fxns.private = &dentryblock;
 	remove_dentry_fxns.check_dentry = remove_dentry;
 
-	if(gfs2_block_check(bl, dir, &q)) {
+	if(gfs2_block_check(sbp, bl, dir, &q)) {
 		stack;
 		return -1;
 	}
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 2b0f847..44ac31a 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -18,7 +18,8 @@
 
 struct metawalk_fxns;
 
-int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass);
+int check_inode_eattr(struct gfs2_inode *ip, enum update_flags *want_updated,
+		      struct metawalk_fxns *pass);
 int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass);
 int check_dir(struct gfs2_sbd *sbp, uint64_t block,
 			  struct metawalk_fxns *pass);
@@ -53,15 +54,18 @@ struct metawalk_fxns {
 			   void *private);
 	int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
 				  uint64_t parent,
-				  struct gfs2_buffer_head **bh, void *private);
+				  struct gfs2_buffer_head **bh,
+				  enum update_flags *want_updated,
+				  void *private);
 	int (*check_eattr_leaf) (struct gfs2_inode *ip, uint64_t block,
 				 uint64_t parent, struct gfs2_buffer_head **bh,
+				 enum update_flags *want_updated,
 				 void *private);
 	int (*check_dentry) (struct gfs2_inode *ip, struct gfs2_dirent *de,
 			     struct gfs2_dirent *prev,
 			     struct gfs2_buffer_head *bh,
-			     char *filename, int *update, uint16_t *count,
-			     void *private);
+			     char *filename, enum update_flags *update,
+			     uint16_t *count, void *private);
 	int (*check_eattr_entry) (struct gfs2_inode *ip,
 				  struct gfs2_buffer_head *leaf_bh,
 				  struct gfs2_ea_header *ea_hdr,
@@ -72,7 +76,11 @@ struct metawalk_fxns {
 				     struct gfs2_buffer_head *leaf_bh,
 				     struct gfs2_ea_header *ea_hdr,
 				     struct gfs2_ea_header *ea_hdr_prev,
+				     enum update_flags *want_updated,
 				     void *private);
+	int (*finish_eattr_indir) (struct gfs2_inode *ip, int indir_ok,
+				   enum update_flags *want_updated,
+				   void *private);
 };
 
 #endif /* _METAWALK_H */
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index b00331d..3579393 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -44,19 +44,57 @@ struct block_count {
 };
 
 static int leaf(struct gfs2_inode *ip, uint64_t block,
-				struct gfs2_buffer_head *bh, void *private)
+		struct gfs2_buffer_head *bh, void *private);
+static int check_metalist(struct gfs2_inode *ip, uint64_t block,
+			  struct gfs2_buffer_head **bh, void *private);
+static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
+static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
+			     uint64_t parent, struct gfs2_buffer_head **bh,
+			     enum update_flags *want_updated, void *private);
+static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
+			    uint64_t parent, struct gfs2_buffer_head **bh,
+			    enum update_flags *want_updated, void *private);
+static int check_eattr_entries(struct gfs2_inode *ip,
+			       struct gfs2_buffer_head *leaf_bh,
+			       struct gfs2_ea_header *ea_hdr,
+			       struct gfs2_ea_header *ea_hdr_prev,
+			       void *private);
+static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
+				     struct gfs2_buffer_head *leaf_bh,
+				     struct gfs2_ea_header *ea_hdr,
+				     struct gfs2_ea_header *ea_hdr_prev,
+				     enum update_flags *want_updated,
+				     void *private);
+static int finish_eattr_indir(struct gfs2_inode *ip, int indir_ok,
+			      enum update_flags *want_updated, void *private);
+
+struct metawalk_fxns pass1_fxns = {
+	.private = NULL,
+	.check_leaf = leaf,
+	.check_metalist = check_metalist,
+	.check_data = check_data,
+	.check_eattr_indir = check_eattr_indir,
+	.check_eattr_leaf = check_eattr_leaf,
+	.check_dentry = NULL,
+	.check_eattr_entry = check_eattr_entries,
+	.check_eattr_extentry = check_extended_leaf_eattr,
+	.finish_eattr_indir = finish_eattr_indir,
+};
+
+static int leaf(struct gfs2_inode *ip, uint64_t block,
+		struct gfs2_buffer_head *bh, void *private)
 {
 	struct block_count *bc = (struct block_count *) private;
 
 	log_debug("\tLeaf block at %15" PRIu64 " (0x%" PRIx64 ")\n",
 			  block, block);
-	gfs2_block_set(bl, block, gfs2_leaf_blk);
+	gfs2_block_set(ip->i_sbd, bl, block, gfs2_leaf_blk);
 	bc->indir_count++;
 	return 0;
 }
 
 static int check_metalist(struct gfs2_inode *ip, uint64_t block,
-						  struct gfs2_buffer_head **bh, void *private)
+			  struct gfs2_buffer_head **bh, void *private)
 {
 	struct gfs2_block_query q = {0};
 	int found_dup = 0;
@@ -66,19 +104,20 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
 	*bh = NULL;
 
 	if (gfs2_check_range(ip->i_sbd, block)){ /* blk outside of FS */
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_bad_block);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
+			       gfs2_bad_block);
 		log_debug("Bad indirect block pointer (out of range).\n");
 
 		return 1;
 	}
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	if(q.block_type != gfs2_block_free) {
 		log_debug("Found duplicate block in indirect block -"
 				  " was marked %d\n", q.block_type);
-		gfs2_block_mark(bl, block, gfs2_dup_block);
+		gfs2_block_mark(ip->i_sbd, bl, block, gfs2_dup_block);
 		found_dup = 1;
 	}
 	nbh = bread(ip->i_sbd, block);
@@ -87,7 +126,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
 		log_debug("Bad indirect block pointer "
 				  "(points to something that is not an indirect block).\n");
 		if(!found_dup) {
-			gfs2_block_set(bl, block, gfs2_meta_inval);
+			gfs2_block_set(ip->i_sbd, bl, block, gfs2_meta_inval);
 			brelse(nbh, not_updated);
 			return 1;
 		}
@@ -96,7 +135,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
 
 	log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to indirect block.\n",
 			  block, block);
-	gfs2_block_set(bl, block, gfs2_indir_blk);
+	gfs2_block_set(ip->i_sbd, bl, block, gfs2_indir_blk);
 	bc->indir_count++;
 
 	return 0;
@@ -111,30 +150,77 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
 		log_err( "Bad data block pointer (out of range)\n");
 		/* Mark the owner of this block with the bad_block
 		 * designator so we know to check it for out of range blocks later */
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_bad_block);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
+			       gfs2_bad_block);
 		return 1;
 	}
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	if(q.block_type != gfs2_block_free) {
 		log_debug("Found duplicate block at %" PRIu64 " (0x%"PRIx64 ")\n",
 				  block, block);
-		gfs2_block_mark(bl, block, gfs2_dup_block);
+		gfs2_block_mark(ip->i_sbd, bl, block, gfs2_dup_block);
 		bc->data_count++;
 		return 1;
 	}
 	log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to data block\n", block,
 			  block);
-	gfs2_block_set(bl, block, gfs2_block_used);
+	gfs2_block_set(ip->i_sbd, bl, block, gfs2_block_used);
 	bc->data_count++;
 	return 0;
 }
 
+/* clear_eas - clear the extended attributes for an inode
+ *
+ * @ip       - in core inode pointer
+ * @bc       - pointer to a block count structure
+ * block     - the block that had the problem
+ * duplicate - if this is a duplicate block, don't set it "free"
+ * emsg      - what to tell the user about the eas being checked
+ * Returns: 1 if the EA is fixed, else 0 if it was not fixed.
+ */
+static int clear_eas(struct gfs2_inode *ip, struct block_count *bc,
+		     uint64_t block, int duplicate,
+		     enum update_flags *want_updated, const char *emsg)
+{
+	struct gfs2_sbd *sdp = ip->i_sbd;
+
+	*want_updated = not_updated;
+	log_err("Inode #%" PRIu64 " (0x%" PRIx64 "): %s",
+		ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr, emsg);
+	if (block)
+		log_err(" at block #%" PRIu64 " (0x%" PRIx64 ")",
+			block, block);
+	log_err(".\n");
+	if (query(&opts, "Clear the bad EA? (y/n) ")) {
+		if (block == 0)
+			block = ip->i_di.di_eattr;
+		gfs2_block_clear(sdp, bl, block, gfs2_eattr_block);
+		if (!duplicate) {
+			gfs2_block_clear(sdp, bl, block, gfs2_indir_blk);
+			gfs2_block_set(sdp, bl, block, gfs2_block_free);
+			gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
+		}
+		ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+		if (block == ip->i_di.di_eattr)
+			ip->i_di.di_eattr = 0;
+		bc->ea_count = 0;
+		ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
+		gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
+		*want_updated = updated;
+		return 1;
+	} else {
+		log_err("The bad EA was not fixed.\n");
+		bc->ea_count++;
+		return 0;
+	}
+}
+
 static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
-							 uint64_t parent, struct gfs2_buffer_head **bh,
-							 void *private)
+			     uint64_t parent, struct gfs2_buffer_head **bh,
+			     enum update_flags *want_updated, void *private)
 {
 	struct gfs2_sbd *sdp = ip->i_sbd;
 	int ret = 0;
@@ -146,48 +232,67 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
 	if(gfs2_check_range(sdp, indirect)) {
 		/*log_warn("EA indirect block #%"PRIu64" is out of range.\n",
 			indirect);
-			gfs2_block_set(bl, parent, bad_block);*/
+			gfs2_block_set(sdp, bl, parent, bad_block);*/
 		/* Doesn't help to mark this here - this gets checked
 		 * in pass1c */
-		ret = 1;
+		return 1;
 	}
-	else if(gfs2_block_check(bl, indirect, &q)) {
+	if(gfs2_block_check(sdp, bl, indirect, &q)) {
 		stack;
-		ret = -1;
+		return -1;
+	}
+
+	/* Special duplicate processing:  If we have an EA block,
+	   check if it really is an EA.  If it is, let duplicate
+	   handling sort it out.  If it isn't, clear it but don't
+	   count it as a duplicate. */
+	*bh = bread(sdp, indirect);
+	if(gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
+		if(q.block_type != gfs2_block_free) { /* Duplicate? */
+			if (!clear_eas(ip, bc, indirect, 1, want_updated,
+				       "Bad indirect EA duplicate found"))
+				gfs2_block_set(sdp, bl, indirect,
+					       gfs2_dup_block);
+			return 1;
+		}
+		clear_eas(ip, bc, indirect, 0, want_updated,
+			  "EA indirect block has incorrect type");
+		return 1;
 	}
-	else if(q.block_type != gfs2_block_free) {
-		log_debug("Duplicate block found at #%" PRIu64 " (0x%" PRIx64 ").\n",
-				  indirect, indirect);
-		gfs2_block_set(bl, indirect, gfs2_dup_block);
+	if(q.block_type != gfs2_block_free) { /* Duplicate? */
+		log_err("Inode #%" PRIu64 " (0x%" PRIx64
+			"): Duplicate EA indirect block found at #%" PRIu64
+			" (0x%" PRIx64 ").\n",
+			ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr,
+			indirect, indirect);
+		gfs2_block_set(sdp, bl, indirect, gfs2_dup_block);
 		bc->ea_count++;
 		ret = 1;
+	} else {
+		log_debug("Setting #%" PRIu64 " (0x%" PRIx64
+			  ") to indirect EA block\n", indirect, indirect);
+		gfs2_block_set(sdp, bl, indirect, gfs2_indir_blk);
+		bc->ea_count++;
 	}
-	else {
-		log_debug("Marking inode %" PRIu64 " (0x%"
+	return ret;
+}
+
+static int finish_eattr_indir(struct gfs2_inode *ip, int indir_ok,
+			      enum update_flags *want_updated, void *private)
+{
+	if (indir_ok) {
+		log_debug("Marking inode #%" PRIu64 " (0x%"
 			  PRIx64 ") with eattr block\n",
 			  ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 		/* Mark the inode as having an eattr in the block map
 		   so pass1c can check it. */
-		gfs2_block_mark(bl, ip->i_di.di_num.no_addr, gfs2_eattr_block);
-
-		*bh = bread(sdp, indirect);
-		if(gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
-			log_warn("EA indirect block %" PRIu64 " (0x%" PRIx64
-				 ") has incorrect type.\n",
-				 indirect, indirect);
-			gfs2_block_set(bl, indirect, gfs2_meta_inval);
-			ret = 1;
-			brelse(*bh, not_updated);
-		}
-		else {
-			/* FIXME: do i need to differentiate this as an ea_indir? */
-			log_debug("Setting %" PRIu64 " (0x%" PRIx64
-				  ") to indirect block\n", indirect, indirect);
-			gfs2_block_set(bl, indirect, gfs2_indir_blk);
-			bc->ea_count++;
-		}
+		gfs2_block_mark(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
+				gfs2_eattr_block);
+		return 0;
 	}
-	return ret;
+	clear_eas(ip, (struct block_count *)private, 0, 0, want_updated,
+		  "has unrecoverable indirect EA errors");
+	return 0;
 }
 
 /**
@@ -205,6 +310,7 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
 				     struct gfs2_buffer_head *leaf_bh,
 				     struct gfs2_ea_header *ea_hdr,
 				     struct gfs2_ea_header *ea_hdr_prev,
+				     enum update_flags *want_updated,
 				     void *private)
 {
 	struct gfs2_buffer_head *el_buf;
@@ -212,45 +318,60 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
 	struct gfs2_block_query q;
 	uint64_t el_blk = be64_to_cpu(*data_ptr);
 	struct block_count *bc = (struct block_count *) private;
+	int ret = 0;
 
 	if(gfs2_check_range(sdp, el_blk)){
-		log_err("EA extended leaf block #%" PRIu64 " (0x%" PRIx64
-				") is out of range.\n",	el_blk, el_blk);
-		gfs2_block_set(bl, ip->i_di.di_eattr, gfs2_bad_block);
+		log_err("Inode #%" PRIu64 " (0x%" PRIx64 "): EA extended "
+			"leaf block #%" PRIu64 " (0x%" PRIx64
+			") is out of range.\n",
+			ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr,
+			el_blk, el_blk);
+		gfs2_block_set(sdp, bl, ip->i_di.di_eattr, gfs2_bad_block);
 		return 1;
 	}
 
-	if(gfs2_block_check(bl, el_blk, &q)) {
+	if(gfs2_block_check(sdp, bl, el_blk, &q)) {
 		stack;
 		return -1;
 	}
-	if(q.block_type != gfs2_block_free) {
-		gfs2_block_set(bl, el_blk, gfs2_dup_block);
-		bc->ea_count++;
-		return 1;
-	}
-
 	el_buf = bread(sdp, el_blk);
 
+	/* Special duplicate processing:  If we have an EA block,
+	   check if it really is an EA.  If it is, let duplicate
+	   handling sort it out.  If it isn't, clear it but don't
+	   count it as a duplicate. */
 	if(gfs2_check_meta(el_buf, GFS2_METATYPE_ED)) {
-		log_err("EA extended leaf block %" PRIu64 " (0x%" PRIx64
-				") has incorrect type.\n", el_blk, el_blk);
-		brelse(el_buf, not_updated);
-		gfs2_block_set(bl, el_blk, gfs2_meta_inval);
-		return 1;
+		if(q.block_type != gfs2_block_free) /* Duplicate? */
+			clear_eas(ip, bc, el_blk, 1, want_updated,
+				  "has bad extended EA duplicate");
+		else
+			clear_eas(ip, bc, el_blk, 0, want_updated,
+				  "EA extended leaf block has incorrect type");
+		ret = 1;
+	} else { /* If this looks like an EA */
+		if(q.block_type != gfs2_block_free) { /* Duplicate? */
+			log_debug("Duplicate block found at #%" PRIu64
+				  " (0x%" PRIx64 ").\n",
+				  el_blk, el_blk);
+			gfs2_block_set(sdp, bl, el_blk, gfs2_dup_block);
+			bc->ea_count++;
+			ret = 1;
+		} else {
+			log_debug("Setting block #%" PRIu64
+				  " (0x%" PRIx64 ") to eattr block\n",
+				  el_blk, el_blk);
+			gfs2_block_set(sdp, bl, el_blk, gfs2_meta_eattr);
+			bc->ea_count++;
+		}
 	}
 
-	log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to eattr block\n",
-			  el_blk, el_blk);
-	gfs2_block_set(bl, el_blk, gfs2_meta_eattr);
-	bc->ea_count++;
 	brelse(el_buf, not_updated);
-	return 0;
+	return ret;
 }
 
 static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 			    uint64_t parent, struct gfs2_buffer_head **bh,
-			    void *private)
+			    enum update_flags *want_updated, void *private)
 {
 	struct gfs2_sbd *sdp = ip->i_sbd;
 	struct gfs2_buffer_head *leaf_bh = NULL;
@@ -263,47 +384,57 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 	if (parent != ip->i_di.di_num.no_addr) { /* if parent isn't the inode */
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to eattr block\n",
 				  parent, parent);
-		gfs2_block_set(bl, parent, gfs2_eattr_block);
+		gfs2_block_set(sdp, bl, parent, gfs2_eattr_block);
 	}
 	if(gfs2_check_range(sdp, block)){
-		log_warn("EA leaf block #%" PRIu64 " (0x%" PRIx64 ") in inode %" PRIu64
-				 " (0x%" PRIx64 ") is out of range.\n",
-				 ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr,
-				 block, block);
-		gfs2_block_set(bl, ip->i_di.di_eattr, gfs2_bad_block);
+		log_warn("Inode #%" PRIu64 " (0x%" PRIx64 "): EA leaf block "
+			 "#%" PRIu64 " (0x%" PRIx64 ") is out of range.\n",
+			 ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr,
+			 block, block);
+		gfs2_block_set(sdp, bl, ip->i_di.di_eattr, gfs2_bad_block);
 		ret = 1;
 	}
-	else if(gfs2_block_check(bl, block, &q)) {
+	else if(gfs2_block_check(sdp, bl, block, &q)) {
 		stack;
 		return -1;
 	}
-	else if(q.block_type != gfs2_block_free) {
-		log_debug("Duplicate block found at #%" PRIu64 " (0x%" PRIx64 ").\n",
-				  block, block);
-		gfs2_block_set(bl, block, gfs2_dup_block);
-		bc->ea_count++;
-		ret = 1;
-	}
 	else {
+		/* Special duplicate processing:  If we have an EA block,
+		   check if it really is an EA.  If it is, let duplicate
+		   handling sort it out.  If it isn't, clear it but don't
+		   count it as a duplicate. */
 		leaf_bh = bread(sdp, block);
 		if(gfs2_check_meta(leaf_bh, GFS2_METATYPE_EA)) {
-			log_warn("EA leaf block %"PRIu64" (0x%" 
-				 PRIx64") for inode %"PRIu64" (0x%"
-				 PRIx64") has incorrect type.\n",
-				 block, block, ip->i_di.di_num.no_addr,
-				 ip->i_di.di_num.no_addr);
-			gfs2_block_set(bl, block, gfs2_meta_inval);
-			ret = -1;
+			if(q.block_type != gfs2_block_free) { /* Duplicate? */
+				clear_eas(ip, bc, block, 1, want_updated,
+					  "Bad EA duplicate found");
+			} else {
+				clear_eas(ip, bc, block, 0, want_updated,
+					  "EA leaf block has incorrect type");
+			}
+			ret = 1;
 			brelse(leaf_bh, not_updated);
-		}
-		else {
-			log_debug("Setting block %" PRIu64 " (0x%" PRIx64
-					  ") to eattr block\n", block, block);
-			gfs2_block_set(bl, block, gfs2_meta_eattr);
-			bc->ea_count++;
+		} else { /* If this looks like an EA */
+			if(q.block_type != gfs2_block_free) { /* Duplicate? */
+				log_debug("Duplicate block found at #%" PRIu64
+					  " (0x%" PRIx64 ").\n",
+					  block, block);
+				gfs2_block_set(sdp, bl, block, gfs2_dup_block);
+				bc->ea_count++;
+				ret = 1;
+				brelse(leaf_bh, not_updated);
+			} else {
+				log_debug("Setting block #%" PRIu64
+					  " (0x%" PRIx64 ") to eattr block\n",
+					  block, block);
+				gfs2_block_set(sdp, bl, block,
+					       gfs2_meta_eattr);
+				bc->ea_count++;
+			}
 		}
 	}
-	*bh = leaf_bh;
+	if (!ret)
+		*bh = leaf_bh;
 
 	return ret;
 }
@@ -349,18 +480,6 @@ static int check_eattr_entries(struct gfs2_inode *ip,
 	return 0;
 }
 
-struct metawalk_fxns pass1_fxns = {
-	.private = NULL,
-	.check_leaf = leaf,
-	.check_metalist = check_metalist,
-	.check_data = check_data,
-	.check_eattr_indir = check_eattr_indir,
-	.check_eattr_leaf = check_eattr_leaf,
-	.check_dentry = NULL,
-	.check_eattr_entry = check_eattr_entries,
-	.check_eattr_extentry = check_extended_leaf_eattr,
-};
-
 int clear_metalist(struct gfs2_inode *ip, uint64_t block,
 		   struct gfs2_buffer_head **bh, void *private)
 {
@@ -368,12 +487,12 @@ int clear_metalist(struct gfs2_inode *ip, uint64_t block,
 
 	*bh = NULL;
 
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	if(!q.dup_block) {
-		gfs2_block_set(bl, block, gfs2_block_free);
+		gfs2_block_set(ip->i_sbd, bl, block, gfs2_block_free);
 		return 0;
 	}
 	return 0;
@@ -383,12 +502,12 @@ int clear_data(struct gfs2_inode *ip, uint64_t block, void *private)
 {
 	struct gfs2_block_query q = {0};
 
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	if(!q.dup_block) {
-		gfs2_block_set(bl, block, gfs2_block_free);
+		gfs2_block_set(ip->i_sbd, bl, block, gfs2_block_free);
 		return 0;
 	}
 	return 0;
@@ -399,16 +518,16 @@ int clear_leaf(struct gfs2_inode *ip, uint64_t block,
 	       struct gfs2_buffer_head *bh, void *private)
 {
 	struct gfs2_block_query q = {0};
-	log_crit("Clearing leaf %" PRIu64 " (0x%" PRIx64 ")\n", block, block);
+	log_crit("Clearing leaf #%" PRIu64 " (0x%" PRIx64 ")\n", block, block);
 
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(ip->i_sbd, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	if(!q.dup_block) {
-		log_crit("Setting leaf %" PRIu64 " (0x%" PRIx64 ") invalid\n",
+		log_crit("Setting leaf #%" PRIu64 " (0x%" PRIx64 ") invalid\n",
 				 block, block);
-		if(gfs2_block_set(bl, block, gfs2_block_free)) {
+		if(gfs2_block_set(ip->i_sbd, bl, block, gfs2_block_free)) {
 			stack;
 			return -1;
 		}
@@ -429,7 +548,7 @@ int add_to_dir_list(struct gfs2_sbd *sbp, uint64_t block)
 	 * matter too much */
 	find_di(sbp, block, &di);
 	if(di) {
-		log_err("Attempting to add directory block %" PRIu64
+		log_err("Attempting to add directory block #%" PRIu64
 				" (0x%" PRIx64 ") which is already in list\n", block, block);
 		return -1;
 	}
@@ -469,25 +588,25 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				"): Bad inode address found: %"	PRIu64 " (0x%" PRIx64 ")\n",
 				block, block, ip->i_di.di_num.no_addr,
 				ip->i_di.di_num.no_addr);
-		if(query(&opts, "Fix address in inode at block %"
+		if(query(&opts, "Fix address in inode at block #%"
 				 PRIu64 " (0x%" PRIx64 ")? (y/n) ", block, block)) {
 			ip->i_di.di_num.no_addr = ip->i_di.di_num.no_formal_ino = block;
 			gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
 			f = updated;
 		} else
-			log_err("Address in inode at block %" PRIu64
+			log_err("Address in inode at block #%" PRIu64
 				 " (0x%" PRIx64 ") not fixed\n", block, block);
 	}
 
-	if(gfs2_block_check(bl, block, &q)) {
+	if(gfs2_block_check(sdp, bl, block, &q)) {
 		stack;
 		fsck_inode_put(ip, f);
 		return -1;
 	}
 	if(q.block_type != gfs2_block_free) {
-		log_debug("Found duplicate block at %" PRIu64 " (0x%" PRIx64 ")\n",
+		log_debug("Found duplicate block at #%" PRIu64 " (0x%" PRIx64 ")\n",
 				  block, block);
-		if(gfs2_block_mark(bl, block, gfs2_dup_block)) {
+		if(gfs2_block_mark(sdp, bl, block, gfs2_dup_block)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -501,7 +620,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFDIR:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to directory inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_dir)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_dir)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -515,7 +634,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFREG:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to file inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_file)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_file)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -524,7 +643,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFLNK:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to symlink inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_lnk)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_lnk)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -533,7 +652,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFBLK:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to block dev inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_blk)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_blk)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -542,7 +661,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFCHR:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to char dev inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_chr)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_chr)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -551,7 +670,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFIFO:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to fifo inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_fifo)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_fifo)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -560,7 +679,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	case S_IFSOCK:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to socket inode.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_inode_sock)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_inode_sock)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
@@ -569,11 +688,12 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	default:
 		log_debug("Setting %" PRIu64 " (0x%" PRIx64 ") to invalid.\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_meta_inval)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
 		}
+		gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
 		fsck_inode_put(ip, f);
 		return 0;
 	}
@@ -592,11 +712,12 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				 compute_height(sdp, ip->i_di.di_size));
 			/* once implemented, remove continue statement */
 		log_warn("Marking inode invalid\n");
-		if(gfs2_block_set(bl, block, gfs2_meta_inval)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 			stack;
 			fsck_inode_put(ip, f);
 			return -1;
 		}
+		gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
 		fsck_inode_put(ip, f);
 		return 0;
 	}
@@ -611,11 +732,12 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 					 (1 >> (ip->i_di.di_size/sizeof(uint64_t))));
 			/* once implemented, remove continue statement */
 			log_warn("Marking inode invalid\n");
-			if(gfs2_block_set(bl, block, gfs2_meta_inval)) {
+			if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 				stack;
 				fsck_inode_put(ip, f);
 				return -1;
 			}
+			gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
 			fsck_inode_put(ip, f);
 			return 0;
 		}
@@ -629,23 +751,22 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 		return 0;
 	}
 	if(error > 0) {
-		log_warn("Marking inode invalid\n");
+		log_warn("Marking inode #%" PRIu64 " (0x%" PRIx64 ") invalid\n",
+			 ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 		/* FIXME: Must set all leaves invalid as well */
 		check_metatree(ip, &invalidate_metatree);
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_meta_inval);
+		gfs2_block_set(sdp, bl, ip->i_di.di_num.no_addr,
+			       gfs2_meta_inval);
+		gfs2_set_bitmap(sdp, ip->i_di.di_num.no_addr, GFS2_BLKST_FREE);
 		fsck_inode_put(ip, f);
 		return 0;
 	}
 
-	if(check_inode_eattr(ip, &pass1_fxns) < 0){
-		ip->i_di.di_eattr = 0;
-		gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
-		f = updated;
-	}
+	check_inode_eattr(ip, &f, &pass1_fxns);
 
 	if (ip->i_di.di_blocks != 
 		(1 + bc.indir_count + bc.data_count + bc.ea_count)) {
-		log_err("Inode %" PRIu64 " (0x%" PRIx64 "): Ondisk block count (%"
+		log_err("Inode #%" PRIu64 " (0x%" PRIx64 "): Ondisk block count (%"
 				PRIu64 ") does not match what fsck found (%" PRIu64 ")\n",
 				ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr,
 				ip->i_di.di_blocks,
@@ -656,7 +777,7 @@ int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 			gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
 			f = updated;
 		} else
-			log_err("Bad block count for %" PRIu64 " (0x%" PRIx64
+			log_err("Bad block count for #%" PRIu64 " (0x%" PRIx64
 					") not fixed\n", ip->i_di.di_num.no_addr,
 					ip->i_di.di_num.no_addr);
 	}
@@ -669,16 +790,17 @@ int scan_meta(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 			  uint64_t block)
 {
 	if (gfs2_check_meta(bh, 0)) {
-		log_debug("Found invalid metadata at %" PRIu64 " (0x%" PRIx64 ")\n",
+		log_debug("Found invalid metadata at #%" PRIu64 " (0x%" PRIx64 ")\n",
 				  block, block);
-		if(gfs2_block_set(bl, block, gfs2_meta_inval)) {
+		if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 			stack;
 			return -1;
 		}
+		gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
 		return 0;
 	}
 
-	log_debug("Checking metadata block %" PRIu64 " (0x%" PRIx64 ")\n", block,
+	log_debug("Checking metadata block #%" PRIu64 " (0x%" PRIx64 ")\n", block,
 			  block);
 
 	if (!gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
@@ -752,7 +874,8 @@ int pass1(struct gfs2_sbd *sbp)
 		log_debug("RG at %" PRIu64 " (0x%" PRIx64 ") is %u long\n",
 				  rgd->ri.ri_addr, rgd->ri.ri_addr, rgd->ri.ri_length);
 		for (i = 0; i < rgd->ri.ri_length; i++) {
-			if(gfs2_block_set(bl, rgd->ri.ri_addr + i, gfs2_meta_other)){
+			if(gfs2_block_set(sbp, bl, rgd->ri.ri_addr + i,
+					  gfs2_meta_other)){
 				stack;
 				return -1;
 			}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 2b0ab50..0fcfc06 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -77,11 +77,13 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
 }
 
 static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
-			     uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+			     uint64_t parent, struct gfs2_buffer_head **bh,
+			     enum update_flags *want_updated, void *private)
 {
 	struct gfs2_sbd *sbp = ip->i_sbd;
 	struct gfs2_buffer_head *indir_bh = NULL;
 
+	*want_updated = not_updated;
 	inc_if_found(block, 0, private);
 	indir_bh = bread(sbp, block);
 	*bh = indir_bh;
@@ -90,11 +92,13 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 }
 
 static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-			    uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+			    uint64_t parent, struct gfs2_buffer_head **bh,
+			    enum update_flags *want_updated, void *private)
 {
 	struct gfs2_sbd *sbp = ip->i_sbd;
 	struct gfs2_buffer_head *leaf_bh = NULL;
 
+	*want_updated = not_updated;
 	inc_if_found(block, 0, private);
 	leaf_bh = bread(sbp, block);
 
@@ -115,10 +119,11 @@ static int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
 				struct gfs2_buffer_head *leaf_bh,
 				struct gfs2_ea_header *ea_hdr,
 				struct gfs2_ea_header *ea_hdr_prev,
-				void *private)
+				enum update_flags *want_updated, void *private)
 {
 	uint64_t block = be64_to_cpu(*ea_data_ptr);
 
+	*want_updated = not_updated;
 	inc_if_found(block, 0, private);
 
 	return 0;
@@ -126,15 +131,15 @@ static int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
 
 static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
 		       struct gfs2_dirent *prev,
-		       struct gfs2_buffer_head *bh, char *filename, int *update,
-		       uint16_t *count, void *priv)
+		       struct gfs2_buffer_head *bh, char *filename,
+		       enum update_flags *update, uint16_t *count, void *priv)
 {
 	osi_list_t *tmp1, *tmp2;
 	struct blocks *b;
 	struct inode_with_dups *id;
 	struct gfs2_leaf leaf;
 
-	osi_list_foreach(tmp1, &dup_list) {
+	osi_list_foreach(tmp1, &ip->i_sbd->dup_blocks.list) {
 		b = osi_list_entry(tmp1, struct blocks, list);
 		osi_list_foreach(tmp2, &b->ref_inode_list) {
 			id = osi_list_entry(tmp2, struct inode_with_dups,
@@ -184,7 +189,8 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
 		inode_hash_remove(inode_hash, ip->i_di.di_num.no_addr);
 		/* Setting the block to invalid means the inode is
 		 * cleared in pass2 */
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_meta_inval);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
+			       gfs2_meta_inval);
 	}
 	return 0;
 }
@@ -208,19 +214,22 @@ static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
 		inode_hash_remove(inode_hash, ip->i_di.di_num.no_addr);
 		/* Setting the block to invalid means the inode is
 		 * cleared in pass2 */
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_meta_inval);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
+			       gfs2_meta_inval);
 	}
 
 	return 0;
 }
 static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 				 uint64_t parent, struct gfs2_buffer_head **bh,
+				 enum update_flags *want_updated,
 				 void *private)
 {
 	struct dup_handler *dh = (struct dup_handler *) private;
 	/* Can't use fxns from eattr.c since we need to check the ref
 	 * count */
 	*bh = NULL;
+	*want_updated = not_updated;
 	if(dh->ref_count == 1)
 		return 1;
 	if(block == dh->b->block_no) {
@@ -232,16 +241,20 @@ static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 		log_err("Inode %s is in directory %" PRIu64 " (0x%" PRIx64 ")\n",
 				dh->id->name ? dh->id->name : "",
 				dh->id->parent, dh->id->parent);
-		gfs2_block_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_eattr,
+			       gfs2_meta_inval);
 	}
 
 	return 0;
 }
 
 static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-				uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+				uint64_t parent, struct gfs2_buffer_head **bh,
+				enum update_flags *want_updated, void *private)
 {
 	struct dup_handler *dh = (struct dup_handler *) private;
+
+	*want_updated = not_updated;
 	if(dh->ref_count == 1)
 		return 1;
 	if(block == dh->b->block_no) {
@@ -254,7 +267,8 @@ static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 				dh->id->name ? dh->id->name : "",
 				dh->id->parent, dh->id->parent);
 		/* mark the main eattr block invalid */
-		gfs2_block_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_eattr,
+			       gfs2_meta_inval);
 	}
 
 	return 0;
@@ -303,11 +317,16 @@ static int clear_eattr_entry (struct gfs2_inode *ip,
 }
 
 static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
-			 struct gfs2_buffer_head *leaf_bh, struct gfs2_ea_header *ea_hdr,
-			 struct gfs2_ea_header *ea_hdr_prev, void *private)
+				struct gfs2_buffer_head *leaf_bh,
+				struct gfs2_ea_header *ea_hdr,
+				struct gfs2_ea_header *ea_hdr_prev,
+				enum update_flags *want_updated,
+				void *private)
 {
 	uint64_t block = be64_to_cpu(*ea_data_ptr);
 	struct dup_handler *dh = (struct dup_handler *) private;
+
+	*want_updated = not_updated;
 	if(dh->ref_count == 1)
 		return 1;
 	if(block == dh->b->block_no) {
@@ -320,7 +339,8 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
 				dh->id->name ? dh->id->name : "",
 				dh->id->parent, dh->id->parent);
 		/* mark the main eattr block invalid */
-		gfs2_block_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_eattr,
+			       gfs2_meta_inval);
 	}
 
 	return 0;
@@ -344,6 +364,7 @@ int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct blocks *b)
 		.check_eattr_entry = check_eattr_entry,
 		.check_eattr_extentry = check_eattr_extentry,
 	};
+	enum update_flags update;
 
 	ip = fsck_load_inode(sbp, inode); /* bread, inode_get */
 	log_info("Checking inode %" PRIu64 " (0x%" PRIx64
@@ -356,7 +377,7 @@ int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct blocks *b)
 	}
 	log_info("Done checking metatree\n");
 	/* Check for ea references in the inode */
-	if(check_inode_eattr(ip, &find_refs) < 0){
+	if(check_inode_eattr(ip, &update, &find_refs) < 0){
 		stack;
 		fsck_inode_put(ip, not_updated); /* out, brelse, free */
 		return -1;
@@ -382,33 +403,6 @@ int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct blocks *b)
 	return 0;
 }
 
-/* Finds all blocks marked in the duplicate block bitmap */
-int find_dup_blocks(struct gfs2_sbd *sbp)
-{
-	uint64_t block_no = 0;
-	struct blocks *b;
-
-	while (!gfs2_find_next_block_type(bl, gfs2_dup_block, &block_no)) {
-		if(!(b = malloc(sizeof(*b)))) {
-			log_crit("Unable to allocate blocks structure\n");
-			return -1;
-		}
-		if(!memset(b, 0, sizeof(*b))) {
-			log_crit("Unable to zero blocks structure\n");
-			return -1;
-		}
-		b->block_no = block_no;
-		osi_list_init(&b->ref_inode_list);
-		log_notice("Found dup block at %"PRIu64" (0x%" PRIx64 ")\n", block_no,
-				   block_no);
-		osi_list_add(&b->list, &dup_list);
-		block_no++;
-	}
-	return 0;
-}
-
-
-
 int handle_dup_blk(struct gfs2_sbd *sbp, struct blocks *b)
 {
 	osi_list_t *tmp;
@@ -426,6 +420,7 @@ int handle_dup_blk(struct gfs2_sbd *sbp, struct blocks *b)
 	};
 	struct gfs2_inode *ip;
 	struct dup_handler dh = {0};
+	enum update_flags update;
 
 	osi_list_foreach(tmp, &b->ref_inode_list) {
 		id = osi_list_entry(tmp, struct inode_with_dups, list);
@@ -449,7 +444,7 @@ int handle_dup_blk(struct gfs2_sbd *sbp, struct blocks *b)
 		dh.id = id;
 		clear_dup_fxns.private = (void *) &dh;
 		/* Clear the EAs for the inode first */
-		check_inode_eattr(ip, &clear_dup_fxns);
+		check_inode_eattr(ip, &update, &clear_dup_fxns);
 		/* If the dup wasn't only in the EA, clear the inode */
 		if(!id->ea_only)
 			check_metatree(ip, &clear_dup_fxns);
@@ -480,13 +475,10 @@ int pass1b(struct gfs2_sbd *sbp)
 	find_dirents.check_dentry = &find_dentry;
 	int rc = 0;
 
-	osi_list_init(&dup_list);
-	/* Shove all blocks marked as duplicated into a list */
 	log_info("Looking for duplicate blocks...\n");
-	find_dup_blocks(sbp);
 
 	/* If there were no dups in the bitmap, we don't need to do anymore */
-	if(osi_list_empty(&dup_list)) {
+	if(osi_list_empty(&sbp->dup_blocks.list)) {
 		log_info("No duplicate blocks found\n");
 		return 0;
 	}
@@ -502,7 +494,7 @@ int pass1b(struct gfs2_sbd *sbp)
 			goto out;
 		log_debug("Scanning block %" PRIu64 " (0x%" PRIx64 ") for inodes\n",
 				  i, i);
-		if(gfs2_block_check(bl, i, &q)) {
+		if(gfs2_block_check(sbp, bl, i, &q)) {
 			stack;
 			rc = -1;
 			goto out;
@@ -514,7 +506,7 @@ int pass1b(struct gfs2_sbd *sbp)
 		   (q.block_type == gfs2_inode_chr) ||
 		   (q.block_type == gfs2_inode_fifo) ||
 		   (q.block_type == gfs2_inode_sock)) {
-			osi_list_foreach(tmp, &dup_list) {
+			osi_list_foreach(tmp, &sbp->dup_blocks.list) {
 				b = osi_list_entry(tmp, struct blocks, list);
 				if(find_block_ref(sbp, i, b)) {
 					stack;
@@ -532,8 +524,9 @@ int pass1b(struct gfs2_sbd *sbp)
 	 * it later */
 	log_info("Handling duplicate blocks\n");
 out:
-	while (!osi_list_empty(&dup_list)) {
-		b = osi_list_entry(dup_list.next, struct blocks, list);
+	while (!osi_list_empty(&sbp->dup_blocks.list)) {
+		b = osi_list_entry(&sbp->dup_blocks.list.next, struct blocks,
+				   list);
 		if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
 			handle_dup_blk(sbp, b);
 		osi_list_del(&b->list);
diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c
index 12a0cc8..4e42021 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -22,12 +22,12 @@
 #include "metawalk.h"
 
 static int remove_eattr_entry(struct gfs2_sbd *sdp,
-							  struct gfs2_buffer_head *leaf_bh,
-							  struct gfs2_ea_header *curr,
-							  struct gfs2_ea_header *prev)
+			      struct gfs2_buffer_head *leaf_bh,
+			      struct gfs2_ea_header *curr,
+			      struct gfs2_ea_header *prev)
 {
 	log_warn("Removing EA located in block #%"PRIu64" (0x%" PRIx64 ").\n",
-			 leaf_bh->b_blocknr, leaf_bh->b_blocknr);
+		 leaf_bh->b_blocknr, leaf_bh->b_blocknr);
 	if(!prev)
 		curr->ea_type = GFS2_EATYPE_UNUSED;
 	else {
@@ -42,25 +42,33 @@ static int remove_eattr_entry(struct gfs2_sbd *sdp,
 
 int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 		      uint64_t parent, struct gfs2_buffer_head **bh,
-		      void *private)
+		      enum update_flags *update, void *private)
 {
-	int *update = (int *) private;
 	struct gfs2_sbd *sbp = ip->i_sbd;
 	struct gfs2_block_query q;
 	struct gfs2_buffer_head *indir_bh = NULL;
 
+	*update = not_updated;
 	if(gfs2_check_range(sbp, block)) {
-		log_err("Extended attributes indirect block out of range...removing\n");
+		log_err("Extended attributes indirect block #%"PRIu64
+			" (0x%" PRIx64 ") for inode #%" PRIu64
+			" (0x%" PRIx64 ") out of range...removing\n",
+			block, block, ip->i_di.di_num.no_addr,
+			ip->i_di.di_num.no_addr);
 		ip->i_di.di_eattr = 0;
 		*update = (opts.no ? not_updated : updated);
 		return 1;
 	}
-	else if (gfs2_block_check(bl, block, &q)) {
+	else if (gfs2_block_check(sbp, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	else if(q.block_type != gfs2_indir_blk) {
-		log_err("Extended attributes indirect block invalid...removing\n");
+		log_err("Extended attributes indirect block #%"PRIu64
+			" (0x%" PRIx64 ") for inode #%" PRIu64
+			" (0x%" PRIx64 ") invalid...removing\n",
+			block, block, ip->i_di.di_num.no_addr,
+			ip->i_di.di_num.no_addr);
 		ip->i_di.di_eattr = 0;
 		*update = (opts.no ? not_updated : updated);
 		return 1;
@@ -71,25 +79,31 @@ int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 	*bh = indir_bh;
 	return 0;
 }
+
 int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-		     uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+		     uint64_t parent, struct gfs2_buffer_head **bh,
+		     enum update_flags *update, void *private)
 {
-	int *update = (int *) private;
 	struct gfs2_sbd *sbp = ip->i_sbd;
 	struct gfs2_block_query q;
 
+	*update = not_updated;
 	if(gfs2_check_range(sbp, block)) {
-		log_err("Extended attributes block out of range...removing\n");
+		log_err("Extended attributes block for inode #%" PRIu64
+			" (0x%" PRIx64 ") out of range...removing\n",
+			ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 		ip->i_di.di_eattr = 0;
 		*update = (opts.no ? not_updated : updated);
 		return 1;
 	}
-	else if (gfs2_block_check(bl, block, &q)) {
+	else if (gfs2_block_check(sbp, bl, block, &q)) {
 		stack;
 		return -1;
 	}
 	else if(q.block_type != gfs2_meta_eattr) {
-		log_err("Extended attributes block invalid...removing\n");
+		log_err("Extended attributes block for inode #%"PRIu64
+			" (0x%" PRIx64 ") invalid...removing\n",
+			ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 		ip->i_di.di_eattr = 0;
 		*update = (opts.no ? not_updated : updated);
 		return 1;
@@ -195,11 +209,13 @@ int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_ptr,
 			 struct gfs2_buffer_head *leaf_bh,
 			 struct gfs2_ea_header *ea_hdr,
 			 struct gfs2_ea_header *ea_hdr_prev,
-			 void *private)
+			 enum update_flags *want_updated, void *private)
 {
 	struct gfs2_block_query q;
 	struct gfs2_sbd *sbp = ip->i_sbd;
-	if(gfs2_block_check(bl, be64_to_cpu(*ea_ptr), &q)) {
+
+	*want_updated = not_updated;
+	if(gfs2_block_check(sbp, bl, be64_to_cpu(*ea_ptr), &q)) {
 		stack;
 		return -1;
 	}
@@ -220,18 +236,22 @@ int pass1c(struct gfs2_sbd *sbp)
 	uint64_t block_no = 0;
 	struct gfs2_buffer_head *bh;
 	struct gfs2_inode *ip = NULL;
-	int update = 0;
 	struct metawalk_fxns pass1c_fxns = { 0 };
 	int error = 0;
+	osi_list_t *tmp;
+	struct special_blocks *ea_block;
+	enum update_flags want_updated = not_updated;
 
 	pass1c_fxns.check_eattr_indir = &check_eattr_indir;
 	pass1c_fxns.check_eattr_leaf = &check_eattr_leaf;
 	pass1c_fxns.check_eattr_entry = &check_eattr_entry;
 	pass1c_fxns.check_eattr_extentry = &check_eattr_extentry;
-	pass1c_fxns.private = (void *) &update;
+	pass1c_fxns.private = NULL;
 
 	log_info("Looking for inodes containing ea blocks...\n");
-	while (!gfs2_find_next_block_type(bl, gfs2_eattr_block, &block_no)) {
+	osi_list_foreach(tmp, &sbp->eattr_blocks.list) {
+		ea_block = osi_list_entry(tmp, struct special_blocks, list);
+		block_no = ea_block->block;
 
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
 			return 0;
@@ -239,24 +259,25 @@ int pass1c(struct gfs2_sbd *sbp)
 		if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) { /* if a dinode */
 			log_info("EA in inode %"PRIu64" (0x%" PRIx64 ")\n",
 				 block_no, block_no);
-			gfs2_block_clear(bl, block_no, gfs2_eattr_block);
+			gfs2_block_clear(sbp, bl, block_no, gfs2_eattr_block);
 			ip = fsck_inode_get(sbp, bh);
 
 			log_debug("Found eattr at %"PRIu64" (0x%" PRIx64 ")\n",
 				  ip->i_di.di_eattr, ip->i_di.di_eattr);
 			/* FIXME: Handle walking the eattr here */
-			error = check_inode_eattr(ip, &pass1c_fxns);
+			error = check_inode_eattr(ip, &want_updated,
+						  &pass1c_fxns);
 			if(error < 0) {
 				stack;
 				brelse(bh, not_updated);
 				return -1;
 			}
 
-			fsck_inode_put(ip, update); /* dinode_out, brelse, free */
+			fsck_inode_put(ip, want_updated); /* dinode_out,
+							     brelse, free */
 		} else {
-			brelse(bh, update);
+			brelse(bh, want_updated);
 		}
-		block_no++;
 	}
 	return 0;
 }
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index c15b0a8..260c4af 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -87,14 +87,18 @@ int set_dotdot_dir(struct gfs2_sbd *sbp, uint64_t childblock,
 }
 
 static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
-			    uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+			    uint64_t parent, struct gfs2_buffer_head **bh,
+			     enum update_flags *want_updated, void *private)
 {
+	*want_updated = not_updated;
 	*bh = bread(ip->i_sbd, block);
 	return 0;
 }
 static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
-			    uint64_t parent, struct gfs2_buffer_head **bh, void *private)
+			    uint64_t parent, struct gfs2_buffer_head **bh,
+			    enum update_flags *want_updated, void *private)
 {
+	*want_updated = not_updated;
 	*bh = bread(ip->i_sbd, block);
 	return 0;
 }
@@ -154,7 +158,7 @@ static int check_file_type(uint8_t de_type, uint8_t block_type)
 int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 		 struct gfs2_dirent *prev_de,
 		 struct gfs2_buffer_head *bh, char *filename,
-		 int *update, uint16_t *count, void *priv)
+		 enum update_flags *update, uint16_t *count, void *priv)
 {
 	struct gfs2_sbd *sbp = ip->i_sbd;
 	struct gfs2_block_query q = {0};
@@ -167,6 +171,7 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 	struct gfs2_dirent dentry, *de;
 	uint32_t calculated_hash;
 
+	*update = not_updated;
 	memset(&dentry, 0, sizeof(struct gfs2_dirent));
 	gfs2_dirent_in(&dentry, (char *)dent);
 	de = &dentry;
@@ -185,7 +190,8 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			"\tName length = %u\n",
 			de->de_rec_len,
 			de->de_name_len);
-		gfs2_block_set(bl, ip->i_di.di_num.no_addr, gfs2_meta_inval);
+		gfs2_block_set(sbp, bl, ip->i_di.di_num.no_addr,
+			       gfs2_meta_inval);
 		return 1;
 		/* FIXME: should probably delete the entry here at the
 		 * very least - maybe look at attempting to fix it */
@@ -226,7 +232,7 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 				 "Clear directory entry tp out of range block? (y/n) ")) {
 			log_err("Clearing %s\n", tmp_name);
 			dirent2_del(ip, bh, prev_de, dent);
-			*update = 1;
+			*update = updated;
 			return 1;
 		} else {
 			log_err("Directory entry to out of range block remains\n");
@@ -235,7 +241,7 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			return 0;
 		}
 	}
-	if(gfs2_block_check(bl, de->de_inum.no_addr, &q)) {
+	if(gfs2_block_check(sbp, bl, de->de_inum.no_addr, &q)) {
 		stack;
 		return -1;
 	}
@@ -251,7 +257,7 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 		if(query(&opts, "Clear entry to inode containing bad blocks? (y/n)")) {
 
 			entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-			check_inode_eattr(entry_ip, &clear_eattrs);
+			check_inode_eattr(entry_ip, update, &clear_eattrs);
 			fsck_inode_put(entry_ip, not_updated);
 
 			/* FIXME: make sure all blocks referenced by
@@ -259,8 +265,9 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 
 			dirent2_del(ip, bh, prev_de, dent);
 
-			gfs2_block_set(bl, de->de_inum.no_addr, gfs2_meta_inval);
-			*update = 1;
+			gfs2_block_set(sbp, bl, de->de_inum.no_addr,
+				       gfs2_meta_inval);
+			*update = updated;
 			return 1;
 		} else {
 			log_warn("Entry to inode containing bad blocks remains\n");
@@ -286,7 +293,7 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			 * this inode are cleared in the bitmap */
 
 			dirent2_del(ip, bh, prev_de, dent);
-			*update = 1;
+			*update = updated;
 			log_warn("Directory entry '%s' cleared\n", tmp_name);
 			return 1;
 		} else {
@@ -310,11 +317,11 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 				 block_type_string(&q));
 		if(query(&opts, "Clear stale directory entry? (y/n) ")) {
 			entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-			check_inode_eattr(entry_ip, &clear_eattrs);
+			check_inode_eattr(entry_ip, update, &clear_eattrs);
 			fsck_inode_put(entry_ip, not_updated);
 
 			dirent2_del(ip, bh, prev_de, dent);
-			*update  = 1;
+			*update = updated;
 			return 1;
 		} else {
 			log_err("Stale directory entry remains\n");
@@ -334,11 +341,12 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			if(query(&opts, "Clear duplicate '.' entry? (y/n) ")) {
 
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-				check_inode_eattr(entry_ip, &clear_eattrs);
+				check_inode_eattr(entry_ip, update,
+						  &clear_eattrs);
 				fsck_inode_put(entry_ip, not_updated);
 
 				dirent2_del(ip, bh, prev_de, dent);
-				*update  = 1;
+				*update = updated;
 				return 1;
 			} else {
 				log_err("Duplicate '.' entry remains\n");
@@ -365,11 +373,12 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 					ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 			if(query(&opts, "Remove '.' reference? (y/n) ")) {
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-				check_inode_eattr(entry_ip, &clear_eattrs);
+				check_inode_eattr(entry_ip, update,
+						  &clear_eattrs);
 				fsck_inode_put(entry_ip, not_updated);
 
 				dirent2_del(ip, bh, prev_de, dent);
-				*update = 1;
+				*update = updated;
 				return 1;
 
 			} else {
@@ -385,7 +394,6 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 
 		ds->dotdir = 1;
 		increment_link(sbp, de->de_inum.no_addr);
-		*update = (opts.no ? not_updated : updated);
 		(*count)++;
 		ds->entry_count++;
 
@@ -400,7 +408,8 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			if(query(&opts, "Clear duplicate '..' entry? (y/n) ")) {
 
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-				check_inode_eattr(entry_ip, &clear_eattrs);
+				check_inode_eattr(entry_ip, update,
+						  &clear_eattrs);
 				fsck_inode_put(entry_ip, not_updated);
 
 				dirent2_del(ip, bh, prev_de, dent);
@@ -425,7 +434,8 @@ int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 					ip->i_di.di_num.no_addr, ip->i_di.di_num.no_addr);
 			if(query(&opts, "Clear bad '..' directory entry? (y/n) ")) {
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
-				check_inode_eattr(entry_ip, &clear_eattrs);
+				check_inode_eattr(entry_ip, update,
+						  &clear_eattrs);
 				fsck_inode_put(entry_ip, not_updated);
 
 				dirent2_del(ip, bh, prev_de, dent);
@@ -524,13 +534,14 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 	char *filename;
 	int filename_len;
 	char tmp_name[256];
-	int update=0, error = 0;
+	enum update_flags update = not_updated;
+	int error = 0;
 
 	log_info("Checking system directory inode '%s'\n", dirname);
 
 	if (sysinode) {
 		iblock = sysinode->i_di.di_num.no_addr;
-		if(gfs2_block_check(bl, iblock, &ds.q)) {
+		if(gfs2_block_check(sysinode->i_sbd, bl, iblock, &ds.q)) {
 			iblock = sysinode->i_di.di_num.no_addr;
 		}
 	}
@@ -548,10 +559,10 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 		return -1;
 	}
 	if (error > 0)
-		gfs2_block_set(bl, iblock, gfs2_meta_inval);
+		gfs2_block_set(sysinode->i_sbd, bl, iblock, gfs2_meta_inval);
 
 	bh = bhold(sysinode->i_bh);
-	if(check_inode_eattr(sysinode, &pass2_fxns)) {
+	if(check_inode_eattr(sysinode, &update, &pass2_fxns)) {
 		stack;
 		return -1;
 	}
@@ -668,7 +679,7 @@ int pass2(struct gfs2_sbd *sbp)
 		if (is_system_dir(sbp, i))
 			continue;
 
-		if(gfs2_block_check(bl, i, &q)) {
+		if(gfs2_block_check(sbp, bl, i, &q)) {
 			log_err("Can't get block %"PRIu64 " (0x%" PRIx64
 					") from block list\n", i, i);
 			return -1;
@@ -727,7 +738,7 @@ int pass2(struct gfs2_sbd *sbp)
 				} else
 					log_err("Directory entry to invalid inode remains.\n");
 			}
-			gfs2_block_set(bl, i, gfs2_meta_inval);
+			gfs2_block_set(sbp, bl, i, gfs2_meta_inval);
 		}
 		bh = bread(sbp, i);
 		ip = fsck_inode_get(sbp, bh);
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 58e0009..719d0b1 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -85,13 +85,14 @@ struct dir_info *mark_and_return_parent(struct gfs2_sbd *sbp,
 				   PRIu64" (0x%" PRIx64 ")\n", di->dotdot_parent,
 				   di->dotdot_parent, di->treewalk_parent,
 				   di->treewalk_parent);
-		if(gfs2_block_check(bl, di->dotdot_parent, &q_dotdot)) {
+		if(gfs2_block_check(sbp, bl, di->dotdot_parent, &q_dotdot)) {
 			log_err("Unable to find block %"PRIu64
 					" (0x%" PRIx64 ") in block map.\n",
 					di->dotdot_parent, di->dotdot_parent);
 			return NULL;
 		}
-		if(gfs2_block_check(bl, di->treewalk_parent, &q_treewalk)) {
+		if(gfs2_block_check(sbp, bl, di->treewalk_parent,
+				    &q_treewalk)) {
 			log_err("Unable to find block %"PRIu64
 					" (0x%" PRIx64 ") in block map\n",
 					di->treewalk_parent, di->treewalk_parent);
@@ -160,7 +161,7 @@ struct dir_info *mark_and_return_parent(struct gfs2_sbd *sbp,
 		}
 	}
 	else {
-		if(gfs2_block_check(bl, di->dotdot_parent, &q_dotdot)) {
+		if(gfs2_block_check(sbp, bl, di->dotdot_parent, &q_dotdot)) {
 			log_err("Unable to find parent block %"PRIu64
 					" (0x%" PRIx64 ")  in block map\n",
 					di->dotdot_parent, di->dotdot_parent);
@@ -220,7 +221,7 @@ int pass3(struct gfs2_sbd *sbp)
 
 			/* FIXME: Factor this ? */
 			if(!tdi) {
-				if(gfs2_block_check(bl, di->dinode, &q)) {
+				if(gfs2_block_check(sbp, bl, di->dinode, &q)) {
 					stack;
 					return -1;
 				}
@@ -228,7 +229,9 @@ int pass3(struct gfs2_sbd *sbp)
 					log_err("Found unlinked directory containing bad block\n");
 					if(query(&opts,
 					   "Clear unlinked directory with bad blocks? (y/n) ")) {
-						gfs2_block_set(bl, di->dinode, gfs2_block_free);
+						gfs2_block_set(sbp, bl,
+							       di->dinode,
+							       gfs2_block_free);
 						break;
 					} else
 						log_err("Unlinked directory with bad block remains\n");
@@ -241,7 +244,8 @@ int pass3(struct gfs2_sbd *sbp)
 				   q.block_type != gfs2_inode_fifo &&
 				   q.block_type != gfs2_inode_sock) {
 					log_err("Unlinked block marked as inode not an inode\n");
-					gfs2_block_set(bl, di->dinode, gfs2_block_free);
+					gfs2_block_set(sbp, bl, di->dinode,
+						       gfs2_block_free);
 					log_err("Cleared\n");
 					break;
 				}
@@ -254,7 +258,9 @@ int pass3(struct gfs2_sbd *sbp)
 				if(!ip->i_di.di_size && !ip->i_di.di_eattr){
 					log_err("Unlinked directory has zero size.\n");
 					if(query(&opts, "Remove zero-size unlinked directory? (y/n) ")) {
-						gfs2_block_set(bl, di->dinode, gfs2_block_free);
+						gfs2_block_set(sbp, bl,
+							       di->dinode,
+							       gfs2_block_free);
 						fsck_inode_put(ip, not_updated);
 						break;
 					} else {
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 8a9e733..583a266 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -60,7 +60,7 @@ int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 		if(ii->counted_links == 0) {
 			log_err("Found unlinked inode at %" PRIu64 " (0x%" PRIx64 ")\n",
 					ii->inode, ii->inode);
-			if(gfs2_block_check(bl, ii->inode, &q)) {
+			if(gfs2_block_check(sbp, bl, ii->inode, &q)) {
 				stack;
 				return -1;
 			}
@@ -68,7 +68,8 @@ int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				log_err("Unlinked inode contains bad blocks\n", ii->inode);
 				if(query(&opts,
 						 "Clear unlinked inode with bad blocks? (y/n) ")) {
-					gfs2_block_set(bl, ii->inode, gfs2_block_free);
+					gfs2_block_set(sbp, bl, ii->inode,
+						       gfs2_block_free);
 					continue;
 				} else
 					log_err("Unlinked inode with bad blocks not cleared\n");
@@ -81,7 +82,8 @@ int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 			   q.block_type != gfs2_inode_fifo &&
 			   q.block_type != gfs2_inode_sock) {
 				log_err("Unlinked block marked as inode not an inode\n");
-				gfs2_block_set(bl, ii->inode, gfs2_block_free);
+				gfs2_block_set(sbp, bl, ii->inode,
+					       gfs2_block_free);
 				log_err("Cleared\n");
 				continue;
 			}
@@ -93,7 +95,8 @@ int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 			if(!ip->i_di.di_size && !ip->i_di.di_eattr){
 				log_err("Unlinked inode has zero size\n");
 				if(query(&opts, "Clear zero-size unlinked inode? (y/n) ")) {
-					gfs2_block_set(bl, ii->inode, gfs2_block_free);
+					gfs2_block_set(sbp, bl, ii->inode,
+						       gfs2_block_free);
 					fsck_inode_put(ip, not_updated);
 					continue;
 				}
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 8db2ca7..bc4b859 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -84,7 +84,7 @@ int check_block_status(struct gfs2_sbd *sbp, char *buffer, unsigned int buflen,
 		warm_fuzzy_stuff(block);
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
 			return 0;
-		gfs2_block_check(bl, block, &q);
+		gfs2_block_check(sbp, bl, block, &q);
 
 		block_status = convert_mark(&q, count);
 
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index 8ba16bf..355bc1f 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -24,6 +24,7 @@
 #include "fsck.h"
 
 int rindex_modified = FALSE;
+struct special_blocks false_rgrps;
 
 #define ri_equal(ondisk, expected, field) (ondisk.field == expected.field)
 
@@ -37,6 +38,53 @@ int rindex_modified = FALSE;
 	}
 
 /*
+ * find_journal_entry_rgs - find all RG blocks within all journals
+ *
+ * Since Resource Groups (RGs) are journaled, it is not uncommon for them
+ * to appear inside a journal.  But if there is severe damage to the rindex
+ * file or some of the RGs, we may need to hunt and peck for RGs and in that
+ * case, we don't want to mistake these blocks that look just a real RG
+ * for a real RG block.  These are "fake" RGs that need to be ignored for
+ * the purposes of finding where things are.
+ */
+void find_journaled_rgs(struct gfs2_sbd *sdp)
+{
+	int j, new = 0;
+	unsigned int jblocks;
+	uint64_t b, dblock;
+	uint32_t extlen;
+	struct gfs2_inode *ip;
+	struct gfs2_buffer_head *bh;
+
+	osi_list_init(&false_rgrps.list);
+	for (j = 0; j < sdp->md.journals; j++) {
+		log_debug("Checking for RGs in journal%d.\n", j);
+		ip = sdp->md.journal[j];
+		jblocks = ip->i_di.di_size / sdp->sd_sb.sb_bsize;
+		for (b = 0; b < jblocks; b++) {
+			block_map(ip, b, &new, &dblock, &extlen, 0,
+				  not_updated);
+			if (!dblock)
+				break;
+			bh = bread(sdp, dblock);
+			if (!gfs2_check_meta(bh, GFS2_METATYPE_RG)) {
+				log_debug("False RG found at block "
+					  "0x%" PRIx64 "\n", dblock);
+				gfs2_special_set(&false_rgrps, dblock);
+			}
+			brelse(bh, not_updated);
+		}
+	}
+}
+
+int is_false_rg(uint64_t block)
+{
+	if (blockfind(&false_rgrps, block))
+		return 1;
+	return 0;
+}
+
+/*
  * gfs2_rindex_rebuild - rebuild a corrupt Resource Group (RG) index manually
  *                        where trust_lvl == distrust
  *
@@ -75,6 +123,9 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 	int rg_was_fnd = FALSE, corrupt_rgs = 0, bitmap_was_fnd;
 	osi_list_t *tmp;
 
+	/* Figure out if there are any RG-looking blocks in the journal we
+	   need to ignore. */
+	find_journaled_rgs(sdp);
 	osi_list_init(ret_list);
 	number_of_rgs = 0;
 	initial_first_rg_dist = first_rg_dist = sdp->sb_addr + 1;
@@ -90,8 +141,9 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 	     blk < sdp->device.length && number_of_rgs < 6;
 	     blk++) {
 		bh = bread(sdp, blk);
-		if ((blk == sdp->sb_addr + 1) ||
-		    (!gfs2_check_meta(bh, GFS2_METATYPE_RG))) {
+		if (((blk == sdp->sb_addr + 1) ||
+		    (!gfs2_check_meta(bh, GFS2_METATYPE_RG))) &&
+		    !is_false_rg(blk)) {
 			log_debug("RG found at block 0x%" PRIx64 "\n", blk);
 			if (blk > sdp->sb_addr + 1) {
 				uint64_t rgdist;
@@ -124,6 +176,8 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 		brelse(bh, not_updated);
 	}
 	number_of_rgs = 0;
+	gfs2_special_free(&false_rgrps);
+
 	/* -------------------------------------------------------------- */
 	/* Sanity-check our first_rg_dist. If RG #2 got nuked, the        */
 	/* first_rg_dist would measure from #1 to #3, which would be bad. */
diff --git a/gfs2/libgfs2/bitmap.c b/gfs2/libgfs2/bitmap.c
index c8ba4ec..d198fe2 100644
--- a/gfs2/libgfs2/bitmap.c
+++ b/gfs2/libgfs2/bitmap.c
@@ -21,11 +21,39 @@
 #include "libgfs2.h"
 
 #define BITMAP_SIZE(size, cpb) (size / cpb)
+#define BITMAP_SIZE1(size) (size >> 3)
+#define BITMAP_SIZE4(size) (size >> 1)
 
 #define BITMAP_BYTE_OFFSET(x, map) ((x % map->chunks_per_byte) \
                                     * map->chunksize )
 
+/* BITMAP_BYTE_OFFSET1 is for chunksize==1, which implies chunks_per_byte==8 */
+/* Reducing the math, we get:                                                */
+/* #define BITMAP_BYTE_OFFSET1(x) ((x % 8) * 1)                              */
+/* #define BITMAP_BYTE_OFFSET1(x) (x % 8)                                    */
+/* #define BITMAP_BYTE_OFFSET1(x) (x & 0x0000000000000007)                   */
+#define BITMAP_BYTE_OFFSET1(x) (x & 0x0000000000000007)
+
+/* BITMAP_BYTE_OFFSET4 is for chunksize==4, which implies chunks_per_byte==2 */
+/* Reducing the math, we get:                                                */
+/* #define BITMAP_BYTE_OFFSET4(x) ((x % 2) * 4)                              */
+/* #define BITMAP_BYTE_OFFSET4(x) ((x & 0x0000000000000001) * 4)             */
+/* #define BITMAP_BYTE_OFFSET4(x) ((x & 0x0000000000000001) << 2)            */
+#define BITMAP_BYTE_OFFSET4(x) ((x & 0x0000000000000001) << 2)
+
 #define BITMAP_MASK(chunksize) ((2 << (chunksize - 1)) - 1)
+/* BITMAP_MASK1 is  for chunksize==1                                         */
+/* Reducing the math, we get:                                                */
+/* #define BITMAP_MASK1(chunksize) ((2 << (1 - 1)) - 1)                      */
+/* #define BITMAP_MASK1(chunksize) ((2 << 0) - 1)                            */
+/* #define BITMAP_MASK1(chunksize) ((2) - 1)                                 */
+#define BITMAP_MASK1(chunksize) (1)
+
+/* BITMAP_MASK4 is  for chunksize==4                                         */
+/* #define BITMAP_MASK(chunksize) ((2 << (4 - 1)) - 1)                       */
+/* #define BITMAP_MASK(chunksize) ((2 << 3) - 1)                             */
+/* #define BITMAP_MASK(chunksize) (0x10 - 1)                                 */
+#define BITMAP_MASK4(chunksize) (0xf)
 
 uint64_t gfs2_bitmap_size(struct gfs2_bmap *bmap) {
 	return bmap->size;
@@ -59,14 +87,19 @@ int gfs2_bitmap_create(struct gfs2_bmap *bmap, uint64_t size,
 
 int gfs2_bitmap_set(struct gfs2_bmap *bmap, uint64_t offset, uint8_t val)
 {
-	char *byte = NULL;
-	uint64_t b = offset;
+	static char *byte;
+	static uint64_t b;
 
 	if(offset < bmap->size) {
-		byte = bmap->map + BITMAP_SIZE(offset, bmap->chunks_per_byte);
-		b = BITMAP_BYTE_OFFSET(offset, bmap);
-
-		*byte |= (val & BITMAP_MASK(bmap->chunksize)) << b;
+		if (bmap->chunksize == 1) {
+			byte = bmap->map + BITMAP_SIZE1(offset);
+			b = BITMAP_BYTE_OFFSET1(offset);
+			*byte |= (val & BITMAP_MASK1(bmap->chunksize));
+		} else {
+			byte = bmap->map + BITMAP_SIZE4(offset);
+			b = BITMAP_BYTE_OFFSET4(offset);
+			*byte |= (val & BITMAP_MASK4(bmap->chunksize)) << b;
+		}
 		return 0;
 	}
 	return -1;
@@ -74,14 +107,19 @@ int gfs2_bitmap_set(struct gfs2_bmap *bmap, uint64_t offset, uint8_t val)
 
 int gfs2_bitmap_get(struct gfs2_bmap *bmap, uint64_t bit, uint8_t *val)
 {
-	char *byte = NULL;
-	uint64_t b = bit;
+	static char *byte;
+	static uint64_t b;
 
 	if(bit < bmap->size) {
-		byte = bmap->map + BITMAP_SIZE(bit, bmap->chunks_per_byte);
-		b = BITMAP_BYTE_OFFSET(bit, bmap);
-
-		*val = (*byte & (BITMAP_MASK(bmap->chunksize) << b )) >> b;
+		if (bmap->chunksize == 1) {
+			byte = bmap->map + BITMAP_SIZE1(bit);
+			b = BITMAP_BYTE_OFFSET1(bit);
+			*val = (*byte & (BITMAP_MASK1(bmap->chunksize) << b )) >> b;
+		} else {
+			byte = bmap->map + BITMAP_SIZE4(bit);
+			b = BITMAP_BYTE_OFFSET4(bit);
+			*val = (*byte & (BITMAP_MASK4(bmap->chunksize) << b )) >> b;
+		}
 		return 0;
 	}
 	return -1;
@@ -89,14 +127,19 @@ int gfs2_bitmap_get(struct gfs2_bmap *bmap, uint64_t bit, uint8_t *val)
 
 int gfs2_bitmap_clear(struct gfs2_bmap *bmap, uint64_t offset)
 {
-	char *byte = NULL;
-	uint64_t b = offset;
+	static char *byte;
+	static uint64_t b;
 
 	if(offset < bmap->size) {
-		byte = bmap->map + BITMAP_SIZE(offset, bmap->chunks_per_byte);
-		b = BITMAP_BYTE_OFFSET(offset, bmap);
-
-		*byte &= ~(BITMAP_MASK(bmap->chunksize) << b);
+		if (bmap->chunksize == 1) {
+			byte = bmap->map + BITMAP_SIZE1(offset);
+			b = BITMAP_BYTE_OFFSET1(offset);
+			*byte &= ~(BITMAP_MASK1(bmap->chunksize) << b);
+		} else {
+			byte = bmap->map + BITMAP_SIZE4(offset);
+			b = BITMAP_BYTE_OFFSET4(offset);
+			*byte &= ~(BITMAP_MASK4(bmap->chunksize) << b);
+		}
 		return 0;
 	}
 	return -1;
diff --git a/gfs2/libgfs2/block_list.c b/gfs2/libgfs2/block_list.c
index 0c7ddd9..054a5e4 100644
--- a/gfs2/libgfs2/block_list.c
+++ b/gfs2/libgfs2/block_list.c
@@ -20,23 +20,6 @@
 
 #include "libgfs2.h"
 
-#define FREE	        (0x0)  /*   0000 */
-#define BLOCK_IN_USE    (0x1)  /*   0001 */
-#define DIR_INDIR_BLK   (0x2)  /*   0010 */
-#define DIR_INODE       (0x3)  /*   0011 */
-#define FILE_INODE      (0x4)  /*   0100 */
-#define LNK_INODE       (0x5)
-#define BLK_INODE       (0x6)
-#define CHR_INODE       (0x7)
-#define FIFO_INODE      (0x8)
-#define SOCK_INODE      (0x9)
-#define DIR_LEAF_INODE  (0xA)  /*   1010 */
-#define JOURNAL_BLK     (0xB)  /*   1011 */
-#define OTHER_META      (0xC)  /*   1100 */
-#define EATTR_META      (0xD)  /*   1101 */
-#define UNUSED1	        (0xE)  /*   1110 */
-#define INVALID_META    (0xF)  /*   1111 */
-
 /* Must be kept in sync with mark_block enum in block_list.h */
 /* FIXME: Fragile */
 static int mark_to_gbmap[16] = {
@@ -46,93 +29,110 @@ static int mark_to_gbmap[16] = {
 	INVALID_META, INVALID_META
 };
 
-struct gfs2_block_list *gfs2_block_list_create(uint64_t size,
-											   uint64_t *addl_mem_needed)
+struct gfs2_block_list *gfs2_block_list_create(struct gfs2_sbd *sdp,
+					       uint64_t size,
+					       uint64_t *addl_mem_needed)
 {
 	struct gfs2_block_list *il;
 
 	*addl_mem_needed = 0L;
-	if ((il = malloc(sizeof(*il)))) {
-		if(!memset(il, 0, sizeof(*il)))
-			return NULL;
-
-		if(gfs2_bitmap_create(&il->list.gbmap.group_map, size, 4)) {
-			/* Note on addl_mem_needed: We've tried to allocate ram   */
-			/* for our bitmaps, but we failed.  The fs is too big.    */
-			/* We should tell them how much to allocate.  This first  */
-			/* bitmap is the biggest, but we need three more smaller  */
-			/* for the code that immediately follows.  I'm rounding   */
-			/* up to twice the memory for this bitmap, even though    */
-			/* it's actually 1 + 3/4.  That will allow for future     */
-			/* mallocs that happen after this point in the code.      */
-			/* For the bad_map, we have two more to go (total of 3)   */
-			/* but again I'm rounding it up to 4 smaller ones.        */
-			/* For the dup_map, I'm rounding from 2 to 3, and for     */
-			/* eattr_map, I'm rounding up from 1 to 2.                */
-			*addl_mem_needed = il->list.gbmap.group_map.mapsize * 2;
-			free(il);
-			il = NULL;
-		}
-		else if(gfs2_bitmap_create(&il->list.gbmap.bad_map, size, 1)) {
-			*addl_mem_needed = il->list.gbmap.group_map.mapsize * 4;
-			free(il);
-			il = NULL;
-		}
-		else if(gfs2_bitmap_create(&il->list.gbmap.dup_map, size, 1)) {
-			*addl_mem_needed = il->list.gbmap.group_map.mapsize * 3;
-			free(il);
-			il = NULL;
-		}
-		else if(gfs2_bitmap_create(&il->list.gbmap.eattr_map, size, 1)) {
-			*addl_mem_needed = il->list.gbmap.group_map.mapsize * 2;
-			free(il);
-			il = NULL;
-		}
+	il = malloc(sizeof(*il));
+	if (!il || !memset(il, 0, sizeof(*il)))
+		return NULL;
+
+	if(gfs2_bitmap_create(&il->list.gbmap.group_map, size, 4)) {
+		*addl_mem_needed = il->list.gbmap.group_map.mapsize;
+		free(il);
+		il = NULL;
 	}
+	osi_list_init(&sdp->bad_blocks.list);
+	osi_list_init(&sdp->dup_blocks.list);
+	osi_list_init(&sdp->eattr_blocks.list);
 	return il;
 }
 
-int gfs2_block_mark(struct gfs2_block_list *il, uint64_t block,
-					enum gfs2_mark_block mark)
+void gfs2_special_free(struct special_blocks *blist)
+{
+	struct special_blocks *f;
+
+	while(!osi_list_empty(&blist->list)) {
+		f = osi_list_entry(blist->list.next, struct special_blocks,
+				   list);
+		osi_list_del(&f->list);
+		free(f);
+	}
+}
+
+struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num)
+{
+	osi_list_t *head = &blist->list;
+	osi_list_t *tmp;
+	struct special_blocks *b;
+
+	for (tmp = head->next; tmp != head; tmp = tmp->next) {
+		b = osi_list_entry(tmp, struct special_blocks, list);
+		if (b->block == num)
+			return b;
+	}
+	return NULL;
+}
+
+void gfs2_special_set(struct special_blocks *blocklist, uint64_t block)
+{
+	struct special_blocks *b;
+
+	if (blockfind(blocklist, block))
+		return;
+	b = malloc(sizeof(struct special_blocks));
+	if (b) {
+		b->block = block;
+		osi_list_add(&b->list, &blocklist->list);
+	}
+	return;
+}
+
+void gfs2_special_clear(struct special_blocks *blocklist, uint64_t block)
+{
+	struct special_blocks *b;
+
+	b = blockfind(blocklist, block);
+	if (b) {
+		osi_list_del(&b->list);
+		free(b);
+	}
+}
+
+int gfs2_block_mark(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		    uint64_t block, enum gfs2_mark_block mark)
 {
 	int err = 0;
 
 	if(mark == gfs2_bad_block)
-		err = gfs2_bitmap_set(&il->list.gbmap.bad_map, block, 1);
+		gfs2_special_set(&sdp->bad_blocks, block);
 	else if(mark == gfs2_dup_block)
-		err = gfs2_bitmap_set(&il->list.gbmap.dup_map, block, 1);
+		gfs2_special_set(&sdp->dup_blocks, block);
 	else if(mark == gfs2_eattr_block)
-		err = gfs2_bitmap_set(&il->list.gbmap.eattr_map, block, 1);
+		gfs2_special_set(&sdp->eattr_blocks, block);
 	else
 		err = gfs2_bitmap_set(&il->list.gbmap.group_map, block,
-							  mark_to_gbmap[mark]);
+				      mark_to_gbmap[mark]);
 	return err;
 }
 
-int gfs2_block_set(struct gfs2_block_list *il, uint64_t block,
-				   enum gfs2_mark_block mark)
-{
-	int err = 0;
-	err = gfs2_block_clear(il, block, mark);
-	if(!err)
-		err = gfs2_block_mark(il, block, mark);
-	return err;
-}
-
-int gfs2_block_clear(struct gfs2_block_list *il, uint64_t block,
-					 enum gfs2_mark_block m)
+int gfs2_block_clear(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		     uint64_t block, enum gfs2_mark_block m)
 {
 	int err = 0;
 
 	switch (m) {
 	case gfs2_dup_block:
-		err = gfs2_bitmap_clear(&il->list.gbmap.dup_map, block);
+		gfs2_special_clear(&sdp->dup_blocks, block);
 		break;
 	case gfs2_bad_block:
-		err = gfs2_bitmap_clear(&il->list.gbmap.bad_map, block);
+		gfs2_special_clear(&sdp->bad_blocks, block);
 		break;
 	case gfs2_eattr_block:
-		err = gfs2_bitmap_clear(&il->list.gbmap.eattr_map, block);
+		gfs2_special_clear(&sdp->eattr_blocks, block);
 		break;
 	default:
 		/* FIXME: check types */
@@ -142,72 +142,46 @@ int gfs2_block_clear(struct gfs2_block_list *il, uint64_t block,
 	return err;
 }
 
-int gfs2_block_check(struct gfs2_block_list *il, uint64_t block,
-					 struct gfs2_block_query *val)
+int gfs2_block_set(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		   uint64_t block, enum gfs2_mark_block mark)
+{
+	int err;
+
+	err = gfs2_block_clear(sdp, il, block, mark);
+	if(!err)
+		err = gfs2_block_mark(sdp, il, block, mark);
+	return err;
+}
+
+int gfs2_block_check(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		     uint64_t block, struct gfs2_block_query *val)
 {
 	int err = 0;
+
 	val->bad_block = 0;
 	val->dup_block = 0;
+	val->eattr_block = 0;
 	if((err = gfs2_bitmap_get(&il->list.gbmap.group_map, block,
-							  &val->block_type)))
-		return err;
-	if((err = gfs2_bitmap_get(&il->list.gbmap.bad_map, block,
-							  &val->bad_block)))
+				  &val->block_type)))
 		return err;
-	if((err = gfs2_bitmap_get(&il->list.gbmap.dup_map, block,
-							  &val->dup_block)))
-		return err;
-	if((err = gfs2_bitmap_get(&il->list.gbmap.eattr_map, block,
-							  &val->eattr_block)))
-		return err;
-	return err;
+	if (blockfind(&sdp->bad_blocks, block))
+		val->bad_block = 1;
+	if (blockfind(&sdp->dup_blocks, block))
+		val->dup_block = 1;
+	if (blockfind(&sdp->eattr_blocks, block))
+		val->eattr_block = 1;
+	return 0;
 }
 
-void *gfs2_block_list_destroy(struct gfs2_block_list *il)
+void *gfs2_block_list_destroy(struct gfs2_sbd *sdp, struct gfs2_block_list *il)
 {
 	if(il) {
 		gfs2_bitmap_destroy(&il->list.gbmap.group_map);
-		gfs2_bitmap_destroy(&il->list.gbmap.bad_map);
-		gfs2_bitmap_destroy(&il->list.gbmap.dup_map);
-		gfs2_bitmap_destroy(&il->list.gbmap.eattr_map);
 		free(il);
 		il = NULL;
 	}
+	gfs2_special_free(&sdp->bad_blocks);
+	gfs2_special_free(&sdp->dup_blocks);
+	gfs2_special_free(&sdp->eattr_blocks);
 	return il;
 }
-
-
-int gfs2_find_next_block_type(struct gfs2_block_list *il,
-							  enum gfs2_mark_block m, uint64_t *b)
-{
-	uint64_t i;
-	uint8_t val;
-	int found = 0;
-	for(i = *b; ; i++) {
-		if(i >= gfs2_bitmap_size(&il->list.gbmap.dup_map))
-			return -1;
-
-		switch(m) {
-		case gfs2_dup_block:
-			if(gfs2_bitmap_get(&il->list.gbmap.dup_map, i, &val))
-				return -1;
-			if(val)
-				found = 1;
-			break;
-		case gfs2_eattr_block:
-			if(gfs2_bitmap_get(&il->list.gbmap.eattr_map, i, &val))
-				return -1;
-			if(val)
-				found = 1;
-			break;
-		default:
-			/* FIXME: add support for getting other types */
-			break;
-		}
-		if(found) {
-			*b = i;
-			return 0;
-		}
-	}
-	return -1;
-}
diff --git a/gfs2/libgfs2/buf.c b/gfs2/libgfs2/buf.c
index 562e965..7985945 100644
--- a/gfs2/libgfs2/buf.c
+++ b/gfs2/libgfs2/buf.c
@@ -103,7 +103,6 @@ struct gfs2_buffer_head *bget_generic(struct gfs2_sbd *sdp, uint64_t num,
 	bh->b_count = 1;
 	bh->b_blocknr = num;
 	bh->b_data = (char *)bh + sizeof(struct gfs2_buffer_head);
-	bh->b_size = sdp->bsize;
 	if (read_disk) {
 		do_lseek(sdp->device_fd, num * sdp->bsize);
 		do_read(sdp->device_fd, bh->b_data, sdp->bsize);
diff --git a/gfs2/libgfs2/fs_bits.c b/gfs2/libgfs2/fs_bits.c
index 6e74747..024426f 100644
--- a/gfs2/libgfs2/fs_bits.c
+++ b/gfs2/libgfs2/fs_bits.c
@@ -51,7 +51,7 @@ uint32_t gfs2_bitfit_core(struct gfs2_sbd *sbp, uint64_t goal, uint64_t start,
 	struct gfs2_block_query q;
 
 	for(block = start+goal; block < start+len; block++) {
-		gfs2_block_check(bl, block, &q);
+		gfs2_block_check(sbp, bl, block, &q);
 		switch(old_state) {
 			/* FIXME Make sure these are handled correctly */
 		case GFS2_BLKST_FREE:
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index a48d2ff..e5fc959 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -148,20 +148,20 @@ uint64_t dinode_alloc(struct gfs2_sbd *sdp)
 	return blk_alloc_i(sdp, DINODE);
 }
 
-static __inline__ void buffer_clear_tail(struct gfs2_buffer_head *bh, int head)
+static __inline__ void buffer_clear_tail(struct gfs2_sbd *sdp,
+					 struct gfs2_buffer_head *bh, int head)
 {
-	memset(bh->b_data + head, 0, bh->b_size - head);
+	memset(bh->b_data + head, 0, sdp->bsize - head);
 }
 
 static __inline__ void
-buffer_copy_tail(struct gfs2_buffer_head *to_bh, int to_head,
-				 struct gfs2_buffer_head *from_bh, int from_head)
+buffer_copy_tail(struct gfs2_sbd *sdp,
+		 struct gfs2_buffer_head *to_bh, int to_head,
+		 struct gfs2_buffer_head *from_bh, int from_head)
 {
-	memcpy(to_bh->b_data + to_head,
-	       from_bh->b_data + from_head,
-	       from_bh->b_size - from_head);
-	memset(to_bh->b_data + to_bh->b_size + to_head - from_head,
-	       0,
+	memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
+	       sdp->bsize - from_head);
+	memset(to_bh->b_data + sdp->bsize + to_head - from_head, 0,
 	       from_head - to_head);
 }
 
@@ -184,7 +184,8 @@ static void unstuff_dinode(struct gfs2_inode *ip)
 				gfs2_meta_header_out(&mh, bh->b_data);
 			}
 
-			buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
+			buffer_copy_tail(sdp, bh,
+					 sizeof(struct gfs2_meta_header),
 					 ip->i_bh, sizeof(struct gfs2_dinode));
 
 			brelse(bh, updated);
@@ -192,14 +193,14 @@ static void unstuff_dinode(struct gfs2_inode *ip)
 			block = data_alloc(ip);
 			bh = bget(sdp, block);
 
-			buffer_copy_tail(bh, 0,
+			buffer_copy_tail(sdp, bh, 0,
 					 ip->i_bh, sizeof(struct gfs2_dinode));
 
 			brelse(bh, updated);
 		}
 	}
 
-	buffer_clear_tail(ip->i_bh, sizeof(struct gfs2_dinode));
+	buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
 
 	if (ip->i_di.di_size) {
 		*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
@@ -260,13 +261,14 @@ void build_height(struct gfs2_inode *ip, int height)
 				mh.mh_format = GFS2_FORMAT_IN;
 				gfs2_meta_header_out(&mh, bh->b_data);
 			}
-			buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
+			buffer_copy_tail(sdp, bh,
+					 sizeof(struct gfs2_meta_header),
 					 ip->i_bh, sizeof(struct gfs2_dinode));
 
 			brelse(bh, updated);
 		}
 
-		buffer_clear_tail(ip->i_bh, sizeof(struct gfs2_dinode));
+		buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
 
 		if (new_block) {
 			*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
@@ -628,7 +630,7 @@ int gfs2_dirent_next(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 	char *bh_end;
 	uint16_t cur_rec_len;
 
-	bh_end = bh->b_data + bh->b_size;
+	bh_end = bh->b_data + dip->i_sbd->bsize;
 	cur_rec_len = be16_to_cpu((*dent)->de_rec_len);
 
 	if ((char *)(*dent) + cur_rec_len >= bh_end)
@@ -661,7 +663,7 @@ dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh, int name_len,
 	}
 
 	if (!entries) {
-		dent->de_rec_len = cpu_to_be16(bh->b_size - offset);
+		dent->de_rec_len = cpu_to_be16(dip->i_sbd->bsize - offset);
 		dent->de_name_len = cpu_to_be16(name_len);
 
 		*dent_out = dent;
@@ -1060,7 +1062,7 @@ dir_make_exhash(struct gfs2_inode *dip)
 	leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
 	leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
 
-	buffer_copy_tail(bh, sizeof(struct gfs2_leaf),
+	buffer_copy_tail(sdp, bh, sizeof(struct gfs2_leaf),
 			 dip->i_bh, sizeof(struct gfs2_dinode));
 
 	x = 0;
@@ -1078,7 +1080,7 @@ dir_make_exhash(struct gfs2_inode *dip)
 
 	brelse(bh, updated);
 
-	buffer_clear_tail(dip->i_bh, sizeof(struct gfs2_dinode));
+	buffer_clear_tail(sdp, dip->i_bh, sizeof(struct gfs2_dinode));
 
 	lp = (uint64_t *)(dip->i_bh->b_data + sizeof(struct gfs2_dinode));
 
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 7f8e393..fe0b77b 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -119,11 +119,15 @@ struct gfs2_buffer_head {
 	unsigned int b_count;
 	uint64_t b_blocknr;
 	char *b_data;
-	unsigned int b_size;
 
 	int b_changed;
 };
 
+struct special_blocks {
+	osi_list_t list;
+	uint64_t block;
+};
+
 struct gfs2_sbd;
 struct gfs2_inode {
 	struct gfs2_dinode i_di;
@@ -242,6 +246,9 @@ struct gfs2_sbd {
 	int metafs_fd;
 	int metafs_mounted; /* If metafs was already mounted */
 	char metafs_path[PATH_MAX]; /* where metafs is mounted */
+	struct special_blocks bad_blocks;
+	struct special_blocks dup_blocks;
+	struct special_blocks eattr_blocks;
 };
 
 extern char *prog_name;
@@ -290,26 +297,44 @@ void gfs2_bitmap_destroy(struct gfs2_bmap *bmap);
 uint64_t gfs2_bitmap_size(struct gfs2_bmap *bmap);
 
 /* block_list.c */
+#define FREE	        (0x0)  /*   0000 */
+#define BLOCK_IN_USE    (0x1)  /*   0001 */
+#define DIR_INDIR_BLK   (0x2)  /*   0010 */
+#define DIR_INODE       (0x3)  /*   0011 */
+#define FILE_INODE      (0x4)  /*   0100 */
+#define LNK_INODE       (0x5)
+#define BLK_INODE       (0x6)
+#define CHR_INODE       (0x7)
+#define FIFO_INODE      (0x8)
+#define SOCK_INODE      (0x9)
+#define DIR_LEAF_INODE  (0xA)  /*   1010 */
+#define JOURNAL_BLK     (0xB)  /*   1011 */
+#define OTHER_META      (0xC)  /*   1100 */
+#define EATTR_META      (0xD)  /*   1101 */
+#define UNUSED1         (0xE)  /*   1110 */
+#define INVALID_META    (0xF)  /*   1111 */
+
 /* Must be kept in sync with mark_to_bitmap array in block_list.c */
 enum gfs2_mark_block {
-        gfs2_block_free = 0,
-        gfs2_block_used,
-        gfs2_indir_blk,
-        gfs2_inode_dir,
-        gfs2_inode_file,
-        gfs2_inode_lnk,
-        gfs2_inode_blk,
-        gfs2_inode_chr,
-        gfs2_inode_fifo,
-        gfs2_inode_sock,
-        gfs2_leaf_blk,
-        gfs2_journal_blk,
-        gfs2_meta_other,
-        gfs2_meta_eattr,
-        gfs2_meta_inval = 15,
-        gfs2_bad_block,      /* Contains at least one bad block */
-        gfs2_dup_block,      /* Contains at least one duplicate block */
-        gfs2_eattr_block,    /* Contains an eattr */
+	gfs2_block_free = FREE,
+	gfs2_block_used = BLOCK_IN_USE,
+	gfs2_indir_blk = DIR_INDIR_BLK,
+	gfs2_inode_dir = DIR_INODE,
+	gfs2_inode_file = FILE_INODE,
+	gfs2_inode_lnk = LNK_INODE,
+	gfs2_inode_blk = BLK_INODE,
+	gfs2_inode_chr = CHR_INODE,
+	gfs2_inode_fifo = FIFO_INODE,
+	gfs2_inode_sock = SOCK_INODE,
+	gfs2_leaf_blk = DIR_LEAF_INODE,
+	gfs2_journal_blk = JOURNAL_BLK,
+	gfs2_meta_other = OTHER_META,
+	gfs2_meta_eattr = EATTR_META,
+	gfs2_meta_unused = UNUSED1,
+	gfs2_meta_inval = INVALID_META,
+	gfs2_bad_block,      /* Contains at least one bad block */
+	gfs2_dup_block,      /* Contains at least one duplicate block */
+	gfs2_eattr_block,    /* Contains an eattr */
 };
 
 struct gfs2_block_query {
@@ -335,21 +360,23 @@ struct gfs2_block_list {
         union gfs2_block_lists list;
 };
 
-struct gfs2_block_list *gfs2_block_list_create(uint64_t size,
+struct gfs2_block_list *gfs2_block_list_create(struct gfs2_sbd *sdp,
+					       uint64_t size,
 					       uint64_t *addl_mem_needed);
-int gfs2_block_mark(struct gfs2_block_list *il, uint64_t block,
-					enum gfs2_mark_block mark);
-int gfs2_block_set(struct gfs2_block_list *il, uint64_t block,
-				   enum gfs2_mark_block mark);
-int gfs2_block_clear(struct gfs2_block_list *il, uint64_t block,
-					 enum gfs2_mark_block m);
-int gfs2_block_check(struct gfs2_block_list *il, uint64_t block,
-					 struct gfs2_block_query *val);
-int gfs2_block_check_for_mark(struct gfs2_block_list *il, uint64_t block,
-			      enum gfs2_mark_block mark);
-void *gfs2_block_list_destroy(struct gfs2_block_list *il);
-int gfs2_find_next_block_type(struct gfs2_block_list *il,
-			      enum gfs2_mark_block m, uint64_t *b);
+struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num);
+void gfs2_special_set(struct special_blocks *blocklist, uint64_t block);
+void gfs2_special_clear(struct special_blocks *blocklist, uint64_t block);
+void gfs2_special_free(struct special_blocks *blist);
+int gfs2_block_mark(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		    uint64_t block, enum gfs2_mark_block mark);
+int gfs2_block_set(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		   uint64_t block, enum gfs2_mark_block mark);
+int gfs2_block_clear(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		     uint64_t block, enum gfs2_mark_block m);
+int gfs2_block_check(struct gfs2_sbd *sdp, struct gfs2_block_list *il,
+		     uint64_t block, struct gfs2_block_query *val);
+void *gfs2_block_list_destroy(struct gfs2_sbd *sdp,
+			      struct gfs2_block_list *il);
 
 /* buf.c */
 struct gfs2_buffer_head *bget_generic(struct gfs2_sbd *sdp, uint64_t num,
diff --git a/gfs2/libgfs2/recovery.c b/gfs2/libgfs2/recovery.c
index 387d4fa..c789078 100644
--- a/gfs2/libgfs2/recovery.c
+++ b/gfs2/libgfs2/recovery.c
@@ -233,7 +233,7 @@ int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head)
 		return -EIO;
 
 	bh = bread(ip->i_sbd, dblock);
-	memset(bh->b_data, 0, bh->b_size);
+	memset(bh->b_data, 0, ip->i_sbd->bsize);
 
 	lh = (struct gfs2_log_header *)bh->b_data;
 	memset(lh, 0, sizeof(struct gfs2_log_header));
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 5728144..461c80e 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -31,6 +31,14 @@ int gfs2_compute_bitstructs(struct gfs2_sbd *sdp, struct rgrp_list *rgd)
 	uint32_t bytes_left, bytes;
 	int x;
 
+	/* Max size of an rg is 2GB.  A 2GB RG with (minimum) 512-byte blocks
+	   has 4194304 blocks.  We can represent 4 blocks in one bitmap byte.
+	   Therefore, all 4194304 blocks can be represented in 1048576 bytes.
+	   Subtract a metadata header for each 512-byte block and we get
+	   488 bytes of bitmap per block.  Divide 1048576 by 488 and we can
+	   be assured we should never have more than 2149 of them. */
+	if (length > 2149 || length == 0)
+		return -1;
 	if(!(rgd->bits = (struct gfs2_bitmap *)
 		 malloc(length * sizeof(struct gfs2_bitmap))))
 		return -1;


hooks/post-receive
--
Cluster Project


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