Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9383e745e23602bc45f9c92184feea59 > files > 7

gfs2-utils-0.1.62-28.el5.src.rpm

commit 1a6be82a56458a55a6e6a489c0672b1bec444704
Author: Bob Peterson <bob@ganesha.peterson>
Date:   Tue Jan 19 13:51:13 2010 -0600

    Attach bh's to inodes
    
    This patch attaches buffer_heads to inodes.  This gives us better
    performance because we don't have to constantly keep searching for
    the buffer based on the dinode address.  It's also another step in
    eliminating the linked list of buffers altogether.
    
    rhbz#455300

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 5630b9c..22be04f 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -319,12 +319,13 @@ static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
 	amount = size;
 
 	while (copied < size) {
-		bh = bhold(ip->i_bh);
-
+		bh = ip->i_bh;
 		/* First, build up the metatree */
 		for (h = 0; h < blk->height; h++) {
-			lookup_block(ip, bh, h, &blk->mp, 1, &new, &block);
-			brelse(bh);
+			lookup_block(ip, ip->i_bh, h, &blk->mp, 1, &new,
+				     &block);
+			if (bh != ip->i_bh)
+				brelse(bh);
 			if (!block)
 				break;
 
@@ -343,7 +344,8 @@ static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
 		       (char *)srcptr, amount);
 		srcptr += amount;
 		bmodified(bh);
-		brelse(bh);
+		if (bh != ip->i_bh)
+			brelse(bh);
 
 		copied += amount;
 
@@ -413,8 +415,7 @@ static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
 /*                                                                           */
 /* Adapted from gfs2_fsck metawalk.c's build_and_check_metalist              */
 /* ------------------------------------------------------------------------- */
-static int adjust_indirect_blocks(struct gfs2_sbd *sbp, struct gfs2_buffer_head *dibh,
-			   struct gfs2_inode *ip)
+static int adjust_indirect_blocks(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
 {
 	uint32_t gfs2_hgt;
 	struct gfs2_buffer_head *bh;
@@ -425,6 +426,7 @@ static int adjust_indirect_blocks(struct gfs2_sbd *sbp, struct gfs2_buffer_head
 	int error = 0, di_height;
 	struct blocklist blocks, *blk, *newblk;
 	struct metapath gfs2mp;
+	struct gfs2_buffer_head *dibh = ip->i_bh;			   
 
 	/* if there are no indirect blocks to check */
 	if (ip->i_di.di_height <= 1)
@@ -693,8 +695,7 @@ void fix_jdatatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
 	}
 }
 
-int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *dibh,
-			   struct gfs2_inode *ip)
+int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
 {
 	uint32_t gfs2_hgt;
 	struct gfs2_buffer_head *bh;
@@ -705,6 +706,7 @@ int adjust_jdata_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *dibh,
 	int error = 0, di_height;
 	struct blocklist blocks, *blk, *newblk;
 	struct metapath gfs2mp;
+	struct gfs2_buffer_head *dibh = ip->i_bh;
 
 	/* Don't have to worry about things with stuffed inodes */
 	if (ip->i_di.di_height == 0)
@@ -941,14 +943,15 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 		inode->i_di.di_generation = 0;
 		if (!(inode->i_di.di_mode & S_IFDIR) && 
 		    inode->i_di.di_flags & GFS2_DIF_JDATA)
-			ret = adjust_jdata_inode(sbp, bh, inode);
+			ret = adjust_jdata_inode(sbp, inode);
 		else 
-			ret = adjust_indirect_blocks(sbp, bh, inode);
+			ret = adjust_indirect_blocks(sbp, inode);
 		if (ret)
 			return -1;
 	}
 	
-	gfs2_dinode_out(&inode->i_di, bh);
+	bmodified(inode->i_bh);
+	inode_put(&inode); /* does gfs2_dinode_out if modified */
 	sbp->md.next_inum++; /* update inode count */
 	return 0;
 } /* adjust_inode */
@@ -1051,15 +1054,12 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 static int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
 					   struct gfs2_inum *inum)
 {
-	struct gfs2_buffer_head *bh_fix;
 	struct gfs2_inode *fix_inode;
 
-	bh_fix = bread(&sbp->buf_list, iblock);
-	fix_inode = inode_get(sbp, bh_fix);
+	fix_inode = inode_read(sbp, iblock);
 	inum->no_formal_ino = fix_inode->i_di.di_num.no_formal_ino;
 	inum->no_addr = fix_inode->i_di.di_num.no_addr;
-	bmodified(bh_fix);
-	brelse(bh_fix);
+	inode_put(&fix_inode);
 	return 0;
 }/* fetch_inum */
 
@@ -1213,7 +1213,6 @@ static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
 	struct inode_block *dir_iblk;
 	uint64_t offset, dirblock;
 	struct gfs2_inode *dip;
-	struct gfs2_buffer_head *bh_dir;
 
 	dirs_fixed = 0;
 	dirents_fixed = 0;
@@ -1235,27 +1234,24 @@ static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
 		dir_iblk = (struct inode_block *)fix;
 		dirblock = dir_iblk->di_addr; /* addr of dir inode */
 		/* read in the directory inode */
-		bh_dir = bread(&sbp->buf_list, dirblock);
-		dip = inode_get(sbp, bh_dir);
+		dip = inode_read(sbp, dirblock);
 		/* fix the directory: either exhash (leaves) or linear (stuffed) */
 		if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
 			if (fix_one_directory_exhash(sbp, dip)) {
 				log_crit("Error fixing exhash directory.\n");
-				bmodified(bh_dir);
-				brelse(bh_dir);
+				inode_put(&dip);
 				return -1;
 			}
 		}
 		else {
-			if (process_dirent_info(dip, sbp, bh_dir, dip->i_di.di_entries)) {
+			if (process_dirent_info(dip, sbp, dip->i_bh,
+						dip->i_di.di_entries)) {
 				log_crit("Error fixing linear directory.\n");
-				bmodified(bh_dir);
-				brelse(bh_dir);
+				inode_put(&dip);
 				return -1;
 			}
 		}
-		bmodified(bh_dir);
-		brelse(bh_dir);
+		inode_put(&dip);
 	}
 	/* Free the last entry in memory: */
 	if (tmp) {
@@ -1416,11 +1412,10 @@ static int init(struct gfs2_sbd *sbp)
 	}
 	/* get gfs1 rindex inode - gfs1's rindex inode ptr became __pad2 */
 	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_rindex_di);
-	bh = bread(&sbp->buf_list, inum.no_addr);
-	sbp->md.riinode = gfs_inode_get(sbp, bh);
+	sbp->md.riinode = gfs_inode_read(sbp, inum.no_addr);
 	/* get gfs1 jindex inode - gfs1's journal index inode ptr became master */
 	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_jindex_di);
-	sbp->md.jiinode = gfs2_load_inode(sbp, inum.no_addr);
+	sbp->md.jiinode = inode_read(sbp, inum.no_addr);
 	/* read in the journal index data */
 	read_gfs1_jiindex(sbp);
 	/* read in the resource group index data: */
@@ -1439,8 +1434,8 @@ static int init(struct gfs2_sbd *sbp)
 	}
 	printf("\n");
 	fflush(stdout);
-	inode_put(sbp->md.riinode);
-	inode_put(sbp->md.jiinode);
+	inode_put(&sbp->md.riinode);
+	inode_put(&sbp->md.jiinode);
 	log_debug("%d rgs found.\n", rgcount);
 	return 0;
 }/* fill_super_block */
