cluster: STABLE3 - Attach bh's to inodes

Bob Peterson rpeterso at fedoraproject.org
Tue Jan 26 21:19:19 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=71fb85ae21db98d08128ff27ca4c17ac7dd4139d
Commit:        71fb85ae21db98d08128ff27ca4c17ac7dd4139d
Parent:        8956735abb1523be8d63cfbbb55d16c535795cae
Author:        Bob Peterson <bob at ganesha.peterson>
AuthorDate:    Tue Jan 19 13:51:13 2010 -0600
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Tue Jan 26 14:39:28 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
---
 gfs2/convert/gfs2_convert.c |   73 ++++++++---------
 gfs2/edit/hexedit.c         |   23 ++---
 gfs2/edit/savemeta.c        |   20 ++---
 gfs2/fsck/fs_recovery.c     |    9 +-
 gfs2/fsck/fsck.h            |    6 +-
 gfs2/fsck/initialize.c      |    5 +-
 gfs2/fsck/lost_n_found.c    |    2 +-
 gfs2/fsck/main.c            |   20 ++--
 gfs2/fsck/metawalk.c        |  111 ++++++++++--------------
 gfs2/fsck/pass1.c           |   40 ++++-----
 gfs2/fsck/pass1b.c          |   10 +-
 gfs2/fsck/pass1c.c          |    4 +-
 gfs2/fsck/pass2.c           |   31 ++-----
 gfs2/fsck/pass3.c           |   22 +++---
 gfs2/fsck/pass4.c           |   16 ++--
 gfs2/libgfs2/fs_ops.c       |  196 ++++++++++++++++++++++++++++++-------------
 gfs2/libgfs2/gfs1.c         |   52 +++++++++++-
 gfs2/libgfs2/libgfs2.h      |   13 ++-
 gfs2/libgfs2/structures.c   |   41 ++++------
 gfs2/mkfs/main_grow.c       |    9 +--
 gfs2/mkfs/main_mkfs.c       |   12 +--
 21 files changed, 390 insertions(+), 325 deletions(-)

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index ba21e94..02bd9b9 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -310,12 +310,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;
 
@@ -334,7 +335,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;
 
@@ -404,8 +406,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;
@@ -416,6 +417,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)
@@ -656,11 +658,12 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 		inode->i_di.di_goal_data = 0; /* make sure the upper 32b are 0 */
 		inode->i_di.di_goal_data = gfs1_dinode_struct->di_goal_dblk;
 		inode->i_di.di_generation = 0;
-		if (adjust_indirect_blocks(sbp, bh, inode))
+		if (adjust_indirect_blocks(sbp, inode))
 			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 */
@@ -763,15 +766,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 */
 
@@ -926,7 +926,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;
@@ -948,27 +947,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) {
@@ -1140,11 +1136,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: */
@@ -1163,8 +1158,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 */
@@ -1464,11 +1459,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];
@@ -1477,20 +1471,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);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1595,9 +1590,9 @@ int main(int argc, char **argv)
 		update_inode_file(&sb2);
 		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 a277b7a..b3f31e6 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -786,7 +786,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);
 }
@@ -870,7 +870,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;
 
@@ -878,14 +877,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;
 }
 
@@ -1596,17 +1594,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)
@@ -1744,8 +1740,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 {
@@ -1753,7 +1748,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/savemeta.c b/gfs2/edit/savemeta.c
index 99bc986..18a0798 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -407,7 +407,7 @@ static void save_inode_data(int out_fd)
 		}
 		brelse(lbh);
 	}
-	inode_put(inode);
+	inode_put(&inode);
 	brelse(metabh);
 }
 
@@ -429,19 +429,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);
@@ -451,10 +450,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;
 	}
@@ -577,14 +572,13 @@ void savemeta(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 be9d3d0..71f1544 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -552,8 +552,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 */
@@ -577,10 +576,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 bf3b74c..15c33f9 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -59,10 +59,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 555e8e4..9d3def5 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -178,10 +178,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 4170380..cc2ba14 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -77,7 +77,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 616cbdc..fba0c42 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -455,18 +455,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 f34a185..bdb8b80 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -19,8 +19,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)
@@ -39,10 +37,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
@@ -52,11 +47,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
@@ -64,39 +57,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);
 }
 
 /**
@@ -244,7 +223,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 {
@@ -753,6 +731,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++;
 		}
@@ -825,14 +804,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>) */
@@ -877,8 +854,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)
@@ -901,8 +885,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;
 }
 
@@ -951,14 +933,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);
@@ -997,7 +988,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);
 		}
 	}
@@ -1036,31 +1030,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 3638102..40dc6e2 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -421,7 +421,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;
 	}
@@ -687,7 +686,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) {
@@ -695,10 +694,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;
 	}
 
@@ -709,12 +708,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;
@@ -723,7 +722,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;
@@ -732,7 +731,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;
@@ -741,7 +740,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;
@@ -750,7 +749,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;
@@ -759,7 +758,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;
@@ -768,7 +767,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;
@@ -777,16 +776,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;
 	}
 
@@ -803,11 +802,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;
 		}
 	}
@@ -816,7 +815,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) {
@@ -828,7 +827,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;
 	}
 
@@ -865,7 +864,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;
 }
 
@@ -895,7 +894,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 8eaca6f..a1b327a 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -336,14 +336,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) {
@@ -363,7 +363,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;
 }
 
@@ -428,7 +428,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."));
 			}
@@ -474,7 +474,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 9bb7b4a..4d9c820 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -258,6 +258,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,
@@ -269,7 +270,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 f7ad911..40256a5 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -250,7 +250,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);
@@ -306,7 +306,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);
 