@@ -1739,11 +1734,10 @@ static void remove_obsolete_gfs1(struct gfs2_sbd *sbp)
 /* ------------------------------------------------------------------------- */
 static void conv_build_jindex(struct gfs2_sbd *sdp)
 {
-	struct gfs2_inode *jindex;
 	unsigned int j;
 
-	jindex = createi(sdp->master_dir, "jindex", S_IFDIR | 0700,
-			 GFS2_DIF_SYSTEM);
+	sdp->md.jiinode = createi(sdp->master_dir, "jindex", S_IFDIR | 0700,
+				  GFS2_DIF_SYSTEM);
 
 	for (j = 0; j < sdp->md.journals; j++) {
 		char name[256];
@@ -1752,20 +1746,21 @@ static void conv_build_jindex(struct gfs2_sbd *sdp)
 		printf("Writing journal #%d...", j + 1);
 		fflush(stdout);
 		sprintf(name, "journal%u", j);
-		ip = createi(jindex, name, S_IFREG | 0600, GFS2_DIF_SYSTEM);
+		ip = createi(sdp->md.jiinode, name, S_IFREG | 0600,
+			     GFS2_DIF_SYSTEM);
 		write_journal(sdp, ip, j,
 			      sdp->jsize << 20 >> sdp->sd_sb.sb_bsize_shift);
-		inode_put(ip);
+		inode_put(&ip);
 		printf("done.\n");
 		fflush(stdout);
 	}
 
 	if (sdp->debug) {
 		printf("\nJindex:\n");
-		gfs2_dinode_print(&jindex->i_di);
+		gfs2_dinode_print(&sdp->md.jiinode->i_di);
 	}
 
-	inode_put(jindex);
+	inode_put(&sdp->md.jiinode);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1869,9 +1864,9 @@ int main(int argc, char **argv)
 
 		write_statfs_file(&sb2);
 
-		inode_put(sb2.master_dir);
-		inode_put(sb2.md.inum);
-		inode_put(sb2.md.statfs);
+		inode_put(&sb2.master_dir);
+		inode_put(&sb2.md.inum);
+		inode_put(&sb2.md.statfs);
 
 		bcommit(&sb2.buf_list); /* write the buffers to disk */
 
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 1a9c7ae..b99580d 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -55,7 +55,6 @@ const char *allocdesc[2][5] = {
 const char *prog_name;
 
 int display(int identify_only);
-extern void savemeta(const char *out_fn, int slow);
 extern void restoremeta(const char *in_fn, const char *out_device,
 			uint64_t printblocksonly);
 
@@ -807,7 +806,7 @@ static void rgcount(void)
 {
 	printf("%lld RGs in this file system.\n",
 	       (unsigned long long)sbd.md.riinode->i_di.di_size / risize());
-	inode_put(sbd.md.riinode);
+	inode_put(&sbd.md.riinode);
 	gfs2_rgrp_free(&sbd.rglist);
 	exit(EXIT_SUCCESS);
 }
@@ -891,7 +890,6 @@ static void gfs_rgrp_print(struct gfs_rgrp *rg)
 /* ------------------------------------------------------------------------ */
 static uint64_t get_rg_addr(int rgnum)
 {
-	struct gfs2_buffer_head *lbh;
 	uint64_t rgblk = 0, gblock;
 	struct gfs2_inode *riinode;
 
@@ -899,14 +897,13 @@ static uint64_t get_rg_addr(int rgnum)
 		gblock = sbd1->sb_rindex_di.no_addr;
 	else
 		gblock = masterblock("rindex");
-	lbh = bread(&sbd.buf_list, gblock);
-	riinode = inode_get(&sbd, lbh);
+	riinode = inode_read(&sbd, gblock);
 	if (rgnum < riinode->i_di.di_size / risize())
 		rgblk = find_rgrp_block(riinode, rgnum);
 	else
 		fprintf(stderr, "Error: File system only has %lld RGs.\n",
 			(unsigned long long)riinode->i_di.di_size / risize());
-	inode_put(riinode);
+	inode_put(&riinode);
 	return rgblk;
 }
 
@@ -1617,17 +1614,15 @@ int block_is_per_node(void)
 int block_is_in_per_node(void)
 {
 	int d;
-	struct gfs2_dinode per_node_di;
-	struct gfs2_buffer_head *per_node_bh;
+	struct gfs2_inode *per_node_di;
 
 	if (gfs1)
 		return FALSE;
 
-	per_node_bh = bread(&sbd.buf_list, masterblock("per_node"));
-	gfs2_dinode_in(&per_node_di, per_node_bh);
+	per_node_di = inode_read(&sbd, masterblock("per_node"));
 
-	do_dinode_extended(&per_node_di, per_node_bh);
-	brelse(per_node_bh);
+	do_dinode_extended(&per_node_di->i_di, per_node_di->i_bh);
+	inode_put(&per_node_di);
 
 	for (d = 0; d < indirect->ii[0].dirents; d++) {
 		if (block == indirect->ii[0].dirent[d].block)
@@ -1758,8 +1753,7 @@ static void read_superblock(int fd)
 			sizeof(uint64_t);
 		sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs_dinode)) /
 			sizeof(uint64_t);
-		sbd.md.riinode = gfs2_load_inode(&sbd,
-						 sbd1->sb_rindex_di.no_addr);
+		sbd.md.riinode = inode_read(&sbd, sbd1->sb_rindex_di.no_addr);
 		sbd.fssize = sbd.device.length;
 		gfs1_rindex_read(&sbd, 0, &count);
 	} else {
@@ -1767,7 +1761,7 @@ static void read_superblock(int fd)
 			sizeof(uint64_t);
 		sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs2_dinode)) /
 			sizeof(uint64_t);
-		sbd.master_dir = gfs2_load_inode(&sbd,
+		sbd.master_dir = inode_read(&sbd,
 					    sbd.sd_sb.sb_master_dir.no_addr);
 		gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode);
 		sbd.fssize = sbd.device.length;
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index 6996ab5..d78779d 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -184,7 +184,7 @@ extern void gfs_log_header_in(struct gfs_log_header *head,
 			      struct gfs2_buffer_head *bh);
 extern void gfs_log_header_print(struct gfs_log_header *lh);
 extern void gfs_dinode_in(struct gfs_dinode *di, struct gfs2_buffer_head *bh);
-extern void savemeta(const char *out_fn, int saveoption);
+extern void savemeta(char *out_fn, int saveoption);
 extern void restoremeta(const char *in_fn, const char *out_device,
 			uint64_t printblocksonly);
 extern int display(int identify_only);
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 39888fa..1e533a6 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -398,7 +398,7 @@ static void save_inode_data(int out_fd)
 		}
 		brelse(lbh);
 	}
-	inode_put(inode);
+	inode_put(&inode);
 	brelse(metabh);
 }
 
@@ -420,19 +420,18 @@ static void get_journal_inode_blocks(void)
 	for (journal = 0; ; journal++) { /* while journals exist */
 		uint64_t jblock;
 		int amt;
-		struct gfs2_dinode jdi;
 		struct gfs2_inode *j_inode = NULL;
 
 		if (gfs1) {
 			struct gfs_jindex ji;
 			char jbuf[sizeof(struct gfs_jindex)];
 
-			bh = bread(&sbd.buf_list, sbd1->sb_jindex_di.no_addr);
-			j_inode = gfs_inode_get(&sbd, bh);
+			j_inode = gfs_inode_read(&sbd,
+						 sbd1->sb_jindex_di.no_addr);
 			amt = gfs2_readi(j_inode, (void *)&jbuf,
 					 journal * sizeof(struct gfs_jindex),
 					 sizeof(struct gfs_jindex));
-			brelse(bh);
+			inode_put(&j_inode);
 			if (!amt)
 				break;
 			gfs_jindex_in(&ji, jbuf);
@@ -442,10 +441,6 @@ static void get_journal_inode_blocks(void)
 			if (journal > indirect->ii[0].dirents - 3)
 				break;
 			jblock = indirect->ii[0].dirent[journal + 2].block;
-			bh = bread(&sbd.buf_list, jblock);
-			j_inode = inode_get(&sbd, bh);
-			gfs2_dinode_in(&jdi, bh);
-			inode_put(j_inode);
 		}
 		journal_blocks[journals_found++] = jblock;
 	}
@@ -490,7 +485,7 @@ static int next_rg_freemeta(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
 	return 0;
 }
 
-void savemeta(const char *out_fn, int saveoption)
+void savemeta(char *out_fn, int saveoption)
 {
 	int out_fd;
 	int slow;
@@ -558,14 +553,13 @@ void savemeta(const char *out_fn, int saveoption)
 	       last_fs_block, sbd.bsize);
 	if (!slow) {
 		if (gfs1) {
-			sbd.md.riinode =
-				gfs2_load_inode(&sbd,
+			sbd.md.riinode = inode_read(&sbd,
 						sbd1->sb_rindex_di.no_addr);
 			jindex_block = sbd1->sb_jindex_di.no_addr;
 		} else {
 			sbd.master_dir =
-				gfs2_load_inode(&sbd,
-						sbd.sd_sb.sb_master_dir.no_addr);
+				inode_read(&sbd,
+					sbd.sd_sb.sb_master_dir.no_addr);
 
 			slow = gfs2_lookupi(sbd.master_dir, "rindex", 6, 
 					    &sbd.md.riinode);
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 13a60ae..cbc5fe2 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -565,8 +565,7 @@ int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
 	*clean_journals = 0;
 
 	/* Get master dinode */
-	sdp->master_dir = gfs2_load_inode(sdp,
-					  sdp->sd_sb.sb_master_dir.no_addr);
+	sdp->master_dir = inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
 	gfs2_lookupi(sdp->master_dir, "jindex", 6, &sdp->md.jiinode);
 
 	/* read in the journal index data */
@@ -590,10 +589,10 @@ int replay_journals(struct gfs2_sbd *sdp, int preen, int force_check,
 			}
 			*clean_journals += clean;
 		}
-		inode_put(sdp->md.journal[i]);
+		inode_put(&sdp->md.journal[i]);
 	}
-	inode_put(sdp->master_dir);
-	inode_put(sdp->md.jiinode);
+	inode_put(&sdp->master_dir);
+	inode_put(&sdp->md.jiinode);
 	/* Sync the buffers to disk so we get a fresh start. */
 	bsync(&sdp->buf_list);
 	return error;
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 6bba989..b46df92 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -71,10 +71,10 @@ enum rgindex_trust_level { /* how far can we trust our RG index? */
 			  gfs2_grow or something.  Count the RGs by hand. */
 };
 
-struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sbp, uint64_t block);
-struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
+extern struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sbp, uint64_t block);
+extern struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
 				  struct gfs2_buffer_head *bh);
-void fsck_inode_put(struct gfs2_inode *ip);
+extern void fsck_inode_put(struct gfs2_inode **ip);
 
 int initialize(struct gfs2_sbd *sbp, int force_check, int preen,
 	       int *all_clean);
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index d82313b..f6746e7 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -195,10 +195,9 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
 	log_info( _("Initializing special inodes...\n"));
 
 	/* Get master dinode */
-	sdp->master_dir = gfs2_load_inode(sdp,
-					  sdp->sd_sb.sb_master_dir.no_addr);
+	sdp->master_dir = inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
 	/* Get root dinode */
-	sdp->md.rooti = gfs2_load_inode(sdp, sdp->sd_sb.sb_root_dir.no_addr);
+	sdp->md.rooti = inode_read(sdp, sdp->sd_sb.sb_root_dir.no_addr);
 
 	/* Look for "inum" entry in master dinode */
 	gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index e55b5f2..333409a 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -90,7 +90,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
 		}
 		memcpy(filename, tmp_name, filename_len);
 
-		if(gfs2_dirent_del(ip, NULL, filename, filename_len))
+		if(gfs2_dirent_del(ip, filename, filename_len))
 			log_warn( _("add_inode_to_lf:  "
 					 "Unable to remove \"..\" directory entry.\n"));
 
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index f7d1279..4fd7a09 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -274,7 +274,6 @@ void check_statfs(struct gfs2_sbd *sdp)
 {
 	osi_list_t *tmp;
 	struct rgrp_list *rgd;
-	struct gfs2_rgrp rg;
 	struct gfs2_rindex *ri;
 	struct gfs2_statfs_change sc;
 	char buf[sizeof(struct gfs2_statfs_change)];
@@ -309,8 +308,8 @@ void check_statfs(struct gfs2_sbd *sdp)
 		}
 		gfs2_rgrp_read(sdp, rgd);
 		sdp->blks_total += ri->ri_data;
-		sdp->blks_alloced += (ri->ri_data - rg.rg_free);
-		sdp->dinodes_alloced += rg.rg_dinodes;
+		sdp->blks_alloced += (ri->ri_data - rgd->rg.rg_free);
+		sdp->dinodes_alloced += rgd->rg.rg_dinodes;
 		gfs2_rgrp_relse(rgd);
 		free(rgbh);
 	}
@@ -485,18 +484,18 @@ int main(int argc, char **argv)
 	check_statfs(sbp);
 
 	/* Free up our system inodes */
-	inode_put(sbp->md.inum);
-	inode_put(sbp->md.statfs);
+	inode_put(&sbp->md.inum);
+	inode_put(&sbp->md.statfs);
 	for (j = 0; j < sbp->md.journals; j++)
-		inode_put(sbp->md.journal[j]);
-	inode_put(sbp->md.jiinode);
-	inode_put(sbp->md.riinode);
-	inode_put(sbp->md.qinode);
-	inode_put(sbp->md.pinode);
-	inode_put(sbp->md.rooti);
-	inode_put(sbp->master_dir);
+		inode_put(&sbp->md.journal[j]);
+	inode_put(&sbp->md.jiinode);
+	inode_put(&sbp->md.riinode);
+	inode_put(&sbp->md.qinode);
+	inode_put(&sbp->md.pinode);
+	inode_put(&sbp->md.rooti);
+	inode_put(&sbp->master_dir);
 	if (lf_dip)
-		inode_put(lf_dip);
+		inode_put(&lf_dip);
 
 	if (!opts.no && errors_corrected)
 		log_notice( _("Writing changes to disk\n"));
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index d3cdd22..b29224f 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -32,8 +32,6 @@
 static struct gfs2_inode *get_system_inode(struct gfs2_sbd *sbp,
 					   uint64_t block)
 {
-	int j;
-
 	if (block == sbp->md.inum->i_di.di_num.no_addr)
 		return sbp->md.inum;
 	if (block == sbp->md.statfs->i_di.di_num.no_addr)
@@ -52,10 +50,7 @@ static struct gfs2_inode *get_system_inode(struct gfs2_sbd *sbp,
 		return sbp->master_dir;
 	if (lf_dip && block == lf_dip->i_di.di_num.no_addr)
 		return lf_dip;
-	for (j = 0; j < sbp->md.journals; j++)
-		if (block == sbp->md.journal[j]->i_di.di_num.no_addr)
-			return sbp->md.journal[j];
-	return NULL;
+	return is_system_inode(sbp, block);
 }
 
 /* fsck_load_inode - same as gfs2_load_inode() in libgfs2 but system inodes
@@ -65,11 +60,9 @@ struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sbp, uint64_t block)
 	struct gfs2_inode *ip = NULL;
 
 	ip = get_system_inode(sbp, block);
-	if (ip) {
-		bhold(ip->i_bh);
+	if (ip)
 		return ip;
-	}
-	return gfs2_load_inode(sbp, block);
+	return inode_read(sbp, block);
 }
 
 /* fsck_inode_get - same as inode_get() in libgfs2 but system inodes
@@ -77,39 +70,25 @@ struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sbp, uint64_t block)
 struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp,
 				  struct gfs2_buffer_head *bh)
 {
-	struct gfs2_inode *ip, *sysip;
-
-	ip = calloc(1, sizeof(struct gfs2_inode));
-	if (ip == NULL) {
-		fprintf(stderr, _("Out of memory in %s\n"), __FUNCTION__);
-		exit(-1);
-	}
-	gfs2_dinode_in(&ip->i_di, bh);
-	ip->i_bh = bh;
-	ip->i_sbd = sdp;
+	struct gfs2_inode *sysip;
 
-	sysip = get_system_inode(sdp, ip->i_di.di_num.no_addr);
-	if (sysip) {
-		free(ip);
+	sysip = get_system_inode(sdp, bh->b_blocknr);
+	if (sysip)
 		return sysip;
-	}
-	return ip;
+
+	return inode_get(sdp, bh);
 }
 
 /* fsck_inode_put - same as inode_put() in libgfs2 but system inodes
    get special treatment. */
-void fsck_inode_put(struct gfs2_inode *ip)
+void fsck_inode_put(struct gfs2_inode **ip_in)
 {
+	struct gfs2_inode *ip = *ip_in;
 	struct gfs2_inode *sysip;
 
 	sysip = get_system_inode(ip->i_sbd, ip->i_di.di_num.no_addr);
-	if (sysip) {
-		if (ip->i_bh->b_changed)
-			gfs2_dinode_out(&ip->i_di, ip->i_bh);
-		brelse(ip->i_bh);
-	} else {
-		inode_put(ip);
-	}
+	if (!sysip)
+		inode_put(ip_in);
 }
 
 /**
@@ -257,7 +236,6 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 				} else {
 					log_err( _("Corrupt directory entry "
 						   "repaired.\n"));
-					bmodified(bh);
 					/* keep looping through dentries */
 				}
 			} else {
@@ -765,6 +743,7 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
 				   GGGG when we finish.  To do that, we set
 				   di_eattr to 0 temporarily. */
 				ip->i_di.di_eattr = 0;
+				bmodified(ip->i_bh);
 			}
 			ea_leaf_ptr++;
 		}
@@ -837,14 +816,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
 				    struct metawalk_fxns *pass)
 {
 	uint32_t height = ip->i_di.di_height;
-	struct gfs2_buffer_head *bh, *nbh, *metabh;
+	struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
 	osi_list_t *prev_list, *cur_list, *tmp;
 	int i, head_size;
 	uint64_t *ptr, block;
 	int err;
 
-	metabh = bread(&ip->i_sbd->buf_list, ip->i_di.di_num.no_addr);
-
 	osi_list_add(&metabh->b_altlist, &mlp[0]);
 
 	/* if(<there are no indirect blocks to check>) */
@@ -889,8 +866,15 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
 				}
 				if(err > 0) {
 					log_debug( _("Skipping block %" PRIu64
-						  " (0x%" PRIx64 ")\n"),
-						  block, block);
+						     " (0x%" PRIx64 ")\n"),
+						   block, block);
+					continue;
+				}
+				if (gfs2_check_range(ip->i_sbd, block)) {
+					log_debug( _("Skipping invalid block "
+						     "%lld (0x%llx)\n"),
+						   (unsigned long long)block,
+						   (unsigned long long)block);
 					continue;
 				}
 				if(!nbh)
@@ -913,8 +897,6 @@ fail:
 			osi_list_del(&nbh->b_altlist);
 		}
 	}
-	/* This is an error path, so we need to release the buffer here: */
-	brelse(metabh);
 	return -1;
 }
 
@@ -963,14 +945,23 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist);
 
 		if (height > 1) {
-			/* if this isn't really a block list skip it */
-			if (gfs2_check_meta(bh, GFS2_METATYPE_IN))
+			if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) {
+				if (bh == ip->i_bh)
+					osi_list_del(&bh->b_altlist);
+				else
+					brelse(bh);
 				continue;
+			}
 			head_size = sizeof(struct gfs2_meta_header);
 		} else {
 			/* if this isn't really a dinode, skip it */
-			if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
+			if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+				if (bh == ip->i_bh)
+					osi_list_del(&bh->b_altlist);
+				else
+					brelse(bh);
 				continue;
+			}
 			head_size = sizeof(struct gfs2_dinode);
 		}
 		ptr = (uint64_t *)(bh->b_data + head_size);
@@ -1009,7 +1000,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
 		{
 			bh = osi_list_entry(list->next,
 					    struct gfs2_buffer_head, b_altlist);
-			brelse(bh);
+			if (bh == ip->i_bh)
+				osi_list_del(&bh->b_altlist);
+			else
+				brelse(bh);
 			osi_list_del(&bh->b_altlist);
 		}
 	}
@@ -1048,31 +1042,20 @@ static int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 
 int check_dir(struct gfs2_sbd *sbp, uint64_t block, struct metawalk_fxns *pass)
 {
-	struct gfs2_buffer_head *bh;
 	struct gfs2_inode *ip;
 	int error = 0;
 
-	bh = bread(&sbp->buf_list, block);
-	ip = fsck_inode_get(sbp, bh);
+	ip = fsck_load_inode(sbp, block);
 
-	if(ip->i_di.di_flags & GFS2_DIF_EXHASH) {
+	if(ip->i_di.di_flags & GFS2_DIF_EXHASH)
 		error = check_leaf_blks(ip, pass);
-		if(error < 0) {
-			stack;
-			fsck_inode_put(ip); /* does brelse(bh); */
-			return -1;
-		}
-	}
-	else {
-		error = check_linear_dir(ip, bh, pass);
-		if(error < 0) {
-			stack;
-			fsck_inode_put(ip); /* does brelse(bh); */
-			return -1;
-		}
-	}
+	else
+		error = check_linear_dir(ip, ip->i_bh, pass);
+
+	if(error < 0)
+		stack;
 
-	fsck_inode_put(ip); /* does a brelse */
+	fsck_inode_put(&ip); /* does a brelse */
 	return error;
 }
 
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index de93345..e00b7d6 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -435,7 +435,6 @@ static int check_leaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
 				  _("Extended Attribute leaf block "
 				    "has incorrect type"));
 		}
-		bmodified(leaf_bh);
 		brelse(leaf_bh);
 		return 1;
 	}