@@ -334,7 +334,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);
@@ -359,7 +359,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);
@@ -394,7 +394,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);
@@ -429,7 +429,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);
@@ -454,7 +454,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);
@@ -544,7 +544,6 @@ static 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];
@@ -574,7 +573,6 @@ static 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;
@@ -603,7 +601,6 @@ static 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"));
 	}
@@ -629,10 +626,6 @@ static 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;
 }
 
@@ -666,7 +659,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];
@@ -720,11 +712,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) {
@@ -762,8 +753,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);
@@ -793,7 +783,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"));
 			}
@@ -812,7 +801,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 16fa086..feeebdc 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -32,29 +32,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;
 }
 
@@ -253,7 +253,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"));
@@ -262,16 +262,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 1ab18ea..6389342 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -75,7 +75,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;
@@ -104,7 +104,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;
 			}
@@ -118,16 +118,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 {
@@ -136,7 +136,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
@@ -150,7 +150,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_ops.c b/gfs2/libgfs2/fs_ops.c
index 19ebc38..4279d99 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -40,15 +40,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)
@@ -126,6 +187,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;
 }
 
@@ -134,6 +196,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;
 }
 
@@ -321,6 +384,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;
 }
@@ -364,11 +428,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;
 
@@ -379,8 +444,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)
@@ -408,7 +477,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);
@@ -474,14 +544,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;
@@ -557,11 +630,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++;
@@ -571,8 +648,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;
 }
@@ -592,13 +671,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,
@@ -657,6 +741,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;
 	}
 
@@ -685,6 +771,8 @@ static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
 
 				*dent_out = new;
 				bmodified(bh);
+				dip->i_di.di_entries++;
+				bmodified(dip->i_bh);
 				return 0;
 			}
 
@@ -692,6 +780,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);
@@ -705,9 +795,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;
@@ -847,8 +938,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);
 }
 
@@ -892,6 +985,7 @@ static void dir_double_exhash(struct gfs2_inode *dip)
 	free(buf);
 
 	dip->i_di.di_depth++;
+	bmodified(dip->i_bh);
 }
 
 /**
@@ -1018,6 +1112,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;
@@ -1035,9 +1130,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;
 	}
 }
@@ -1101,6 +1193,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,
@@ -1119,9 +1213,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,
@@ -1213,13 +1304,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;
 }
 
@@ -1335,7 +1429,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;
@@ -1350,14 +1444,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;
 }
@@ -1402,21 +1498,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;
 }
 
@@ -1488,37 +1581,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;
 }
 
@@ -1534,8 +1613,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))
@@ -1544,7 +1623,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;
 }
@@ -1578,7 +1657,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;
 }
@@ -1650,8 +1729,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);
 	/* Now we have to adjust the rg freespace count and inode count: */
 	rgd = gfs2_blk2rgrpd(sdp, diblock);
 	rgd->rg.rg_free++;
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 49bc151..643c728 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -129,6 +129,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;
@@ -409,7 +410,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);
@@ -427,13 +431,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,
@@ -529,6 +532,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 6a481bc..5343f88 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -30,6 +30,7 @@ int build_master(struct gfs2_sbd *sdp)
 		printf("\nMaster dir:\n");
 		gfs2_dinode_print(&sdp->master_dir->i_di);
 	}
+	sdp->master_dir->bh_owned = 1;
 	return 0;
 }
 
@@ -110,6 +111,7 @@ int 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)
@@ -142,8 +144,7 @@ int build_jindex(struct gfs2_sbd *sdp)
 			      sdp->jsize << 20 >> sdp->sd_sb.sb_bsize_shift);
 		if (ret)
 			return ret;
-		bmodified(ip->i_bh);
-		inode_put(ip);
+		inode_put(&ip);
 	}
 
 	if (sdp->debug) {
@@ -151,8 +152,7 @@ int build_jindex(struct gfs2_sbd *sdp)
 		gfs2_dinode_print(&jindex->i_di);
 	}
 
-	bmodified(jindex->i_bh);
-	inode_put(jindex);
+	inode_put(&jindex);
 	return 0;
 }
 
@@ -166,14 +166,14 @@ static int 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);
 	return 0;
 }
 
@@ -187,14 +187,14 @@ static void 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 int build_quota_change(struct gfs2_inode *per_node, unsigned int j)
@@ -230,8 +230,7 @@ static int 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);
 	return 0;
 }
 
@@ -254,8 +253,7 @@ int 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);
 	return 0;
 }
 
@@ -302,6 +300,7 @@ int 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;
@@ -321,8 +320,7 @@ int build_rindex(struct gfs2_sbd *sdp)
 		gfs2_dinode_print(&ip->i_di);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 	return 0;
 }
 
@@ -336,6 +334,7 @@ int 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;
@@ -353,8 +352,7 @@ int build_quota(struct gfs2_sbd *sdp)
 		gfs2_quota_print(&qu);
 	}
 
-	bmodified(ip->i_bh);
-	inode_put(ip);
+	inode_put(&ip);
 	return 0;
 }
 
@@ -375,6 +373,7 @@ int build_root(struct gfs2_sbd *sdp)
 		printf("\nRoot directory:\n");
 		gfs2_dinode_print(&sdp->md.rooti->i_di);
 	}
+	sdp->md.rooti->bh_owned = 1;
 	return 0;
 }
 
@@ -418,16 +417,6 @@ int do_init_statfs(struct gfs2_sbd *sdp)
 	return 0;
 }
 
-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 52b8c38..2da353a 100644
--- a/gfs2/mkfs/main_grow.c
+++ b/gfs2/mkfs/main_grow.c
@@ -167,11 +167,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);
@@ -317,7 +314,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 6ebaa99..3d3012f 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -637,14 +637,10 @@ void 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);


More information about the cluster-commits mailing list