@@ -701,7 +700,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 
 	if(gfs2_block_check(sdp, bl, block, &q)) {
 		stack;
-		fsck_inode_put(ip);
+		fsck_inode_put(&ip);
 		return -1;
 	}
 	if(q.block_type != gfs2_block_free) {
@@ -709,10 +708,10 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 			   "#%" PRIu64 " (0x%" PRIx64 ")\n"), block, block);
 		if(gfs2_block_mark(sdp, bl, block, gfs2_dup_block)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
-		fsck_inode_put(ip);
+		fsck_inode_put(&ip);
 		return 0;
 	}
 
@@ -723,12 +722,12 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_dir)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		if(add_to_dir_list(sdp, block)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -737,7 +736,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_file)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -746,7 +745,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_lnk)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -755,7 +754,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_blk)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -764,7 +763,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_chr)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -773,7 +772,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_fifo)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -782,7 +781,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_inode_sock)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		break;
@@ -791,16 +790,16 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				  block, block);
 		if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 			stack;
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return -1;
 		}
 		gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
-		fsck_inode_put(ip);
+		fsck_inode_put(&ip);
 		return 0;
 	}
 	if(set_link_count(ip->i_sbd, ip->i_di.di_num.no_addr, ip->i_di.di_nlink)) {
 		stack;
-		fsck_inode_put(ip);
+		fsck_inode_put(&ip);
 		return -1;
 	}
 
@@ -836,11 +835,11 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 			log_warn( _("Marking inode invalid\n"));
 			if(gfs2_block_set(sdp, bl, block, gfs2_meta_inval)) {
 				stack;
-				fsck_inode_put(ip);
+				fsck_inode_put(&ip);
 				return -1;
 			}
 			gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 			return 0;
 		}
 	}
@@ -849,7 +848,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 
 	error = check_metatree(ip, &pass1_fxns);
 	if (fsck_abort || error < 0) {
-		fsck_inode_put(ip);
+		fsck_inode_put(&ip);
 		return 0;
 	}
 	if(error > 0) {
@@ -861,7 +860,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 		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);
+		fsck_inode_put(&ip);
 		return 0;
 	}
 
@@ -898,7 +897,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 				(unsigned long long)ip->i_di.di_num.no_addr);
 	}
 
-	fsck_inode_put(ip);
+	fsck_inode_put(&ip);
 	return 0;
 }
 
@@ -928,7 +927,6 @@ static int scan_meta(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
 	if (!gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
 		/* handle_di calls inode_get, then inode_put, which does brelse.   */
 		/* In order to prevent brelse from getting the count off, hold it. */
-		bhold(bh);
 		if(handle_di(sdp, bh, block)) {
 			stack;
 			return -1;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 78f1ed6..3121d4c 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -351,14 +351,14 @@ static int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct dup_block
 		     ")\n"), inode, inode, b->block_no, b->block_no);
 	if(check_metatree(ip, &find_refs)) {
 		stack;
-		fsck_inode_put(ip); /* out, brelse, free */
+		fsck_inode_put(&ip); /* out, brelse, free */
 		return -1;
 	}
 	log_debug( _("Done checking metatree\n"));
 	/* Check for ea references in the inode */
 	if(check_inode_eattr(ip, &find_refs) < 0){
 		stack;
-		fsck_inode_put(ip); /* out, brelse, free */
+		fsck_inode_put(&ip); /* out, brelse, free */
 		return -1;
 	}
 	if (myfi.found) {
@@ -378,7 +378,7 @@ static int find_block_ref(struct gfs2_sbd *sbp, uint64_t inode, struct dup_block
 		id->ea_only = myfi.ea_only;
 		osi_list_add_prev(&id->list, &b->ref_inode_list);
 	}
-	fsck_inode_put(ip); /* out, brelse, free */
+	fsck_inode_put(&ip); /* out, brelse, free */
 	return 0;
 }
 
@@ -443,7 +443,7 @@ static int handle_dup_blk(struct gfs2_sbd *sbp, struct dup_blocks *b)
 					       ip->i_di.di_num.no_addr,
 					       gfs2_meta_inval);
 				bmodified(ip->i_bh);
-				fsck_inode_put(ip);
+				fsck_inode_put(&ip);
 			} else {
 				log_warn( _("The bad inode was not cleared."));
 			}
@@ -489,7 +489,7 @@ static int handle_dup_blk(struct gfs2_sbd *sbp, struct dup_blocks *b)
 
 		gfs2_block_set(ip->i_sbd, bl, ip->i_di.di_num.no_addr,
 			       gfs2_meta_inval);
-		fsck_inode_put(ip); /* out, brelse, free */
+		fsck_inode_put(&ip); /* out, brelse, free */
 		dh.ref_inode_count--;
 		if(dh.ref_inode_count == 1)
 			break;
diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c
index a00ce2d..3595bb1 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -271,6 +271,7 @@ int pass1c(struct gfs2_sbd *sbp)
 				 block_no, block_no);
 			gfs2_special_clear(&sbp->eattr_blocks, block_no);
 			ip = fsck_inode_get(sbp, bh);
+			ip->bh_owned = 1;
 
 			log_debug( _("Found eattr at %llu (0x%llx)\n"),
 				  (unsigned long long)ip->i_di.di_eattr,
@@ -282,7 +283,8 @@ int pass1c(struct gfs2_sbd *sbp)
 				brelse(bh);
 				return FSCK_ERROR;
 			}
-			fsck_inode_put(ip); /* dinode_out, brelse, free */
+
+			fsck_inode_put(&ip); /* dinode_out, brelse, free */
 		} else {
 			brelse(bh);
 		}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 6509171..8e4f05b 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -263,7 +263,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			check_inode_eattr(entry_ip, &pass2_fxns_delete);
 			check_metatree(entry_ip, &pass2_fxns_delete);
 			bmodified(entry_ip->i_bh);
-			fsck_inode_put(entry_ip);
+			fsck_inode_put(&entry_ip);
 			dirent2_del(ip, bh, prev_de, dent);
 			gfs2_block_set(sbp, bl, de->de_inum.no_addr,
 				       gfs2_block_free);
@@ -319,7 +319,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			check_inode_eattr(entry_ip, &pass2_fxns_delete);
 			check_metatree(entry_ip, &pass2_fxns_delete);
 			bmodified(entry_ip->i_bh);
-			fsck_inode_put(entry_ip);
+			fsck_inode_put(&entry_ip);
 			gfs2_block_set(sbp, bl, de->de_inum.no_addr,
 				       gfs2_block_free);
 
@@ -347,7 +347,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 		if(query( _("Clear stale directory entry? (y/n) "))) {
 			entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
 			check_inode_eattr(entry_ip, &clear_eattrs);
-			fsck_inode_put(entry_ip);
+			fsck_inode_put(&entry_ip);
 
 			dirent2_del(ip, bh, prev_de, dent);
 			bmodified(bh);
@@ -372,7 +372,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			if(query( _("Clear duplicate '.' entry? (y/n) "))) {
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
 				check_inode_eattr(entry_ip, &clear_eattrs);
-				fsck_inode_put(entry_ip);
+				fsck_inode_put(&entry_ip);
 
 				dirent2_del(ip, bh, prev_de, dent);
 				bmodified(bh);
@@ -407,7 +407,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			if(query( _("Remove '.' reference? (y/n) "))) {
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
 				check_inode_eattr(entry_ip, &clear_eattrs);
-				fsck_inode_put(entry_ip);
+				fsck_inode_put(&entry_ip);
 
 				dirent2_del(ip, bh, prev_de, dent);
 				bmodified(bh);
@@ -442,7 +442,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
 				check_inode_eattr(entry_ip, &clear_eattrs);
-				fsck_inode_put(entry_ip);
+				fsck_inode_put(&entry_ip);
 
 				dirent2_del(ip, bh, prev_de, dent);
 				bmodified(bh);
@@ -467,7 +467,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
 			if(query( _("Clear bad '..' directory entry? (y/n) "))) {
 				entry_ip = fsck_load_inode(sbp, de->de_inum.no_addr);
 				check_inode_eattr(entry_ip, &clear_eattrs);
-				fsck_inode_put(entry_ip);
+				fsck_inode_put(&entry_ip);
 
 				dirent2_del(ip, bh, prev_de, dent);
 				bmodified(bh);
@@ -557,7 +557,6 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 {
 	uint64_t iblock = 0;
 	struct dir_status ds = {0};
-	struct gfs2_buffer_head b, *bh = &b;
 	char *filename;
 	int filename_len;
 	char tmp_name[256];
@@ -587,7 +586,6 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 	if (error > 0)
 		gfs2_block_set(sysinode->i_sbd, bl, iblock, gfs2_meta_inval);
 
-	bh = bhold(sysinode->i_bh);
 	if(check_inode_eattr(sysinode, &pass2_fxns)) {
 		stack;
 		return -1;
@@ -616,7 +614,6 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 				       sysinode->i_di.di_num.no_addr);
 			ds.entry_count++;
 			free(filename);
-			bmodified(sysinode->i_bh);
 		} else
 			log_err( _("The directory was not fixed.\n"));
 	}
@@ -642,10 +639,6 @@ int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
 				sysinode->i_di.di_num.no_addr);
 		}
 	}
-
-	if (!opts.no)
-		bmodified(bh);
-	brelse(bh);
 	return 0;
 }
 
@@ -679,7 +672,6 @@ int pass2(struct gfs2_sbd *sbp)
 	struct gfs2_block_query q;
 	struct dir_status ds = {0};
 	struct gfs2_inode *ip;
-	struct gfs2_buffer_head *bh = NULL;
 	char *filename;
 	int filename_len;
 	char tmp_name[256];
@@ -733,11 +725,10 @@ int pass2(struct gfs2_sbd *sbp)
 			 * is valid */
 			ip = fsck_load_inode(sbp, i);
 			if(check_metatree(ip, &pass2_fxns)) {
-				fsck_inode_put(ip);
+				fsck_inode_put(&ip);
 				stack;
 				return FSCK_ERROR;
 			}
-			fsck_inode_put(ip);
 		}
 		error = check_dir(sbp, i, &pass2_fxns);
 		if(error < 0) {
@@ -775,8 +766,7 @@ int pass2(struct gfs2_sbd *sbp)
 			}
 			gfs2_block_set(sbp, bl, i, gfs2_meta_inval);
 		}
-		bh = bread(&sbp->buf_list, i);
-		ip = fsck_inode_get(sbp, bh);
+		ip = fsck_load_inode(sbp, i);
 		if(!ds.dotdir) {
 			log_err(_("No '.' entry found for directory inode at "
 				  "block %"PRIu64" (0x%" PRIx64 ")\n"), i, i);
@@ -806,7 +796,6 @@ int pass2(struct gfs2_sbd *sbp)
 				ds.entry_count++;
 				free(filename);
 				log_err( _("The directory was fixed.\n"));
-				bmodified(ip->i_bh);
 			} else {
 				log_err( _("The directory was not fixed.\n"));
 			}
@@ -825,7 +814,7 @@ int pass2(struct gfs2_sbd *sbp)
 				log_err( _("The entry count was not fixed.\n"));
 			}
 		}
-		fsck_inode_put(ip); /* does a gfs2_dinode_out, brelse */
+		fsck_inode_put(&ip); /* does a gfs2_dinode_out, brelse */
 	}
 	/* Now that we've deleted the inodes marked "bad" we can safely
 	   get rid of the duplicate block list.  If we do it any sooner,
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 910ecf3..c4ea3a5 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -45,29 +45,29 @@ static int attach_dotdot_to(struct gfs2_sbd *sbp, uint64_t newdotdot,
 	filename_len = strlen("..");
 	if(!(filename = malloc((sizeof(char) * filename_len) + 1))) {
 		log_err( _("Unable to allocate name\n"));
-		fsck_inode_put(ip);
-		fsck_inode_put(pip);
+		fsck_inode_put(&ip);
+		fsck_inode_put(&pip);
 		stack;
 		return -1;
 	}
 	if(!memset(filename, 0, (sizeof(char) * filename_len) + 1)) {
 		log_err( _("Unable to zero name\n"));
-		fsck_inode_put(ip);
-		fsck_inode_put(pip);
+		fsck_inode_put(&ip);
+		fsck_inode_put(&pip);
 		stack;
 		return -1;
 	}
 	memcpy(filename, "..", filename_len);
-	if(gfs2_dirent_del(ip, NULL, filename, filename_len))
+	if(gfs2_dirent_del(ip, filename, filename_len))
 		log_warn( _("Unable to remove \"..\" directory entry.\n"));
 	else
 		decrement_link(sbp, olddotdot);
 	dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
 	increment_link(sbp, newdotdot);
 	bmodified(ip->i_bh);
-	fsck_inode_put(ip);
+	fsck_inode_put(&ip);
 	bmodified(pip->i_bh);
-	fsck_inode_put(pip);
+	fsck_inode_put(&pip);
 	return 0;
 }
 
@@ -266,7 +266,7 @@ int pass3(struct gfs2_sbd *sbp)
 						gfs2_block_set(sbp, bl,
 							       di->dinode,
 							       gfs2_block_free);
-						fsck_inode_put(ip);
+						fsck_inode_put(&ip);
 						break;
 					} else {
 						log_err( _("Zero-size unlinked directory remains\n"));
@@ -275,16 +275,16 @@ int pass3(struct gfs2_sbd *sbp)
 				if(query( _("Add unlinked directory to "
 					    "lost+found? (y/n) "))) {
 					if(add_inode_to_lf(ip)) {
-						fsck_inode_put(ip);
+						fsck_inode_put(&ip);
 						stack;
 						return FSCK_ERROR;
 					}
 					log_warn( _("Directory relinked to lost+found\n"));
 					bmodified(ip->i_bh);
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 				} else {
 					log_err( _("Unlinked directory remains unlinked\n"));
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 				}
 				break;
 			}
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 0d590d5..c6328b5 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -88,7 +88,7 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 							  &pass4_fxns_delete);
 					check_metatree(ip, &pass4_fxns_delete);
 					bmodified(ip->i_bh);
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 					gfs2_block_set(sbp, bl, ii->inode,
 						       gfs2_block_free);
 					continue;
@@ -117,7 +117,7 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				} else {
 					log_err( _("The inode was not "
 						   "deleted\n"));
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 				}
 				continue;
 			}
@@ -131,16 +131,16 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				if(query( _("Clear zero-size unlinked inode? (y/n) "))) {
 					gfs2_block_set(sbp, bl, ii->inode,
 						       gfs2_block_free);
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 					continue;
 				}
 
 			}
-			if(query( _("Add unlinked inode to lost+found? (y/n)"))) {
-				bmodified(ip->i_bh);
+			if(query( _("Add unlinked inode to lost+found? "
+				    "(y/n)"))) {
 				if(add_inode_to_lf(ip)) {
 					stack;
-					fsck_inode_put(ip);
+					fsck_inode_put(&ip);
 					return -1;
 				}
 				else {
@@ -149,7 +149,7 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				}
 			} else
 				log_err( _("Unlinked inode left unlinked\n"));
-			fsck_inode_put(ip);
+			fsck_inode_put(&ip);
 		} /* if(ii->counted_links == 0) */
 		else if(ii->link_count != ii->counted_links) {
 			log_err( _("Link count inconsistent for inode %" PRIu64
@@ -163,7 +163,7 @@ static int scan_inode_list(struct gfs2_sbd *sbp, osi_list_t *list) {
 				ip = fsck_load_inode(sbp, ii->inode); /* bread, inode_get */
 				fix_inode_count(sbp, ii, ip);
 				bmodified(ip->i_bh);
-				fsck_inode_put(ip); /* out, brelse, free */
+				fsck_inode_put(&ip); /* out, brelse, free */
 				log_warn( _("Link count updated for inode %"
 						 PRIu64 " (0x%" PRIx64 ") \n"), ii->inode, ii->inode);
 			} else {
diff --git a/gfs2/libgfs2/fs_bits.c b/gfs2/libgfs2/fs_bits.c
index 9dc34c8..e8e601b 100644
--- a/gfs2/libgfs2/fs_bits.c
+++ b/gfs2/libgfs2/fs_bits.c
@@ -18,53 +18,6 @@
 
 #include "libgfs2.h"
 
-uint32_t gfs2_bitfit_core(struct gfs2_sbd *sbp, uint64_t goal, uint64_t start,
-						  uint64_t len, unsigned char old_state,
-						  struct gfs2_block_list *bl)
-{
-	uint64_t block;
-	struct gfs2_block_query q;
-
-	for(block = start+goal; block < start+len; block++) {
-		gfs2_block_check(sbp, bl, block, &q);
-		switch(old_state) {
-			/* FIXME Make sure these are handled correctly */
-		case GFS2_BLKST_FREE:
-			switch(q.block_type) {
-			case gfs2_block_free:
-				return block - start;
-			}
-			break;
-		case GFS2_BLKST_DINODE:
-			switch(q.block_type) {
-			case gfs2_inode_dir:
-			case gfs2_inode_file:
-			case gfs2_inode_lnk:
-			case gfs2_inode_blk:
-			case gfs2_inode_chr:
-			case gfs2_inode_fifo:
-			case gfs2_inode_sock:
-				return block - start;
-			}
-			break;
-		case GFS2_BLKST_USED:
-			switch(q.block_type) {
-			case gfs2_indir_blk:
-			case gfs2_leaf_blk:
-			case gfs2_journal_blk:
-			case gfs2_meta_other:
-			case gfs2_meta_eattr:
-			case gfs2_block_used:
-				return block - start;
-			}
-			break;
-		case GFS2_BLKST_UNLINKED:
-		default:
-			break;
-		}
-	}
-	return BFITNOENT;
-}
 /**
  * gfs2_bitfit - Find a free block in the bitmaps
  * @buffer: the buffer that holds the bitmaps
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 1dcae78..fccbfd3 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -43,15 +43,76 @@ struct gfs2_inode *inode_get(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
 	gfs2_dinode_in(&ip->i_di, bh);
 	ip->i_bh = bh;
 	ip->i_sbd = sdp;
+	ip->bh_owned = 0; /* caller did the bread so we don't own the bh */
 	return ip;
 }
 
-void inode_put(struct gfs2_inode *ip)
+struct gfs2_inode *inode_read(struct gfs2_sbd *sdp, uint64_t di_addr)
 {
-	if (ip->i_bh->b_changed)
+	struct gfs2_inode *ip;
+
+	ip = calloc(1, sizeof(struct gfs2_inode));
+	if (ip == NULL) {
+		fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
+		exit(-1);
+	}
+	ip->i_bh = bread(&sdp->buf_list, di_addr);
+	gfs2_dinode_in(&ip->i_di, ip->i_bh);
+	ip->i_sbd = sdp;
+	ip->bh_owned = 1; /* We did the bread so we own the bh */
+	return ip;
+}
+
+struct gfs2_inode *is_system_inode(struct gfs2_sbd *sdp, uint64_t block)
+{
+	int j;
+
+	if (sdp->md.inum && block == sdp->md.inum->i_di.di_num.no_addr)
+		return sdp->md.inum;
+	if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
+		return sdp->md.statfs;
+	if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
+		return sdp->md.jiinode;
+	if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
+		return sdp->md.riinode;
+	if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
+		return sdp->md.qinode;
+	if (sdp->md.pinode && block == sdp->md.pinode->i_di.di_num.no_addr)
+		return sdp->md.pinode;
+	if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
+		return sdp->md.rooti;
+	if (sdp->master_dir && block == sdp->master_dir->i_di.di_num.no_addr)
+		return sdp->master_dir;
+	for (j = 0; j < sdp->md.journals; j++)
+		if (sdp->md.journal && sdp->md.journal[j] &&
+		    block == sdp->md.journal[j]->i_di.di_num.no_addr)
+			return sdp->md.journal[j];
+	return NULL;
+}
+
+void inode_put(struct gfs2_inode **ip_in)
+{
+	struct gfs2_inode *ip = *ip_in;
+	uint64_t block = ip->i_di.di_num.no_addr;
+	struct gfs2_sbd *sdp = ip->i_sbd;
+
+	if (ip->i_bh->b_changed) {
 		gfs2_dinode_out(&ip->i_di, ip->i_bh);
-	brelse(ip->i_bh);
+		if (!ip->bh_owned && is_system_inode(sdp, block))
+			fprintf(stderr, "Warning: Change made to inode "
+				"were discarded.\n");
+		/* This is for debugging only: a convenient place to set
+		   a breakpoint. This means a system inode was modified but
+		   not written.  That's not fatal: some places like
+		   adjust_inode in gfs2_convert will do this on purpose.
+		   It can also point out a coding problem, but we don't
+		   want to raise alarm in the users either. */
+	}
+	if (ip->bh_owned)
+		brelse(ip->i_bh);
+	ip->i_bh = NULL;
 	free(ip);
+	*ip_in = NULL; /* make sure the memory isn't accessed again */
 }
 
 static uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type)
@@ -129,6 +190,7 @@ uint64_t data_alloc(struct gfs2_inode *ip)
 	uint64_t x;
 	x = blk_alloc_i(ip->i_sbd, DATA);
 	ip->i_di.di_goal_data = x;
+	bmodified(ip->i_bh);
 	return x;
 }
 
@@ -137,6 +199,7 @@ uint64_t meta_alloc(struct gfs2_inode *ip)
 	uint64_t x;
 	x = blk_alloc_i(ip->i_sbd, META);
 	ip->i_di.di_goal_meta = x;
+	bmodified(ip->i_bh);
 	return x;
 }
 
@@ -319,6 +382,7 @@ void lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 	*ptr = cpu_to_be64(*block);
 	bmodified(bh);
 	ip->i_di.di_blocks++;
+	bmodified(ip->i_bh);
 
 	*new = 1;
 }
@@ -362,11 +426,12 @@ void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 	mp = find_metapath(ip, lblock);
 	end_of_metadata = ip->i_di.di_height - 1;
 
-	bh = bhold(ip->i_bh);
+	bh = ip->i_bh;
 
 	for (x = 0; x < end_of_metadata; x++) {
 		lookup_block(ip, bh, x, mp, create, new, dblock);
-		brelse(bh);
+		if (bh != ip->i_bh)
+			brelse(bh);
 		if (!*dblock)
 			goto out;
 
@@ -377,8 +442,12 @@ void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 			mh.mh_type = GFS2_METATYPE_IN;
 			mh.mh_format = GFS2_FORMAT_IN;
 			gfs2_meta_header_out(&mh, bh);
-		} else
-			bh = bread(&sdp->buf_list, *dblock);
+		} else {
+			if (*dblock == ip->i_di.di_num.no_addr)
+				bh = ip->i_bh;
+			else
+				bh = bread(&sdp->buf_list, *dblock);
+		}
 	}
 
 	if (!prealloc)
@@ -406,7 +475,8 @@ void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 		}
 	}
 
-	brelse(bh);
+	if (bh != ip->i_bh)
+		brelse(bh);
 
  out:
 	free(mp);
@@ -471,14 +541,17 @@ int gfs2_readi(struct gfs2_inode *ip, void *buf,
 				  FALSE);
 
 		if (dblock) {
-			bh = bread(&sdp->buf_list, dblock);
+			if (dblock == ip->i_di.di_num.no_addr)
+				bh = ip->i_bh;
+			else
+				bh = bread(&sdp->buf_list, dblock);
 			dblock++;
 			extlen--;
 		} else
 			bh = NULL;
 
 		copy2mem(bh, &buf, o, amount);
-		if (bh)
+		if (bh && bh != ip->i_bh)
 			brelse(bh);
 
 		copied += amount;
@@ -553,11 +626,15 @@ int gfs2_writei(struct gfs2_inode *ip, void *buf,
 				mh.mh_format = GFS2_FORMAT_JD;
 				gfs2_meta_header_out(&mh, bh);
 			}
-		} else
-			bh = bread(&sdp->buf_list, dblock);
+		} else {
+			if (dblock == ip->i_di.di_num.no_addr)
+				bh = ip->i_bh;
+			else
+				bh = bread(&sdp->buf_list, dblock);
+		}
 		copy_from_mem(bh, &buf, o, amount);
-		bmodified(bh);
-		brelse(bh);
+		if (bh != ip->i_bh)
+			brelse(bh);
 
 		copied += amount;
 		lblock++;
@@ -567,8 +644,10 @@ int gfs2_writei(struct gfs2_inode *ip, void *buf,
 		o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
 	}
 
-	if (ip->i_di.di_size < start + copied)
+	if (ip->i_di.di_size < start + copied) {
+		bmodified(ip->i_bh);
 		ip->i_di.di_size = start + copied;
+	}
 
 	return copied;
 }
@@ -588,13 +667,18 @@ struct gfs2_buffer_head *get_file_buf(struct gfs2_inode *ip, uint64_t lbn,
 		die("get_file_buf\n");
 
 	if (!prealloc && new &&
-	    ip->i_di.di_size < (lbn + 1) << sdp->sd_sb.sb_bsize_shift)
+	    ip->i_di.di_size < (lbn + 1) << sdp->sd_sb.sb_bsize_shift) {
+		bmodified(ip->i_bh);
 		ip->i_di.di_size = (lbn + 1) << sdp->sd_sb.sb_bsize_shift;
-
+	}
 	if (new)
 		return bget(&sdp->buf_list, dbn);
-	else
-		return bread(&sdp->buf_list, dbn);
+	else {
+		if (dbn == ip->i_di.di_num.no_addr)
+			return ip->i_bh;
+		else
+			return bread(&sdp->buf_list, dbn);
+	}
 }
 
 int gfs2_dirent_first(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
@@ -653,6 +737,8 @@ static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 		dent->de_name_len = cpu_to_be16(name_len);
 		bmodified(bh);
 		*dent_out = dent;
+		dip->i_di.di_entries++;
+		bmodified(dip->i_bh);
 		return 0;
 	}
 
@@ -678,6 +764,8 @@ static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 											   be16_to_cpu(new->de_rec_len));
 				*dent_out = new;
 				bmodified(bh);
+				dip->i_di.di_entries++;
+				bmodified(dip->i_bh);
 				return 0;
 			}
 
@@ -685,6 +773,8 @@ static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 
 			*dent_out = dent;
 			bmodified(bh);
+			dip->i_di.di_entries++;
+			bmodified(dip->i_bh);
 			return 0;
 		}
 	} while (gfs2_dirent_next(dip, bh, &dent) == 0);
@@ -698,9 +788,10 @@ void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 	uint16_t cur_rec_len, prev_rec_len;
 
 	bmodified(bh);
-	bmodified(dip->i_bh);
-	if (dip->i_di.di_entries)
+	if (dip->i_di.di_entries) {
+		bmodified(dip->i_bh);
 		dip->i_di.di_entries--;
+	}
 	if (!prev) {
 		cur->de_inum.no_formal_ino = 0;
 		return;
@@ -837,8 +928,10 @@ static void dir_split_leaf(struct gfs2_inode *dip, uint32_t lindex, uint64_t lea
 	nleaf->lf_depth = oleaf->lf_depth;
 
 	dip->i_di.di_blocks++;
+	bmodified(dip->i_bh);
 
 	brelse(obh);
+	bmodified(nbh);
 	brelse(nbh);
 }
 
@@ -878,6 +971,7 @@ static void dir_double_exhash(struct gfs2_inode *dip)
 	free(buf);
 
 	dip->i_di.di_depth++;
+	bmodified(dip->i_bh);
 }
 
 /**
@@ -1004,6 +1098,7 @@ static void dir_e_add(struct gfs2_inode *dip, const char *filename, int len,
 
 				dirent_alloc(dip, nbh, len, &dent);
 				dip->i_di.di_blocks++;
+				bmodified(dip->i_bh);
 				bmodified(bh);
 				brelse(bh);
 				bh = nbh;
@@ -1021,9 +1116,6 @@ static void dir_e_add(struct gfs2_inode *dip, const char *filename, int len,
 
 		bmodified(bh);
 		brelse(bh);
-
-		dip->i_di.di_entries++;
-		bmodified(dip->i_bh);
 		return;
 	}
 }
@@ -1086,6 +1178,8 @@ static void dir_make_exhash(struct gfs2_inode *dip)
 
 	for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
 	dip->i_di.di_depth = y;
+
+	gfs2_dinode_out(&dip->i_di, dip->i_bh);
 }
 
 static void dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
@@ -1104,9 +1198,6 @@ static void dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
 	dent->de_hash = cpu_to_be32(dent->de_hash);
 	dent->de_type = cpu_to_be16(type);
 	memcpy((char *)(dent + 1), filename, len);
-
-	dip->i_di.di_entries++;
-	bmodified(dip->i_bh);
 }
 
 void dir_add(struct gfs2_inode *dip, const char *filename, int len,
@@ -1199,13 +1290,16 @@ struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
 
 		dir_add(dip, filename, strlen(filename), &inum, IF2DT(mode));
 
-		if(S_ISDIR(mode))
+		if(S_ISDIR(mode)) {
+			bmodified(dip->i_bh);
 			dip->i_di.di_nlink++;
+		}
 
 		bh = init_dinode(sdp, &inum, mode, flags, &dip->i_di.di_num);
 		ip = inode_get(sdp, bh);
 		bmodified(bh);
 	}
+	ip->bh_owned = 1;
 	return ip;
 }
 
@@ -1321,7 +1415,7 @@ static int linked_leaf_search(struct gfs2_inode *dip, const char *filename,
 
 	/*  Find the entry  */
 	do{
-		if (bh)
+		if (bh && bh != dip->i_bh)
 			brelse(bh);
 
 		bh = bh_next;
@@ -1336,14 +1430,16 @@ static int linked_leaf_search(struct gfs2_inode *dip, const char *filename,
 			break;
 			
 		default:
-			brelse(bh);
+			if (bh && bh != dip->i_bh)
+				brelse(bh);
 			return error;
 		}
 		
 		error = get_next_leaf(dip, bh, &bh_next);
 	} while (!error);
 	
-	brelse(bh);
+	if (bh && bh != dip->i_bh)
+		brelse(bh);
 	
 	return error;
 }
@@ -1388,21 +1484,18 @@ static int dir_e_search(struct gfs2_inode *dip, const char *filename,
 static int dir_l_search(struct gfs2_inode *dip, const char *filename,
 			int len, unsigned int *type, struct gfs2_inum *inum)
 {
-	struct gfs2_buffer_head *dibh;
 	struct gfs2_dirent *dent;
 	int error;
 
 	if(!inode_is_stuffed(dip))
 		return -1;
 
-	dibh = bread(&dip->i_sbd->buf_list, dip->i_di.di_num.no_addr);
-	error = leaf_search(dip, dibh, filename, len, &dent, NULL);
+	error = leaf_search(dip, dip->i_bh, filename, len, &dent, NULL);
 	if (!error) {
 		gfs2_inum_in(inum, (char *)&dent->de_inum);
 		if(type)
 			*type = be16_to_cpu(dent->de_type);
 	}
-	brelse(dibh);
 	return error;
 }
 
@@ -1474,37 +1567,23 @@ static int dir_e_del(struct gfs2_inode *dip, const char *filename, int len)
 	return 0;
 }
 
-static int dir_l_del(struct gfs2_inode *dip, struct gfs2_buffer_head *dibh,
-		     const char *filename, int len){
+static int dir_l_del(struct gfs2_inode *dip, const char *filename, int len)
+{
 	int error=0;
-	int got_buf = 0;
 	struct gfs2_dirent *cur, *prev;
 
 	if(!inode_is_stuffed(dip))
 		return -1;
 
-	if(!dibh) {
-		dibh = bread(&dip->i_sbd->buf_list, dip->i_di.di_num.no_addr);
-		if (error)
-			return -1;
-		got_buf = 1;
-	}
-
-	error = leaf_search(dip, dibh, filename, len, &cur, &prev);
+	error = leaf_search(dip, dip->i_bh, filename, len, &cur, &prev);
 	if (error) {
-		if (got_buf)
-			brelse(dibh);
 		if (error == -ENOENT)
 			return 1;
 		else
 			return -1;
 	}
 
-	dirent2_del(dip, dibh, prev, cur);
-	if (got_buf) {
-		bmodified(dibh);
-		brelse(dibh);
-	}
+	dirent2_del(dip, dip->i_bh, prev, cur);
 	return 0;
 }
 
@@ -1520,8 +1599,8 @@ static int dir_l_del(struct gfs2_inode *dip, struct gfs2_buffer_head *dibh,
  *
  * Returns: 0 on success (or if it doesn't already exist), -1 on failure
  */
-int gfs2_dirent_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
-		    const char *filename, int len){
+int gfs2_dirent_del(struct gfs2_inode *dip, const char *filename, int len)
+{
 	int error;
 
 	if(!S_ISDIR(dip->i_di.di_mode))
@@ -1530,7 +1609,7 @@ int gfs2_dirent_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
 		error = dir_e_del(dip, filename, len);
 	else
-		error = dir_l_del(dip, bh, filename, len);
+		error = dir_l_del(dip, filename, len);
 	bmodified(dip->i_bh);
 	return error;
 }
@@ -1564,7 +1643,7 @@ int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
 			return 0;
 	}
 	else
-		*ipp = gfs2_load_inode(sdp, inum.no_addr);
+		*ipp = inode_read(sdp, inum.no_addr);
 
 	return error;
 }
@@ -1637,8 +1716,7 @@ int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t diblock)
 	}
 	/* Set the bitmap type for inode to free space: */
 	gfs2_set_bitmap(sdp, ip->i_di.di_num.no_addr, GFS2_BLKST_FREE);
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
         /* inode_put deallocated the extra block used by the disk inode, */
         /* so adjust it in the superblock struct */
 	sdp->blks_alloced--;
diff --git a/gfs2/libgfs2/gfs1.c b/gfs2/libgfs2/gfs1.c
index a06fe11..5232c01 100644
--- a/gfs2/libgfs2/gfs1.c
+++ b/gfs2/libgfs2/gfs1.c
@@ -98,11 +98,12 @@ void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 	mp = find_metapath(ip, lblock);
 	end_of_metadata = ip->i_di.di_height - 1;
 
-	bh = bhold(ip->i_bh);
+	bh = ip->i_bh;
 
 	for (x = 0; x < end_of_metadata; x++) {
 		gfs1_lookup_block(ip, bh, x, mp, create, new, dblock);
-		brelse(bh);
+		if (bh != ip->i_bh)
+			brelse(bh);
 		if (!*dblock)
 			goto out;
 
@@ -146,7 +147,8 @@ void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 		}
 	}
 
-	brelse(bh);
+	if (bh != ip->i_bh)
+		brelse(bh);
 
  out:
 	free(mp);
@@ -395,5 +397,49 @@ struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
 	ip->i_di.di_eattr = gfs1_dinode.di_eattr;
 	ip->i_bh = bh;
 	ip->i_sbd = sdp;
+	ip->bh_owned = 0;
+	return ip;
+}
+
+struct gfs2_inode *gfs_inode_read(struct gfs2_sbd *sdp, uint64_t di_addr)
+{
+	struct gfs_dinode gfs1_dinode;
+	struct gfs2_inode *ip;
+
+	ip = calloc(1, sizeof(struct gfs2_inode));
+	if (ip == NULL) {
+		fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
+		exit(-1);
+	}
+
+	ip->i_bh = bread(&sdp->buf_list, di_addr);
+	gfs_dinode_in(&gfs1_dinode, ip->i_bh);
+	memcpy(&ip->i_di.di_header, &gfs1_dinode.di_header,
+	       sizeof(struct gfs2_meta_header));
+	memcpy(&ip->i_di.di_num, &gfs1_dinode.di_num,
+	       sizeof(struct gfs2_inum));
+	ip->i_di.di_mode = gfs1_dinode.di_mode;
+	ip->i_di.di_uid = gfs1_dinode.di_uid;
+	ip->i_di.di_gid = gfs1_dinode.di_gid;
+	ip->i_di.di_nlink = gfs1_dinode.di_nlink;
+	ip->i_di.di_size = gfs1_dinode.di_size;
+	ip->i_di.di_blocks = gfs1_dinode.di_blocks;
+	ip->i_di.di_atime = gfs1_dinode.di_atime;
+	ip->i_di.di_mtime = gfs1_dinode.di_mtime;
+	ip->i_di.di_ctime = gfs1_dinode.di_ctime;
+	ip->i_di.di_major = gfs1_dinode.di_major;
+	ip->i_di.di_minor = gfs1_dinode.di_minor;
+	ip->i_di.di_goal_data = gfs1_dinode.di_goal_dblk;
+	ip->i_di.di_goal_meta = gfs1_dinode.di_goal_mblk;
+	ip->i_di.di_flags = gfs1_dinode.di_flags;
+	ip->i_di.di_payload_format = gfs1_dinode.di_payload_format;
+	ip->i_di.__pad1 = gfs1_dinode.di_type;
+	ip->i_di.di_height = gfs1_dinode.di_height;
+	ip->i_di.di_depth = gfs1_dinode.di_depth;
+	ip->i_di.di_entries = gfs1_dinode.di_entries;
+	ip->i_di.di_eattr = gfs1_dinode.di_eattr;
+	ip->i_sbd = sdp;
+	ip->bh_owned = 1;
 	return ip;
 }
+
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 47faa60..a6b9314 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -134,6 +134,7 @@ struct special_blocks {
 
 struct gfs2_sbd;
 struct gfs2_inode {
+	int bh_owned; /* Is this bh owned, iow, should we release it later? */
 	struct gfs2_dinode i_di;
 	struct gfs2_buffer_head *i_bh;
 	struct gfs2_sbd *i_sbd;
@@ -438,7 +439,10 @@ extern void lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
 			 int create, int *new, uint64_t *block);
 extern struct gfs2_inode *inode_get(struct gfs2_sbd *sdp,
 				    struct gfs2_buffer_head *bh);
-extern void inode_put(struct gfs2_inode *ip);
+extern struct gfs2_inode *inode_read(struct gfs2_sbd *sdp, uint64_t di_addr);
+extern struct gfs2_inode *is_system_inode(struct gfs2_sbd *sdp,
+					  uint64_t block);
+extern void inode_put(struct gfs2_inode **ip);
 extern uint64_t data_alloc(struct gfs2_inode *ip);
 extern uint64_t meta_alloc(struct gfs2_inode *ip);
 extern uint64_t dinode_alloc(struct gfs2_sbd *sdp);
@@ -456,13 +460,12 @@ extern struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
 				  unsigned int mode, uint32_t flags);
 extern void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 			struct gfs2_dirent *prev, struct gfs2_dirent *cur);
-extern struct gfs2_inode *gfs2_load_inode(struct gfs2_sbd *sbp, uint64_t block);
 extern int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
 			struct gfs2_inode **ipp);
 extern void dir_add(struct gfs2_inode *dip, const char *filename, int len,
 		    struct gfs2_inum *inum, unsigned int type);
-extern int gfs2_dirent_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
-			   const char *filename, int filename_len);
+extern int gfs2_dirent_del(struct gfs2_inode *dip, const char *filename,
+			   int filename_len);
 extern void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 		      uint64_t *dblock, uint32_t *extlen, int prealloc);
 extern void gfs2_get_leaf_nr(struct gfs2_inode *dip, uint32_t index,
@@ -558,6 +561,8 @@ extern int gfs1_rindex_read(struct gfs2_sbd *sdp, int fd, int *count1);
 extern int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount, int quiet);
 extern struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
 					struct gfs2_buffer_head *bh);
+extern struct gfs2_inode *gfs_inode_read(struct gfs2_sbd *sdp,
+					 uint64_t di_addr);
 
 /* gfs2_log.c */
 struct gfs2_options {
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 5e4a8c3..0dabbc0 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -43,6 +43,7 @@ void build_master(struct gfs2_sbd *sdp)
 		printf("\nMaster dir:\n");
 		gfs2_dinode_print(&sdp->master_dir->i_di);
 	}
+	sdp->master_dir->bh_owned = 1;
 }
 
 void
@@ -123,6 +124,7 @@ void write_journal(struct gfs2_sbd *sdp, struct gfs2_inode *ip, unsigned int j,
 		hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
 		((struct gfs2_log_header *)bh->b_data)->lh_hash = cpu_to_be32(hash);
 
+		bmodified(bh);
 		brelse(bh);
 
 		if (++seq == blocks)
@@ -152,8 +154,7 @@ build_jindex(struct gfs2_sbd *sdp)
 		ip = createi(jindex, name, S_IFREG | 0600, GFS2_DIF_SYSTEM);
 		write_journal(sdp, ip, j,
 			      sdp->jsize << 20 >> sdp->sd_sb.sb_bsize_shift);
-		bmodified(ip->i_bh);
-		inode_put(ip);
+		inode_put(&ip);
 	}
 
 	if (sdp->debug) {
@@ -161,8 +162,7 @@ build_jindex(struct gfs2_sbd *sdp)
 		gfs2_dinode_print(&jindex->i_di);
 	}
 
-	bmodified(jindex->i_bh);
-	inode_put(jindex);
+	inode_put(&jindex);
 }
 
 static void
@@ -176,14 +176,14 @@ build_inum_range(struct gfs2_inode *per_node, unsigned int j)
 	ip = createi(per_node, name, S_IFREG | 0600,
 		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
 	ip->i_di.di_size = sizeof(struct gfs2_inum_range);
+	gfs2_dinode_out(&ip->i_di, ip->i_bh);
 
 	if (sdp->debug) {
 		printf("\nInum Range %u:\n", j);
 		gfs2_dinode_print(&ip->i_di);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 }
 
 static void
@@ -197,14 +197,14 @@ build_statfs_change(struct gfs2_inode *per_node, unsigned int j)
 	ip = createi(per_node, name, S_IFREG | 0600,
 		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
 	ip->i_di.di_size = sizeof(struct gfs2_statfs_change);
+	gfs2_dinode_out(&ip->i_di, ip->i_bh);
 
 	if (sdp->debug) {
 		printf("\nStatFS Change %u:\n", j);
 		gfs2_dinode_print(&ip->i_di);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 }
 
 static void
@@ -241,8 +241,7 @@ build_quota_change(struct gfs2_inode *per_node, unsigned int j)
 		gfs2_dinode_print(&ip->i_di);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 }
 
 void
@@ -265,8 +264,7 @@ build_per_node(struct gfs2_sbd *sdp)
 		gfs2_dinode_print(&per_node->i_di);
 	}
 
-	bmodified(per_node->i_bh);
-	inode_put(per_node);
+	inode_put(&per_node);
 }
 
 void
@@ -313,6 +311,7 @@ build_rindex(struct gfs2_sbd *sdp)
 	ip = createi(sdp->master_dir, "rindex", S_IFREG | 0600,
 		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
 	ip->i_di.di_payload_format = GFS2_FORMAT_RI;
+	bmodified(ip->i_bh);
 
 	for (head = &sdp->rglist, tmp = head->next;
 	     tmp != head;
@@ -332,8 +331,7 @@ build_rindex(struct gfs2_sbd *sdp)
 		gfs2_dinode_print(&ip->i_di);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 }
 
 void
@@ -347,6 +345,7 @@ build_quota(struct gfs2_sbd *sdp)
 	ip = createi(sdp->master_dir, "quota", S_IFREG | 0600,
 		     GFS2_DIF_SYSTEM | GFS2_DIF_JDATA);
 	ip->i_di.di_payload_format = GFS2_FORMAT_QU;
+	bmodified(ip->i_bh);
 
 	memset(&qu, 0, sizeof(struct gfs2_quota));
 	qu.qu_value = 1;
@@ -364,8 +363,7 @@ build_quota(struct gfs2_sbd *sdp)
 		gfs2_quota_print(&qu);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 }
 
 void
@@ -386,6 +384,7 @@ build_root(struct gfs2_sbd *sdp)
 		printf("\nRoot directory:\n");
 		gfs2_dinode_print(&sdp->md.rooti->i_di);
 	}
+	sdp->md.rooti->bh_owned = 1;
 }
 
 void do_init_inum(struct gfs2_sbd *sdp)
@@ -426,16 +425,6 @@ void do_init_statfs(struct gfs2_sbd *sdp)
 	}
 }
 
-struct gfs2_inode *gfs2_load_inode(struct gfs2_sbd *sbp, uint64_t block)
-{
-	struct gfs2_buffer_head *bh;
-	struct gfs2_inode *ip;
-
-	bh = bread(&sbp->buf_list, block);
-	ip = inode_get(sbp, bh);
-	return ip;
-}
-
 int gfs2_check_meta(struct gfs2_buffer_head *bh, int type)
 {
 	uint32_t check_magic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
diff --git a/gfs2/mkfs/main_grow.c b/gfs2/mkfs/main_grow.c
index 345babe..1b7b501 100644
--- a/gfs2/mkfs/main_grow.c
+++ b/gfs2/mkfs/main_grow.c
@@ -179,11 +179,8 @@ static void initialize_new_portion(struct gfs2_sbd *sdp, int *old_rg_count)
 	/* Build the remaining resource groups */
 	build_rgrps(sdp, !test);
 
-	/* Note: We do inode_put with not_updated because we only updated */
-	/* the new RGs/bitmaps themselves on disk.  The rindex file must  */
-	/* be updated through the meta_fs so the gfs2 kernel is informed. */
-	inode_put(sdp->md.riinode);
-	inode_put(sdp->master_dir);
+	inode_put(&sdp->md.riinode);
+	inode_put(&sdp->master_dir);
 
 	/* We're done with the libgfs portion, so commit it to disk.      */
 	bsync(&sdp->buf_list);
@@ -304,7 +301,7 @@ main_grow(int argc, char *argv[])
 		}
 		/* Get master dinode */
 		sdp->master_dir =
-			gfs2_load_inode(sdp, sdp->sd_sb.sb_master_dir.no_addr);
+			inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
 		gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
 		/* Fetch the rindex from disk.  We aren't using gfs2 here,  */
 		/* which means that the bitmaps will most likely be cached  */
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index c33f216..101280b 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -503,14 +503,10 @@ main_mkfs(int argc, char *argv[])
 
 	/* Cleanup */
 
-	bmodified(sdp->md.rooti->i_bh);
-	inode_put(sdp->md.rooti);
-	bmodified(sdp->master_dir->i_bh);
-	inode_put(sdp->master_dir);
-	bmodified(sdp->md.inum->i_bh);
-	inode_put(sdp->md.inum);
-	bmodified(sdp->md.statfs->i_bh);
-	inode_put(sdp->md.statfs);
+	inode_put(&sdp->md.rooti);
+	inode_put(&sdp->master_dir);
+	inode_put(&sdp->md.inum);
+	inode_put(&sdp->md.statfs);
 	bsync(&sdp->buf_list);
 
 	error = fsync(sdp->device_fd);
diff --git a/gfs2/tool/df.c b/gfs2/tool/df.c
index 025fc85..abf00f9 100644
--- a/gfs2/tool/df.c
+++ b/gfs2/tool/df.c
@@ -96,6 +96,7 @@ do_df_one(char *path)
 	struct gfs2_sbd sbd;
 	char buf[GFS2_DEFAULT_BSIZE], statfs_fn[PATH_MAX];
 	struct gfs2_statfs_change sc;
+	struct gfs2_buffer_head bh;
 
 	memset(&sbd, 0, sizeof(struct gfs2_sbd));
 	sbd.path_name = path;
@@ -117,12 +118,12 @@ do_df_one(char *path)
 	do_lseek(sbd.device_fd, 0x10 * sbd.bsize);
 	do_read(sbd.device_fd, buf, sbd.bsize); /* read in the superblock */
 
-	gfs2_sb_in(&sbd.sd_sb, buf); /* parse it out into the sb structure */
+	bh.b_data = buf;
+	gfs2_sb_in(&sbd.sd_sb, &bh); /* parse it out into the sb structure */
 	sbd.bsize = sbd.sd_sb.sb_bsize;
 	compute_constants(&sbd);
 
-	sbd.master_dir = gfs2_load_inode(&sbd,
-					 sbd.sd_sb.sb_master_dir.no_addr);
+	sbd.master_dir = inode_read(&sbd, sbd.sd_sb.sb_master_dir.no_addr);
 
 	gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode);
 	gfs2_lookupi(sbd.master_dir, "jindex", 6, &sbd.md.jiinode);