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


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

cluster: master - Fix many bugs with gfs2_convert.


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=59b908abfd33ab22db1af45916eb0a11076f588f
Commit:        59b908abfd33ab22db1af45916eb0a11076f588f
Parent:        660c6e6907205fed807bc8a0527fc03b40f9f3b9
Author:        Bob Peterson <rpeterso@redhat.com>
AuthorDate:    Mon Dec 1 11:50:58 2008 -0600
Committer:     Bob Peterson <rpeterso@redhat.com>
CommitterDate: Mon Dec 1 11:50:58 2008 -0600

Fix many bugs with gfs2_convert.

bz 471618 - GFS2: gfs2_convert is broken

Functional changes to the code are as follows:

1. Original problem is fixed

The original problem reported in the bug was caused because
there is a fundamental shift of indirect block pointers between
GFS1 and GFS2.  For indirect blocks, GFS1 added 64 bytes of
reserved space after the gfs meta header.  GFS2 did not.  That
meant GFS1 could hold fewer pointers than GFS2 on the same block.
The meant code had to be added to gfs2_convert to shuffle all
the pointers around to their corresponding gfs2 locations.
This was not a simple calculation because of sparse files.  For
example, with a 1K block size, if you do:

dd if=/mnt/gfs/big of=/tmp/tocompare skip=496572346368 bs=1024 count=1

the resulting metadata paths will look vastly different for the
single block of data:

height    0     1     2     3     4     5
GFS1:  0x16  0x46  0x70  0x11  0x5e  0x4a
GFS2:  0x10  0x21  0x78  0x05  0x14  0x78

It is relatively easy to calculate the new metapath, but you
can't just shuffle a pointer from its old location to its new
location because the destination slot might be used for a
different source slot.  In the example above, we couldn't just
move the pointer at height 3 from offset 0x11 to another block
at offset 0x05 because there might already be a pointer at 0x05
being used for something else.

To complicate matters, we could not just assign new blocks and
copy the data because we should be able to run on a "full" file
system.  So I had to write a complex new function called
adjust_indirect_blocks along with several support functions.
Someone else might be able to write a function to get the job
done simpler, but at least this one works for both sparse and
fully-packed metadata trees of several heights.  It basically
formulates in memory a metadata tree for all the data blocks,
clears out all the metadata buffers, and lays them all back down
again according to the new layout.

2. Improved error checking

I added some badly needed error checking.  That's because I was
running into problems and wanted to eliminate the possibility
that errors were occurring, but not being reported.

3. Improved progress reporting

With a large number of resource groups, I saw long periods of
time where the program would just sit for five minutes.  I was
afraid that the tool had hung, so I kept breaking in with gdb
to check on the tool's progress.  But if I'm that concerned
about what it is doing when it's quiet, so too will be the
customers who are anxiously trying to watch its progress.  So I
added periodic reports of progress through the RGs when converting
inodes, and also an occasional "." when the RGs themselves are
being analyzed and/or manipulated.

Same goes for writing out the new gfs2 journals.  The journals in
gfs2 are quite different and we need to write them out entirely,
all 128MB.  That takes a fair amount of time going through the
functions in buf.c.  So I added a new message when each journal is
written, so that the code doesn't appear stuck for a long period
of time.  This could still use some improvement, but it's better.

I also modified the progress messages to make them more clear.
For example, the message "Removing obsolete gfs1 structures"
sounded to me like it could cause alarm or panic to a customer.
So I rephased it to "Removing obsolete GFS1 file system
structures".

4. Journal size was not being preserved

In testing, I discovered that if the source file system had 32MB
journals, the reformatted GFS2 file system had 128MB.  I decided
that's not good and decided to fix it.  That is especially
important if the file system is "full" to begin with because we
can't add more blocks.

5. Fixed a segfault dealing with buffer management.
---
 gfs2/convert/gfs2_convert.c |  572 +++++++++++++++++++++++++++++++++++++------
 gfs2/edit/gfs2hex.c         |    2 +-
 gfs2/edit/hexedit.c         |   73 ++----
 gfs2/edit/hexedit.h         |   57 +-----
 gfs2/edit/savemeta.c        |  375 +---------------------------
 gfs2/fsck/fs_recovery.c     |    7 +-
 gfs2/fsck/initialize.c      |    4 +-
 gfs2/fsck/main.c            |    3 +-
 gfs2/fsck/metawalk.c        |   13 +-
 gfs2/fsck/pass1.c           |   10 +-
 gfs2/fsck/pass1b.c          |    4 +-
 gfs2/fsck/pass1c.c          |    6 +-
 gfs2/fsck/pass2.c           |    8 +-
 gfs2/fsck/rgrepair.c        |   10 +-
 gfs2/libgfs2/Makefile       |    1 +
 gfs2/libgfs2/buf.c          |  106 +++++----
 gfs2/libgfs2/fs_geometry.c  |    2 +-
 gfs2/libgfs2/fs_ops.c       |   97 ++++----
 gfs2/libgfs2/gfs1.c         |  395 +++++++++++++++++++++++++++++
 gfs2/libgfs2/libgfs2.h      |  117 ++++++++-
 gfs2/libgfs2/misc.c         |   66 +++---
 gfs2/libgfs2/recovery.c     |    4 +-
 gfs2/libgfs2/rgrp.c         |   10 +-
 gfs2/libgfs2/structures.c   |    8 +-
 gfs2/libgfs2/super.c        |   12 +-
 gfs2/mkfs/main_grow.c       |   10 +-
 gfs2/mkfs/main_mkfs.c       |   12 +-
 gfs2/tool/df.c              |    8 +-
 28 files changed, 1234 insertions(+), 758 deletions(-)

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 08d725c..8808e7d 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -113,57 +113,24 @@ struct gfs1_sb {
 	char sb_reserved[96];
 };
 
-struct gfs1_dinode {
-	struct gfs2_meta_header di_header;
-
-	struct gfs2_inum di_num; /* formal inode # and block address */
-
-	uint32_t di_mode;	/* mode of file */
-	uint32_t di_uid;	/* owner's user id */
-	uint32_t di_gid;	/* owner's group id */
-	uint32_t di_nlink;	/* number (qty) of links to this file */
-	uint64_t di_size;	/* number (qty) of bytes in file */
-	uint64_t di_blocks;	/* number (qty) of blocks in file */
-	int64_t di_atime;	/* time last accessed */
-	int64_t di_mtime;	/* time last modified */
-	int64_t di_ctime;	/* time last changed */
-
-	/*  Non-zero only for character or block device nodes  */
-	uint32_t di_major;	/* device major number */
-	uint32_t di_minor;	/* device minor number */
-
-	/*  Block allocation strategy  */
-	uint64_t di_rgrp;	/* dinode rgrp block number */
-	uint64_t di_goal_rgrp;	/* rgrp to alloc from next */
-	uint32_t di_goal_dblk;	/* data block goal */
-	uint32_t di_goal_mblk;	/* metadata block goal */
-
-	uint32_t di_flags;	/* GFS_DIF_... */
-
-	/*  struct gfs_rindex, struct gfs_jindex, or struct gfs_dirent */
-	uint32_t di_payload_format;  /* GFS_FORMAT_... */
-	uint16_t di_type;	/* GFS_FILE_... type of file */
-	uint16_t di_height;	/* height of metadata (0 == stuffed) */
-	uint32_t di_incarn;	/* incarnation (unused, see gfs_meta_header) */
-	uint16_t di_pad;
-
-	/*  These only apply to directories  */
-	uint16_t di_depth;	/* Number of bits in the table */
-	uint32_t di_entries;	/* The # (qty) of entries in the directory */
-
-	/*  This formed an on-disk chain of unused dinodes  */
-	struct gfs2_inum di_next_unused;  /* used in old versions only */
-
-	uint64_t di_eattr;	/* extended attribute block number */
-
-	char di_reserved[56];
-};
-
 struct inode_block {
 	osi_list_t list;
 	uint64_t di_addr;
 };
 
+struct blocklist {
+	osi_list_t list;
+	uint64_t lbparent; /* parent's buffer offset */
+	uint64_t dbparent; /* parent's disk block */
+	uint64_t dblock; /* disk block */
+	uint64_t lblock; /* logical block relative to start of file */
+};
+
+struct metapath2 {
+	unsigned int mp_list[GFS2_MAX_META_HEIGHT];
+	struct gfs2_buffer_head *mp_bh[GFS2_MAX_META_HEIGHT];
+};
+
 struct gfs1_sb  raw_gfs1_ondisk_sb;
 struct gfs2_sbd sb2;
 char device[256];
@@ -174,6 +141,11 @@ uint64_t dirs_fixed;
 uint64_t dirents_fixed;
 char *prog_name = "gfs2_convert"; /* needed by libgfs2 */
 struct gfs1_jindex *sd_jindex = NULL;    /* gfs1 journal index in memory */
+int gfs2_inptrs;
+uint64_t gfs2_heightsize[GFS2_MAX_META_HEIGHT];
+uint64_t gfs2_jheightsize[GFS2_MAX_META_HEIGHT];
+int gfs2_max_height;
+int gfs2_max_jheight;
 
 /* ------------------------------------------------------------------------- */
 /* This function is for libgfs's sake.                                       */
@@ -203,9 +175,13 @@ void convert_bitmaps(struct gfs2_sbd *sdp, struct rgrp_list *rgd2,
 	struct gfs2_buffer_head *bh;
 
 	ri = &rgd2->ri;
-	gfs2_compute_bitstructs(sdp, rgd2); /* mallocs bh as array */
+	if (gfs2_compute_bitstructs(sdp, rgd2)) { /* mallocs bh as array */
+		log_crit("gfs2_convert: Error converting bitmaps.\n");
+		exit(-1);
+	}
 	for (blk = 0; blk < ri->ri_length; blk++) {
-		bh = bget_generic(sdp, ri->ri_addr + blk, read_disk, read_disk);
+		bh = bget_generic(&sdp->nvbuf_list, ri->ri_addr + blk,
+				  read_disk, read_disk);
 		if (!rgd2->bh[blk])
 			rgd2->bh[blk] = bh;
 		x = (blk) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
@@ -217,6 +193,7 @@ void convert_bitmaps(struct gfs2_sbd *sdp, struct rgrp_list *rgd2,
 				if (state == 0x02) /* unallocated metadata state invalid */
 					rgd2->bh[blk]->b_data[x] &= ~(0x02 << (GFS2_BIT_SIZE * y));
 			}
+		brelse(bh, updated);
 	}
 }/* convert_bitmaps */
 
@@ -230,6 +207,7 @@ static int convert_rgs(struct gfs2_sbd *sbp)
 	osi_list_t *tmp;
 	struct gfs2_buffer_head *bh;
 	struct gfs1_rgrp *rgd1;
+	int rgs = 0;
 
 	/* --------------------------------- */
 	/* Now convert its rgs into gfs2 rgs */
@@ -244,17 +222,378 @@ static int convert_rgs(struct gfs2_sbd *sbp)
 		sbp->blks_total += rgd->ri.ri_data;
 		sbp->blks_alloced += (rgd->ri.ri_data - rgd->rg.rg_free);
 		sbp->dinodes_alloced += rgd1->rg_useddi;
-
 		convert_bitmaps(sbp, rgd, TRUE);
 		/* Write the updated rgrp to the gfs2 buffer */
-		bh = bget(sbp, rgd->ri.ri_addr); /* get a gfs2 buffer for the rg */
+		bh = bget(&sbp->nvbuf_list,
+			  rgd->ri.ri_addr); /* get a gfs2 buffer for the rg */
 		gfs2_rgrp_out(&rgd->rg, rgd->bh[0]->b_data);
 		brelse(bh, updated); /* release the buffer */
+		rgs++;
+		if (rgs % 100 == 0) {
+			printf(".");
+			fflush(stdout);
+		}
 	}
 	return 0;
 }/* superblock_cvt */
 
 /* ------------------------------------------------------------------------- */
+/* find_lbh - find a gfs2_buffer_head in a list, based on relative block #   */
+/* ------------------------------------------------------------------------- */
+struct gfs2_buffer_head *find_lbh(struct gfs2_sbd *sbp,
+				  struct blocklist *blist, uint64_t lblock)
+{
+	struct gfs2_buffer_head *bh;
+	osi_list_t *head, *tmp;
+	struct blocklist *blk;
+
+	head = &blist->list;
+
+	for (tmp = head->next; tmp != head; tmp = tmp->next) {
+		blk = osi_list_entry(tmp, struct blocklist, list);
+		if (blk->lbparent == lblock) {
+			bh = bget(&sbp->buf_list, blk->dblock);
+			return bh;
+		}
+	}
+	/* We didn't find one that has the same offset, so let's just reuse
+	   a bh from the same height */
+	blk->lbparent = lblock;
+	bh = bget(&sbp->buf_list, blk->dblock);
+	return bh;
+}
+
+/* ------------------------------------------------------------------------- */
+/* calc_gfs2_tree_height - calculate new dinode height as if this is gfs2    */
+/* ------------------------------------------------------------------------- */
+unsigned int calc_gfs2_tree_height(struct gfs2_inode *ip, uint64_t size)
+{
+	uint64_t *arr;
+	unsigned int max, height;
+
+	if (ip->i_di.di_size > size)
+		size = ip->i_di.di_size;
+
+	if (S_ISDIR(ip->i_di.di_mode)) {
+		arr = gfs2_jheightsize;
+		max = gfs2_max_jheight;
+	} else {
+		arr = gfs2_heightsize;
+		max = gfs2_max_height;
+	}
+
+	for (height = 0; height < max; height++)
+		if (arr[height] >= size)
+			break;
+
+	return height;
+}
+
+/* ------------------------------------------------------------------------- */
+/* gfs1_mp_to_lblock - convert a gfs1 metapath back to a logical block num.  */
+/* ------------------------------------------------------------------------- */
+uint64_t gfs1_mp_to_lblock(struct gfs2_sbd *sbp, int height, int width,
+			   struct blocklist *srcblk,
+			   struct blocklist *blocks[GFS2_MAX_META_HEIGHT])
+{
+	uint64_t lblock;
+	osi_list_t *head, *tmp;
+	int h;
+	struct blocklist *blk, *higher_blk = srcblk;
+	uint64_t gfs1factor[GFS2_MAX_META_HEIGHT];
+
+	/* figure out multiplication factors for each height */
+	memset(&gfs1factor, 0, sizeof(gfs1factor));
+	gfs1factor[height] = 1ull;
+	for (h = height; h > 0; h--)
+		gfs1factor[h - 1] = gfs1factor[h] * sbp->sd_inptrs;
+	/* First, factor in our own height */
+	lblock = width;
+	for (h = height - 1; h > 0; h--) {
+		head = &blocks[h]->list;
+		for (tmp = head->next; tmp != head; tmp = tmp->next) {
+			blk = osi_list_entry(tmp, struct blocklist, list);
+			if (higher_blk->dbparent == blk->dblock) {
+				lblock += (blk->lbparent * gfs1factor[h]);
+				higher_blk = blk;
+				break; /* found it, go to the next height */
+			}
+		}
+	}
+	return lblock;
+}
+
+/* ------------------------------------------------------------------------- */
+/* adjust_indirect_blocks - convert all gfs_indirect blocks to gfs2.         */
+/*                                                                           */
+/* This function converts all gfs_indirect blocks to GFS2.  The difference   */
+/* is that gfs1 indirect block has a 64-byte chunk of reserved space that    */
+/* gfs2 does not.  Since GFS block locations (relative to the start of the   */
+/* file have their locations defined by the offset from the end of the       */
+/* structure, all block pointers must be shifted.                            */
+/*                                                                           */
+/* Stuffed inodes don't need to be shifted at since there are no indirect    */
+/* blocks.  Inodes with height 1 don't need to be shifted either, because    */
+/* the dinode size is the same between gfs and gfs2 (232 bytes), and         */
+/* therefore you can fit the same number of block pointers after the dinode  */
+/* structure.  For the normal 4K block size, that's 483 pointers.  For 1K    */
+/* blocks, it's 99 pointers.                                                 */
+/*                                                                           */
+/* At height 2 things get complex.  GFS1 reserves an area of 64 (0x40) bytes */
+/* at the start of the indirect block, so for 4K blocks, you can fit 501     */
+/* pointers.  GFS2 doesn't reserve that space, so you can fit 509 pointers.  */
+/* For 1K blocks, it's 117 pointers in GFS1 and 125 in GFS2.                 */
+/*                                                                           */
+/* That means, for example, that if you have 4K blocks, a 946MB file will    */
+/* require a height of 3 for GFS, but only a height of 2 for GFS2.           */
+/* There isn't a good way to shift the pointers around from one height to    */
+/* another, so the only way to do it is to rebuild all those indirect blocks */
+/* from empty ones.                                                          */
+/*                                                                           */
+/* For example, with a 1K block size, if you do:                             */
+/*                                                                           */
+/* dd if=/mnt/gfs/big of=/tmp/tocompare skip=496572346368 bs=1024 count=1    */
+/*                                                                           */
+/* the resulting metadata paths will look vastly different for the data:     */
+/*                                                                           */
+/* height    0     1     2     3     4     5                                 */
+/* GFS1:  0x16  0x46  0x70  0x11  0x5e  0x4a                                 */
+/* GFS2:  0x10  0x21  0x78  0x05  0x14  0x78                                 */
+/*                                                                           */
+/* To complicate matters, we can't really require free space.  A user might  */
+/* be trying to migrate a "full" gfs1 file system to GFS2.  After we         */
+/* convert the journals to GFS2, we might have more free space, so we can    */
+/* allocate blocks at that time.                                             */
+/*                                                                           */
+/* Assumes: GFS1 values are in place for diptrs and inptrs.                  */
+/*                                                                           */
+/* Returns: 0 on success, -1 on failure                                      */
+/*                                                                           */
+/* Adapted from gfs2_fsck metawalk.c's build_and_check_metalist              */
+/* ------------------------------------------------------------------------- */
+int adjust_indirect_blocks(struct gfs2_sbd *sbp, struct gfs2_buffer_head *dibh,
+			   struct gfs2_inode *ip)
+{
+	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
+	uint32_t height1 = ip->i_di.di_height, gfs2_height;
+	struct gfs2_buffer_head *bh, *nbh;
+	osi_list_t *next_list, *cur_list, *tmp, *head;
+	int h, h2, head_size1, head_size2;
+	uint64_t *ptr1, *ptr2, block, b, metablocks_gfs1, metablocks_gfs2;
+	int error = 0;
+	struct metapath mp;
+	struct blocklist *blocks[GFS2_MAX_META_HEIGHT], *blk;
+
+	/* if there are no indirect blocks to check */
+	if (height1 <= 1)
+		return 0;
+
+	/* zero all pointers so we can tell what to free if we need to abort */
+	for (h = 0; h <= height1; h++)
+		blocks[h] = NULL;
+	for (h = 0; h <= height1; h++) {
+		blocks[h] = malloc(sizeof(struct blocklist));
+		if (!blocks[h]) {
+			log_crit("Error: Can't allocate memory for indirect "
+				 "block adjustment\n");
+			error = -1;
+			goto out;
+		}
+		memset(blocks[h], 0, sizeof(struct blocklist));
+		osi_list_init(&blocks[h]->list);
+	}
+
+	/* Now run the metadata chain and build the block lists */
+	for (h = 0; h < GFS2_MAX_META_HEIGHT; h++)
+		osi_list_init(&metalist[h]);
+
+	osi_list_add(&dibh->b_altlist, &metalist[0]);
+	memset(&mp, 0, sizeof(mp));
+
+	/* Add the dinode block to the metaheader list */
+	blk = malloc(sizeof(struct blocklist));
+	if (!blk) {
+		log_crit("Error: Can't allocate memory"
+			 " for indirect block fix.\n");
+		error = -1;
+		goto out;
+	}
+	memset(blk, 0, sizeof(*blk));
+	blk->dbparent = 0ull;
+	blk->dblock = ip->i_di.di_num.no_addr;
+	blk->lbparent = -1;
+	blk->lblock = 0ull;
+	osi_list_add_prev(&blk->list, &blocks[0]->list);
+
+	for (h = 0; h < height1; h++){
+		cur_list = &metalist[h];
+		next_list = &metalist[h + 1]; /* future metadata to process */
+		head_size1 = (h > 0 ? sizeof(struct gfs_indirect) :
+			      sizeof(struct gfs_dinode));
+
+		mp.mp_list[h] = 0;
+		for (tmp = cur_list->next; tmp != cur_list; tmp = tmp->next){
+			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
+					    b_altlist);
+
+			for (ptr1 = (uint64_t *)(bh->b_data + head_size1);
+			     (char *)ptr1 < (bh->b_data + sbp->bsize);
+			     ptr1++, mp.mp_list[h]++) {
+				nbh = NULL;
+				if (!*ptr1)
+					continue;
+
+				b = block = be64_to_cpu(*ptr1);
+
+				blk = malloc(sizeof(struct blocklist));
+				if (!blk) {
+					log_crit("Error: Can't allocate memory"
+					       " for indirect block fix.\n");
+					error = -1;
+					goto out;
+				}
+				memset(blk, 0, sizeof(*blk));
+				blk->dbparent = bh->b_blocknr;
+				blk->dblock = block;
+				blk->lbparent = mp.mp_list[h];
+				osi_list_add_prev(&blk->list,
+						  &blocks[h + 1]->list);
+				if (h == height1 - 1)
+					blk->lblock = gfs1_mp_to_lblock(sbp,
+								height1,
+								mp.mp_list[h],
+								blk, blocks);
+				else
+					blk->lblock = 0ull;
+				if (h == height1 - 1) /* if not metadata */
+					continue; /* don't queue it up */
+				/* read the next metadata block in the chain */
+				if(!nbh)
+					nbh = bread(&sbp->buf_list, block);
+				osi_list_add_prev(&nbh->b_altlist, next_list);
+			} /* for all data on the indirect block */
+			for (h2 = h; h2 > 0; h2--)
+				if (mp.mp_list[h2] >= sbp->sd_inptrs) {
+					mp.mp_list[h2 - 1]++;
+					mp.mp_list[h2] = 0;
+				}
+		} /* for blocks at that height */
+	} /* for height */
+
+	/* Run through the metadata block list and zero out all the block */
+	/* pointers in the buffers so we can start clean.                 */
+	/* We've got to keep track of how many blocks we actually use for */
+	/* the converted metadata because we need to free the blocks we   */
+	/* don't use and mark the proper number as "blocks used" in the   */
+	/* dinode's di_blocks.  For example, in a normal 4K block file    */
+	/* system a contiguous file that is 4152273 bytes long needs 1014 */
+	/* data blocks.  GFS1 needs 3 gfs_indirect metadata blocks to     */
+	/* keep track: (1) 0-500, (2) 501-1001, (3) 1002=1014.  However,  */
+	/* GFS2 only needs 2 metadata blocks to keep track: (1) 0-508,    */
+	/* (2) 509-1014.  So the dinode's count of blocks used has to be  */
+	/* one less, and that final block needs to be freed.              */
+	/* I'm going to use the bh->b_changed flag to keep track of which */
+	/* blocks we actually need and which ones we don't.               */
+	metablocks_gfs1 = 0;
+
+	for (h = 0; h < height1; h++) {
+		head = &blocks[h]->list;
+		for (tmp = head->next; tmp != head; tmp = tmp->next) {
+			blk = osi_list_entry(tmp, struct blocklist, list);
+			bh = bget(&sbp->buf_list, blk->dblock);
+			head_size2 = sizeof(struct gfs2_meta_header);
+			memset(bh->b_data + head_size2, 0,
+			       sbp->bsize - head_size2);
+			bh->b_changed = not_updated; /* not used--yet */
+			metablocks_gfs1++;
+			brelse(bh, not_updated); /* not used--yet */
+		}
+	}
+
+	/* zero the dinode's pointers too */
+	head_size2 = sizeof(struct gfs2_dinode);
+	memset(dibh->b_data + sizeof(struct gfs2_dinode), 0,
+	       sbp->bsize - head_size2);
+
+	/* The gfs2 height may be different */
+	gfs2_height = calc_gfs2_tree_height(ip, ip->i_di.di_size);
+
+	/* Now run through the data block list and reformat the blocks.      */
+	/* We want to reuse the same metadata blocks from the list we built. */
+	head = &blocks[gfs2_height]->list; /* highest height:data blocks */
+
+	for (tmp = head->next; tmp != head; tmp = tmp->next) {
+		struct metapath2 mp2; /* metapath in gfs2 terms */
+		struct metapath *mp1;  /* metapath in gfs1 terms */
+
+		blk = osi_list_entry(tmp, struct blocklist, list);
+		block = blk->dblock;
+
+		/* recalculate the metapath */
+		mp1 = find_metapath(ip, blk->lblock);
+		/* figure out the block number from the start of the file. */
+		b = blk->lblock;
+		/* Calculate the metapath in GFS2 terms */
+		memset(&mp2, 0, sizeof(mp2));
+		for (h = gfs2_height; h--;)
+			mp2.mp_list[h] = do_div(b, gfs2_inptrs);
+		for (h = gfs2_height - 1; h >= 0; h--) {
+			if (h) {
+				/* find/reuse a bh from the old metadata. */
+				mp2.mp_bh[h] = find_lbh(sbp, blocks[h],
+							mp2.mp_list[h - 1]);
+			} else {
+				mp2.mp_bh[h] = dibh;
+			}
+			head_size2 = (h > 0 ? sizeof(struct gfs2_meta_header) :
+				      sizeof(struct gfs2_dinode));
+			ptr2 = (uint64_t *)(mp2.mp_bh[h]->b_data + head_size2);
+			ptr2 += mp2.mp_list[h];
+			*ptr2 = cpu_to_be64(block);
+			block = mp2.mp_bh[h]->b_blocknr;
+			if (h)
+				brelse(mp2.mp_bh[h], updated); /* used */
+		}
+		free(mp1);
+	} /* for all data blocks */
+
+	/* Release all the buffers we were using. */
+	/* We need to count the number of blocks we really used in the new */
+	/* metadata along the way. */
+	metablocks_gfs2 = 1; /* 1 for the inode that we know will change */
+	for (h = 1; h < height1; h++){
+		cur_list = &metalist[h];
+		for (tmp = cur_list->next; tmp != cur_list; tmp = tmp->next){
+			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
+					    b_altlist);
+			if (bh->b_changed)     /* if we changed the block */
+				metablocks_gfs2++; /* count it */
+			else                   /* if we didn't change it */
+				gfs2_free_block(sbp, bh->b_blocknr); /* free */
+			brelse(bh, updated);
+		}
+	}
+	/* Set the new dinode height, which may or may not have changed.  */
+	/* The caller will take it from the ip and write it to the buffer */
+	ip->i_di.di_height = gfs2_height;
+	ip->i_di.di_blocks -= (metablocks_gfs1 - metablocks_gfs2);
+
+out:
+	for (h = 0; h <= height1; h++) {
+		head = &blocks[h]->list;
+		tmp = head->next;
+		while (tmp != head) {
+			blk = osi_list_entry(tmp, struct blocklist, list);
+			tmp = tmp->next;
+			free(blk);
+		}
+		if (blocks[h])
+			free(blocks[h]);
+	}
+	return error;
+}
+
+/* ------------------------------------------------------------------------- */
 /* adjust_inode - change an inode from gfs1 to gfs2                          */
 /*                                                                           */
 /* Returns: 0 on success, -1 on failure                                      */
@@ -265,7 +604,7 @@ int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 	struct inode_block *fixdir;
 	int inode_was_gfs1;
 
-	inode = inode_get(sbp, bh);
+	inode = gfs_inode_get(sbp, bh);
 
 	inode_was_gfs1 = (inode->i_di.di_num.no_formal_ino ==
 					  inode->i_di.di_num.no_addr);
@@ -324,13 +663,15 @@ int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 	/*       don't want to shift the data around.                  */
 	/* ----------------------------------------------------------- */
 	if (inode_was_gfs1) {
-		struct gfs1_dinode *gfs1_dinode_struct;
+		struct gfs_dinode *gfs1_dinode_struct;
 
-		gfs1_dinode_struct = (struct gfs1_dinode *)&inode->i_di;
+		gfs1_dinode_struct = (struct gfs_dinode *)&inode->i_di;
 		inode->i_di.di_goal_meta = inode->i_di.di_goal_data;
 		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))
+			return -1;
 	}
 	
 	gfs2_dinode_out(&inode->i_di, bh->b_data);
@@ -354,6 +695,7 @@ int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 	struct gfs2_buffer_head *bh;
 	int first;
 	int error = 0;
+	int rgs_processed = 0;
 
 	log_notice("Converting inodes.\n");
 	sbp->md.next_inum = 1; /* starting inode numbering */
@@ -364,6 +706,7 @@ int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 	/* Traverse the resource groups to figure out where the inodes are. */
 	/* ---------------------------------------------------------------- */
 	osi_list_foreach(tmp, &sbp->rglist) {
+		rgs_processed++;
 		rgd = osi_list_entry(tmp, struct rgrp_list, list);
 		first = 1;
 		if (gfs2_rgrp_read(sbp, rgd)) {
@@ -376,8 +719,9 @@ int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 			/* doesn't think we hung.  (This may take a long time).       */
 			if (tv.tv_sec - seconds) {
 				seconds = tv.tv_sec;
-				log_notice("\r%" PRIu64" inodes converted.",
-						   sbp->md.next_inum);
+				log_notice("\r%" PRIu64" inodes from %d rgs "
+					   "converted.", sbp->md.next_inum,
+					   rgs_processed);
 				fflush(stdout);
 			}
 			/* Get the next metadata block.  Break out if we reach the end. */
@@ -392,7 +736,7 @@ int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 				sbp->sd_sb.sb_root_dir.no_addr = block;
 				sbp->sd_sb.sb_root_dir.no_formal_ino = sbp->md.next_inum;
 			}
-			bh = bread(sbp, block);
+			bh = bread(&sbp->buf_list, block);
 			if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) /* if it is an dinode */
 				error = adjust_inode(sbp, bh);
 			else { /* It's metadata, but not an inode, so fix the bitmap. */
@@ -425,7 +769,8 @@ int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr)
 		} /* while 1 */
 		gfs2_rgrp_relse(rgd, updated);
 	} /* for all rgs */
-	log_notice("\r%" PRIu64" inodes converted.", sbp->md.next_inum);
+	log_notice("\r%" PRIu64" inodes from %d rgs converted.",
+		   sbp->md.next_inum, rgs_processed);
 	fflush(stdout);
 	return 0;
 }/* inode_renumber */
@@ -439,7 +784,7 @@ int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
 	struct gfs2_buffer_head *bh_fix;
 	struct gfs2_inode *fix_inode;
 
-	bh_fix = bread(sbp, iblock);
+	bh_fix = bread(&sbp->buf_list, iblock);
 	fix_inode = inode_get(sbp, bh_fix);
 	inum->no_formal_ino = fix_inode->i_di.di_num.no_formal_ino;
 	inum->no_addr = fix_inode->i_di.di_num.no_addr;
@@ -603,6 +948,7 @@ int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dirs_to_fix)
 	gettimeofday(&tv, NULL);
 	seconds = tv.tv_sec;
 	log_notice("\nFixing file and directory information.\n");
+	fflush(stdout);
 	offset = 0;
 	tmp = NULL;
 	/* for every directory in the list */
@@ -617,7 +963,7 @@ int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dirs_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, dirblock);
+		bh_dir = bread(&sbp->buf_list, dirblock);
 		dip = inode_get(sbp, bh_dir);
 		/* fix the directory: either exhash (leaves) or linear (stuffed) */
 		if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
@@ -695,6 +1041,7 @@ int read_gfs1_jiindex(struct gfs2_sbd *sdp)
 		}
 		journ = sd_jindex + j;
 		gfs1_jindex_in(journ, buf);
+		sdp->jsize = (journ->ji_nsegment * 16 * sdp->bsize) >> 20;
 	}
 	if(j * sizeof(struct gfs1_jindex) != ip->i_di.di_size){
 		log_crit("journal inode size invalid\n");
@@ -715,7 +1062,7 @@ int read_gfs1_jiindex(struct gfs2_sbd *sdp)
 static int init(struct gfs2_sbd *sbp)
 {
 	struct gfs2_buffer_head *bh;
-	int rgcount, i;
+	int rgcount;
 	struct gfs2_inum inum;
 
 	memset(sbp, 0, sizeof(struct gfs2_sbd));
@@ -745,16 +1092,39 @@ static int init(struct gfs2_sbd *sbp)
 	sbp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
 	sbp->bsize = sbp->sd_sb.sb_bsize;
 	osi_list_init(&sbp->rglist);
-	osi_list_init(&sbp->buf_list);
-	for(i = 0; i < BUF_HASH_SIZE; i++)
-		osi_list_init(&sbp->buf_hash[i]);
+	init_buf_list(sbp, &sbp->buf_list, 128 << 20);
+	init_buf_list(sbp, &sbp->nvbuf_list, 0xffffffff);
 	compute_constants(sbp);
 
-	bh = bread(sbp, GFS2_SB_ADDR >> sbp->sd_fsb2bb_shift);
+	bh = bread(&sbp->buf_list, GFS2_SB_ADDR >> sbp->sd_fsb2bb_shift);
 	memcpy(&raw_gfs1_ondisk_sb, (struct gfs1_sb *)bh->b_data,
 		   sizeof(struct gfs1_sb));
 	gfs2_sb_in(&sbp->sd_sb, bh->b_data);
+	sbp->bsize = sbp->sd_sb.sb_bsize;
+	sbp->sd_inptrs = (sbp->bsize - sizeof(struct gfs_indirect)) /
+		sizeof(uint64_t);
+	sbp->sd_diptrs = (sbp->bsize - sizeof(struct gfs_dinode)) /
+		sizeof(uint64_t);
+	sbp->sd_jbsize = sbp->bsize - sizeof(struct gfs2_meta_header);
 	brelse(bh, not_updated);
+	sbp->sd_max_height = compute_heightsize(sbp, sbp->sd_heightsize,
+						sbp->sd_diptrs,
+						sbp->sd_inptrs);
+	sbp->sd_max_jheight = compute_heightsize(sbp, sbp->sd_jheightsize,
+						sbp->sd_diptrs,
+						sbp->sd_inptrs);
+	/* -------------------------------------------------------- */
+	/* Our constants are for gfs1.  Need some for gfs2 as well. */
+	/* -------------------------------------------------------- */
+	gfs2_inptrs = (sbp->bsize - sizeof(struct gfs2_meta_header)) /
+                sizeof(uint64_t); /* How many ptrs can we fit on a block? */
+	memset(gfs2_heightsize, 0, sizeof(gfs2_heightsize));
+	gfs2_max_height = compute_heightsize(sbp, gfs2_heightsize,
+					     sbp->sd_diptrs, gfs2_inptrs);
+	memset(gfs2_jheightsize, 0, sizeof(gfs2_jheightsize));
+	gfs2_max_jheight = compute_heightsize(sbp, gfs2_jheightsize,
+					      sbp->sd_diptrs, gfs2_inptrs);
+
 	/* ---------------------------------------------- */
 	/* Make sure we're really gfs1                    */
 	/* ---------------------------------------------- */
@@ -769,7 +1139,8 @@ 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);
-	sbp->md.riinode = gfs2_load_inode(sbp, inum.no_addr);
+	bh = bread(&sbp->buf_list, inum.no_addr);
+	sbp->md.riinode = gfs_inode_get(sbp, bh);
 	/* 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);
@@ -783,11 +1154,14 @@ static int init(struct gfs2_sbd *sbp)
 	/* so that it adjusts for the metaheader by faking out the inode to  */
 	/* look like a directory, temporarily.                               */
 	sbp->md.riinode->i_di.di_mode &= ~S_IFMT;
-	sbp->md.riinode->i_di.di_mode |= S_IFDIR; 
-	if (ri_update(sbp, 0, &rgcount)){
+	sbp->md.riinode->i_di.di_mode |= S_IFDIR;
+	printf("Examining file system");
+	if (gfs1_ri_update(sbp, 0, &rgcount)){
 		log_crit("Unable to fill in resource group information.\n");
 		return -1;
 	}
+	printf("\n");
+	fflush(stdout);
 	inode_put(sbp->md.riinode, updated);
 	inode_put(sbp->md.jiinode, updated);
 	log_debug("%d rgs found.\n", rgcount);
@@ -988,7 +1362,7 @@ int journ_space_to_rg(struct gfs2_sbd *sdp)
 			rgd->ri.ri_data--;
 		rgd->rg.rg_free = rgd->ri.ri_data;
 		rgd->ri.ri_bitbytes = rgd->ri.ri_data / GFS2_NBBY;
-		convert_bitmaps(sdp, rgd, FALSE); /* allocates rgd2->bh */
+		convert_bitmaps(sdp, rgd, FALSE); /* allocates rgd->bh */
 		for (x = 0; x < rgd->ri.ri_length; x++) {
 			if (x)
 				gfs2_meta_header_out(&mh, rgd->bh[x]->b_data);
@@ -1046,7 +1420,7 @@ void remove_obsolete_gfs1(struct gfs2_sbd *sbp)
 {
 	struct gfs2_inum inum;
 
-	log_notice("Removing obsolete gfs1 structures.\n");
+	log_notice("Removing obsolete GFS1 file system structures.\n");
 	fflush(stdout);
 	/* Delete the old gfs1 Journal index: */
 	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_jindex_di);
@@ -1066,6 +1440,40 @@ void remove_obsolete_gfs1(struct gfs2_sbd *sbp)
 }
 
 /* ------------------------------------------------------------------------- */
+/* lifted from libgfs2/structures.c                                          */
+/* ------------------------------------------------------------------------- */
+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);
+
+	for (j = 0; j < sdp->md.journals; j++) {
+		char name[256];
+		struct gfs2_inode *ip;
+
+		printf("Writing journal #%d...", j + 1);
+		fflush(stdout);
+		sprintf(name, "journal%u", j);
+		ip = createi(jindex, name, S_IFREG | 0600, GFS2_DIF_SYSTEM);
+		write_journal(sdp, ip, j,
+			      sdp->jsize << 20 >> sdp->sd_sb.sb_bsize_shift);
+		inode_put(ip, updated);
+		printf("done.\n");
+		fflush(stdout);
+	}
+
+	if (sdp->debug) {
+		printf("\nJindex:\n");
+		gfs2_dinode_print(&jindex->i_di);
+	}
+
+	inode_put(jindex, updated);
+}
+
+/* ------------------------------------------------------------------------- */
 /* main - mainline code                                                      */
 /* ------------------------------------------------------------------------- */
 int main(int argc, char **argv)
@@ -1097,12 +1505,14 @@ int main(int argc, char **argv)
 	/* Convert incore gfs1 sb to gfs2 sb              */
 	/* ---------------------------------------------- */
 	if (!error) {
-		log_notice("Converting resource groups.\n");
+		log_notice("Converting resource groups.");
+		fflush(stdout);
 		error = convert_rgs(&sb2);
+		log_notice("\n");
 		if (error)
 			log_crit("%s: Unable to convert resource groups.\n",
 					device);
-		bcommit(&sb2); /* write the buffers to disk */
+		bcommit(&sb2.nvbuf_list); /* write the buffers to disk */
 	}
 	/* ---------------------------------------------- */
 	/* Renumber the inodes consecutively.             */
@@ -1111,7 +1521,7 @@ int main(int argc, char **argv)
 		error = inode_renumber(&sb2, sb2.sd_sb.sb_root_dir.no_addr);
 		if (error)
 			log_crit("\n%s: Error renumbering inodes.\n", device);
-		bcommit(&sb2); /* write the buffers to disk */
+		bcommit(&sb2.buf_list); /* write the buffers to disk */
 	}
 	/* ---------------------------------------------- */
 	/* Fix the directories to match the new numbers.  */
@@ -1132,19 +1542,21 @@ int main(int argc, char **argv)
 		error = journ_space_to_rg(&sb2);
 		if (error)
 			log_crit("%s: Error converting journal space.\n", device);
-		bcommit(&sb2); /* write the buffers to disk */
+		bcommit(&sb2.buf_list); /* write the buffers to disk */
 	}
 	/* ---------------------------------------------- */
 	/* Create our system files and directories.       */
 	/* ---------------------------------------------- */
 	if (!error) {
-		log_notice("Building system structures.\n");
+		/* Now we've got to treat it as a gfs2 file system */
+		compute_constants(&sb2);
 		/* Build the master subdirectory. */
 		build_master(&sb2); /* Does not do inode_put */
 		sb2.sd_sb.sb_master_dir = sb2.master_dir->i_di.di_num;
 		/* Build empty journal index file. */
-		build_jindex(&sb2);
-		/* Build out per-node directories */
+		conv_build_jindex(&sb2);
+		log_notice("Building GFS2 file system structures.\n");
+		/* Build the per-node directories */
 		build_per_node(&sb2);
 		/* Create the empty inode number file */
 		build_inum(&sb2); /* Does not do inode_put */
@@ -1163,7 +1575,8 @@ int main(int argc, char **argv)
 		inode_put(sb2.md.inum, updated);
 		inode_put(sb2.md.statfs, updated);
 
-		bcommit(&sb2); /* write the buffers to disk */
+		bcommit(&sb2.buf_list); /* write the buffers to disk */
+		bcommit(&sb2.nvbuf_list); /* write the buffers to disk */
 
 		/* Now delete the now-obsolete gfs1 files: */
 		remove_obsolete_gfs1(&sb2);
@@ -1175,13 +1588,14 @@ int main(int argc, char **argv)
 		/* end because if the tool is interrupted in the middle, we want */
 		/* it to not reject the partially converted fs as already done   */
 		/* when it's run a second time.                                  */
-		bh = bread(&sb2, sb2.sb_addr);
+		bh = bread(&sb2.buf_list, sb2.sb_addr);
 		sb2.sd_sb.sb_fs_format = GFS2_FORMAT_FS;
 		sb2.sd_sb.sb_multihost_format = GFS2_FORMAT_MULTI;
 		gfs2_sb_out(&sb2.sd_sb, bh->b_data);
 		brelse(bh, updated);
 
-		bsync(&sb2); /* write the buffers to disk */
+		bsync(&sb2.buf_list); /* write the buffers to disk */
+		bsync(&sb2.nvbuf_list); /* write the buffers to disk */
 		error = fsync(sb2.device_fd);
 		if (error)
 			perror(device);
diff --git a/gfs2/edit/gfs2hex.c b/gfs2/edit/gfs2hex.c
index c9950be..a63c421 100644
--- a/gfs2/edit/gfs2hex.c
+++ b/gfs2/edit/gfs2hex.c
@@ -257,7 +257,7 @@ void do_dinode_extended(struct gfs2_dinode *di, char *buf)
 
 				if (last >= max_block)
 					break;
-				tmp_bh = bread(&sbd, last);
+				tmp_bh = bread(&sbd.buf_list, last);
 				gfs2_leaf_in(&leaf, tmp_bh->b_data);
 				indirect->ii[indirect_blocks].dirents = 0;
 				for (direntcount = 0, bufoffset = sizeof(struct gfs2_leaf);
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index 9b001d9..099d66e 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -627,7 +627,7 @@ void rgcount(void)
 		block = sbd1->sb_rindex_di.no_addr;
 	else
 		block = masterblock("rindex");
-	ribh = bread(&sbd, block);
+	ribh = bread(&sbd.buf_list, block);
 	riinode = inode_get(&sbd, ribh);
 	printf("%lld RGs in this file system.\n",
 	       (unsigned long long)riinode->i_di.di_size / risize());
@@ -696,37 +696,6 @@ void gfs_rgrp_out(struct gfs_rgrp *rgrp, char *buf)
 }
 
 /* ------------------------------------------------------------------------ */
-/* gfs_dinode_in */
-/* ------------------------------------------------------------------------ */
-void gfs_dinode_in(struct gfs_dinode *di, char *buf)
-{
-	struct gfs_dinode *str = (struct gfs_dinode *)buf;
-
-	gfs2_meta_header_in(&di->di_header, buf);
-	gfs2_inum_in(&di->di_num, (char *)&str->di_num);
-
-	di->di_mode = be32_to_cpu(str->di_mode);
-	di->di_uid = be32_to_cpu(str->di_uid);
-	di->di_gid = be32_to_cpu(str->di_gid);
-	di->di_nlink = be32_to_cpu(str->di_nlink);
-	di->di_size = be64_to_cpu(str->di_size);
-	di->di_blocks = be64_to_cpu(str->di_blocks);
-	di->di_atime = be64_to_cpu(str->di_atime);
-	di->di_mtime = be64_to_cpu(str->di_mtime);
-	di->di_ctime = be64_to_cpu(str->di_ctime);
-	di->di_major = be32_to_cpu(str->di_major);
-	di->di_minor = be32_to_cpu(str->di_minor);
-	di->di_goal_dblk = be64_to_cpu(str->di_goal_dblk);
-	di->di_goal_mblk = be64_to_cpu(str->di_goal_mblk);
-	di->di_flags = be32_to_cpu(str->di_flags);
-	di->di_payload_format = be32_to_cpu(str->di_payload_format);
-	di->di_height = be16_to_cpu(str->di_height);
-	di->di_depth = be16_to_cpu(str->di_depth);
-	di->di_entries = be32_to_cpu(str->di_entries);
-	di->di_eattr = be64_to_cpu(str->di_eattr);
-}
-
-/* ------------------------------------------------------------------------ */
 /* gfs_rgrp_print - print a gfs1 resource group                             */
 /* ------------------------------------------------------------------------ */
 void gfs_rgrp_print(struct gfs_rgrp *rg)
@@ -754,7 +723,7 @@ uint64_t get_rg_addr(int rgnum)
 		block = sbd1->sb_rindex_di.no_addr;
 	else
 		block = masterblock("rindex");
-	bh = bread(&sbd, block);
+	bh = bread(&sbd.buf_list, block);
 	riinode = inode_get(&sbd, bh);
 	if (rgnum < riinode->i_di.di_size / risize())
 		rgblk = find_rgrp_block(riinode, rgnum);
@@ -782,7 +751,7 @@ void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full)
 	uint64_t rgblk;
 
 	rgblk = get_rg_addr(rgnum);
-	bh = bread(&sbd, rgblk);
+	bh = bread(&sbd.buf_list, rgblk);
 	if (gfs1)
 		gfs_rgrp_in(&rg.rg1, bh->b_data);
 	else
@@ -814,7 +783,7 @@ void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full)
 		brelse(bh, not_updated);
 	}
 	if (modify)
-		bsync(&sbd);
+		bsync(&sbd.buf_list);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -877,7 +846,7 @@ int parse_rindex(struct gfs2_inode *di, int print_rindex)
 			else {
 				struct gfs2_buffer_head *tmp_bh;
 
-				tmp_bh = bread(&sbd, ri.ri_addr);
+				tmp_bh = bread(&sbd.nvbuf_list, ri.ri_addr);
 				if (gfs1) {
 					struct gfs_rgrp rg1;
 					gfs_rgrp_in(&rg1, tmp_bh->b_data);
@@ -1418,7 +1387,7 @@ int display_extended(void)
 
 	/* Display any indirect pointers that we have. */
 	if (block_is_rindex()) {
-		tmp_bh = bread(&sbd, block);
+		tmp_bh = bread(&sbd.buf_list, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		parse_rindex(tmp_inode, TRUE);
 		brelse(tmp_bh, not_updated);
@@ -1430,33 +1399,34 @@ int display_extended(void)
 		return -1;
 	else if (block_is_rglist()) {
 		if (gfs1)
-			tmp_bh = bread(&sbd, sbd1->sb_rindex_di.no_addr);
+			tmp_bh = bread(&sbd.buf_list,
+				       sbd1->sb_rindex_di.no_addr);
 		else
-			tmp_bh = bread(&sbd, masterblock("rindex"));
+			tmp_bh = bread(&sbd.buf_list, masterblock("rindex"));
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		parse_rindex(tmp_inode, FALSE);
 		brelse(tmp_bh, not_updated);
 	}
 	else if (block_is_jindex()) {
-		tmp_bh = bread(&sbd, block);
+		tmp_bh = bread(&sbd.buf_list, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_jindex(tmp_inode);
 		brelse(tmp_bh, not_updated);
 	}
 	else if (block_is_inum_file()) {
-		tmp_bh = bread(&sbd, block);
+		tmp_bh = bread(&sbd.buf_list, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_inum(tmp_inode);
 		brelse(tmp_bh, not_updated);
 	}
 	else if (block_is_statfs_file()) {
-		tmp_bh = bread(&sbd, block);
+		tmp_bh = bread(&sbd.buf_list, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_statfs(tmp_inode);
 		brelse(tmp_bh, not_updated);
 	}
 	else if (block_is_quota_file()) {
-		tmp_bh = bread(&sbd, block);
+		tmp_bh = bread(&sbd.buf_list, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_quota(tmp_inode);
 		brelse(tmp_bh, not_updated);
@@ -1469,8 +1439,6 @@ int display_extended(void)
 /* ------------------------------------------------------------------------ */
 void read_superblock(int fd)
 {
-	int x;
-
 	sbd1 = (struct gfs_sb *)&sbd.sd_sb;
 	ioctl(fd, BLKFLSBUF, 0);
 	do_lseek(fd, 0x10 * 4096);
@@ -1484,9 +1452,8 @@ void read_superblock(int fd)
 	sbd.qcsize = GFS2_DEFAULT_QCSIZE;
 	sbd.time = time(NULL);
 	osi_list_init(&sbd.rglist);
-	osi_list_init(&sbd.buf_list);
-	for (x = 0; x < BUF_HASH_SIZE; x++)
-		osi_list_init(&sbd.buf_hash[x]);
+	init_buf_list(&sbd, &sbd.buf_list, 128 << 20);
+	init_buf_list(&sbd, &sbd.nvbuf_list, 0xffffffff);
 	compute_constants(&sbd);
 	gfs2_sb_in(&sbd.sd_sb, buf); /* parse it out into the sb structure */
 	/* Check to see if this is really gfs1 */
@@ -1680,7 +1647,7 @@ uint64_t find_journal_block(const char *journal, uint64_t *j_size)
 	else
 		jindex_block = masterblock("jindex");
 	/* read in the block */
-	jindex_bh = bread(&sbd, jindex_block);
+	jindex_bh = bread(&sbd.buf_list, jindex_block);
 	/* get the dinode data from it. */
 	gfs2_dinode_in(&di, jindex_bh->b_data); /* parse disk inode to struct*/
 
@@ -1705,7 +1672,7 @@ uint64_t find_journal_block(const char *journal, uint64_t *j_size)
 		struct gfs2_dinode jdi;
 
 		jblock = indirect->ii[0].dirent[journal_num + 2].block;
-		j_bh = bread(&sbd, jblock);
+		j_bh = bread(&sbd.buf_list, jblock);
 		j_inode = inode_get(&sbd, j_bh);
 		gfs2_dinode_in(&jdi, j_bh->b_data);/* parse dinode to struct */
 		*j_size = jdi.di_size;
@@ -2345,7 +2312,7 @@ int fsck_readi(struct gfs2_inode *ip, void *buf, uint64_t offset,
 			block_map(ip, lblock, &not_new, &dblock, &extlen,
 				  FALSE, not_updated);
 		if (dblock) {
-			bh = bread(sdp, dblock);
+			bh = bread(&sdp->buf_list, dblock);
 			if (*abs_block == 0)
 				*abs_block = bh->b_blocknr;
 			dblock++;
@@ -2403,7 +2370,7 @@ void dump_journal(const char *journal)
 	if (!jblock)
 		return;
 	if (!gfs1) {
-		j_bh = bread(&sbd, jblock);
+		j_bh = bread(&sbd.buf_list, jblock);
 		j_inode = inode_get(&sbd, j_bh);
 	}
 
@@ -2411,7 +2378,7 @@ void dump_journal(const char *journal)
 		if (gfs1) {
 			if (j_bh)
 				brelse(j_bh, not_updated);
-			j_bh = bread(&sbd, jblock + jb);
+			j_bh = bread(&sbd.buf_list, jblock + jb);
 			abs_block = jblock + jb;
 			memcpy(jbuf, j_bh->b_data, sbd.bsize);
 		} else {
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index 98a0a7b..a3c0830 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -8,6 +8,7 @@
 #include <linux/gfs2_ondisk.h>
 #include <string.h>
 
+#include "libgfs2.h"
 #include "copyright.cf"
 
 #ifndef TRUE
@@ -156,52 +157,6 @@ struct gfs_rgrp {
 	char rg_reserved[64];
 };
 
-struct gfs_dinode {
-	struct gfs2_meta_header di_header;
-
-	struct gfs2_inum di_num; /* formal inode # and block address */
-
-	uint32_t di_mode;	/* mode of file */
-	uint32_t di_uid;	/* owner's user id */
-	uint32_t di_gid;	/* owner's group id */
-	uint32_t di_nlink;	/* number (qty) of links to this file */
-	uint64_t di_size;	/* number (qty) of bytes in file */
-	uint64_t di_blocks;	/* number (qty) of blocks in file */
-	int64_t di_atime;	/* time last accessed */
-	int64_t di_mtime;	/* time last modified */
-	int64_t di_ctime;	/* time last changed */
-
-	/*  Non-zero only for character or block device nodes  */
-	uint32_t di_major;	/* device major number */
-	uint32_t di_minor;	/* device minor number */
-
-	/*  Block allocation strategy  */
-	uint64_t di_rgrp;	/* dinode rgrp block number */
-	uint64_t di_goal_rgrp;	/* rgrp to alloc from next */
-	uint32_t di_goal_dblk;	/* data block goal */
-	uint32_t di_goal_mblk;	/* metadata block goal */
-
-	uint32_t di_flags;	/* GFS_DIF_... */
-
-	/*  struct gfs_rindex, struct gfs_jindex, or struct gfs_dirent */
-	uint32_t di_payload_format;  /* GFS_FORMAT_... */
-	uint16_t di_type;	/* GFS_FILE_... type of file */
-	uint16_t di_height;	/* height of metadata (0 == stuffed) */
-	uint32_t di_incarn;	/* incarnation (unused, see gfs_meta_header) */
-	uint16_t di_pad;
-
-	/*  These only apply to directories  */
-	uint16_t di_depth;	/* Number of bits in the table */
-	uint32_t di_entries;	/* The # (qty) of entries in the directory */
-
-	/*  This formed an on-disk chain of unused dinodes  */
-	struct gfs2_inum di_next_unused;  /* used in old versions only */
-
-	uint64_t di_eattr;	/* extended attribute block number */
-
-	char di_reserved[56];
-};
-
 EXTERN int block_is_jindex(void);
 EXTERN int block_is_rindex(void);
 EXTERN int block_is_inum_file(void);
@@ -230,12 +185,6 @@ struct iinfo {
 	struct indirect_info ii[512];
 };
 
-struct gfs_indirect {
-	struct gfs2_meta_header in_header;
-
-	char in_reserved[64];
-};
-
 struct blkstack_info {
 	uint64_t block;
 	int start_row[DMODES];
@@ -247,10 +196,6 @@ struct blkstack_info {
 	int gfs2_struct_type;
 };
 
-struct metapath {
-	uint64_t mp_list[GFS2_MAX_META_HEIGHT];
-};
-
 struct gfs_sb {
 	/*  Order is important; need to be able to read old superblocks
 	    in order to support on-disk version upgrades */
diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c
index 3845993..8b7637b 100644
--- a/gfs2/edit/savemeta.c
+++ b/gfs2/edit/savemeta.c
@@ -43,326 +43,6 @@ int journals_found = 0;
 extern void read_superblock(void);
 uint64_t masterblock(const char *fn);
 
-static __inline__ int fs_is_jdata(struct gfs2_inode *ip)
-{
-        return ip->i_di.di_flags & GFS2_DIF_JDATA;
-}
-
-static struct metapath *find_metapath(struct gfs2_inode *ip, uint64_t block)
-{
-	struct gfs2_sbd *sdp = ip->i_sbd;
-	struct metapath *mp;
-	uint64_t b = block;
-	unsigned int i;
-
-	zalloc(mp, sizeof(struct metapath));
-
-	for (i = ip->i_di.di_height; i--;)
-		mp->mp_list[i] = do_div(b, sdp->sd_inptrs);
-
-	return mp;
-}
-
-static __inline__ uint64_t *
-metapointer(struct gfs2_buffer_head *bh, unsigned int height,
-			struct metapath *mp)
-{
-	unsigned int head_size = (height > 0) ?
-		sizeof(struct gfs_indirect) : sizeof(struct gfs_dinode);
-
-	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
-}
-
-static void lookup_block(struct gfs2_inode *ip,
-	     struct gfs2_buffer_head *bh, unsigned int height, struct metapath *mp,
-	     int create, int *new, uint64_t *block)
-{
-	uint64_t *ptr = metapointer(bh, height, mp);
-
-	if (*ptr) {
-		*block = be64_to_cpu(*ptr);
-		return;
-	}
-
-	*block = 0;
-
-	if (!create)
-		return;
-
-	if (height == ip->i_di.di_height - 1&&
-	    !(S_ISDIR(ip->i_di.di_mode)))
-		*block = data_alloc(ip);
-	else
-		*block = meta_alloc(ip);
-
-	*ptr = cpu_to_be64(*block);
-	ip->i_di.di_blocks++;
-
-	*new = 1;
-}
-
-void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
-		    uint64_t *dblock, uint32_t *extlen, int prealloc)
-{
-	struct gfs2_sbd *sdp = ip->i_sbd;
-	struct gfs2_buffer_head *bh;
-	struct metapath *mp;
-	int create = *new;
-	unsigned int bsize;
-	unsigned int height;
-	unsigned int end_of_metadata;
-	unsigned int x;
-	enum update_flags f;
-
-	f = not_updated;
-	*new = 0;
-	*dblock = 0;
-	if (extlen)
-		*extlen = 0;
-
-	if (!ip->i_di.di_height) { /* stuffed */
-		if (!lblock) {
-			*dblock = ip->i_di.di_num.no_addr;
-			if (extlen)
-				*extlen = 1;
-		}
-		return;
-	}
-
-	bsize = (fs_is_jdata(ip)) ? sdp->sd_jbsize : sdp->bsize;
-
-	height = calc_tree_height(ip, (lblock + 1) * bsize);
-	if (ip->i_di.di_height < height) {
-		if (!create)
-			return;
-
-		build_height(ip, height);
-	}
-
-	mp = find_metapath(ip, lblock);
-	end_of_metadata = ip->i_di.di_height - 1;
-
-	bh = bhold(ip->i_bh);
-
-	for (x = 0; x < end_of_metadata; x++) {
-		lookup_block(ip, bh, x, mp, create, new, dblock);
-		brelse(bh, not_updated);
-		if (!*dblock)
-			goto out;
-
-		if (*new) {
-			struct gfs2_meta_header mh;
-
-			bh = bget(sdp, *dblock);
-			mh.mh_magic = GFS2_MAGIC;
-			mh.mh_type = GFS2_METATYPE_IN;
-			mh.mh_format = GFS2_FORMAT_IN;
-			gfs2_meta_header_out(&mh, bh->b_data);
-			f = updated;
-		} else
-			bh = bread(sdp, *dblock);
-	}
-
-	if (!prealloc)
-		lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock);
-
-	if (extlen && *dblock) {
-		*extlen = 1;
-
-		if (!*new) {
-			uint64_t tmp_dblock;
-			int tmp_new;
-			unsigned int nptrs;
-
-			nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
-
-			while (++mp->mp_list[end_of_metadata] < nptrs) {
-				lookup_block(ip, bh, end_of_metadata, mp, FALSE, &tmp_new,
-							 &tmp_dblock);
-
-				if (*dblock + *extlen != tmp_dblock)
-					break;
-
-				(*extlen)++;
-			}
-		}
-	}
-
-	brelse(bh, f);
-
- out:
-	free(mp);
-}
-
-int gfs1_readi(struct gfs2_inode *ip, void *buf,
-	       uint64_t offset, unsigned int size)
-{
-	struct gfs2_sbd *sdp = ip->i_sbd;
-	struct gfs2_buffer_head *bh;
-	uint64_t lblock, dblock = 0;
-	uint32_t extlen = 0;
-	unsigned int amount;
-	int not_new = 0;
-	int journaled = fs_is_jdata(ip);
-	int copied = 0;
-
-	if (offset >= ip->i_di.di_size)
-		return 0;
-
-	if ((offset + size) > ip->i_di.di_size)
-		size = ip->i_di.di_size - offset;
-
-	if (!size)
-		return 0;
-
-	if (journaled) {
-		lblock = offset / sdp->sd_jbsize;
-		offset %= sdp->sd_jbsize;
-	} else {
-		lblock = offset >> sdp->sd_sb.sb_bsize_shift;
-		offset &= sdp->sd_sb.sb_bsize - 1;
-	}
-
-	if (!ip->i_di.di_height) /* stuffed */
-		offset += sizeof(struct gfs_dinode);
-	else if (journaled)
-		offset += sizeof(struct gfs2_meta_header);
-
-	while (copied < size) {
-		amount = size - copied;
-		if (amount > sdp->bsize - offset)
-			amount = sdp->bsize - offset;
-
-		if (!extlen)
-			gfs1_block_map(ip, lblock, &not_new, &dblock,
-				       &extlen, FALSE);
-
-		if (dblock) {
-			bh = bread(sdp, dblock);
-			dblock++;
-			extlen--;
-		} else
-			bh = NULL;
-
-
-		if (bh) {
-			memcpy(buf+copied, bh->b_data + offset, amount);
-			brelse(bh, not_updated);
-		} else
-			memset(buf+copied, 0, amount);
-		copied += amount;
-		lblock++;
-
-		offset = (journaled) ? sizeof(struct gfs2_meta_header) : 0;
-	}
-
-	return copied;
-}
-
-/**
- * gfs1_rindex_read - read in the rg index file
- *                  Stolen from libgfs2/super.c, but modified to handle gfs1.
- * @sdp: the incore superblock pointer
- * fd: optional file handle for rindex file (if meta_fs file system is mounted)
- *     (if fd is <= zero, it will read from raw device)
- * @count1: return count of the rgs.
- *
- * Returns: 0 on success, -1 on failure
- */
-int gfs1_rindex_read(struct gfs2_sbd *sdp, int fd, int *count1)
-{
-	unsigned int rg;
-	int error;
-	struct gfs2_rindex buf;
-	struct rgrp_list *rgd, *prev_rgd;
-	uint64_t prev_length = 0;
-
-	*count1 = 0;
-	prev_rgd = NULL;
-	for (rg = 0; ; rg++) {
-		if (fd > 0)
-			error = read(fd, &buf, sizeof(struct gfs2_rindex));
-		else
-			error = gfs1_readi(sdp->md.riinode, (char *)&buf,
-					   (rg * sizeof(struct gfs2_rindex)),
-					   sizeof(struct gfs2_rindex));
-		if (!error)
-			break;
-		if (error != sizeof(struct gfs2_rindex))
-			return -1;
-
-		rgd = (struct rgrp_list *)malloc(sizeof(struct rgrp_list));
-		// FIXME: handle failed malloc
-		memset(rgd, 0, sizeof(struct rgrp_list));
-		osi_list_add_prev(&rgd->list, &sdp->rglist);
-
-		gfs2_rindex_in(&rgd->ri, (char *)&buf);
-
-		rgd->start = rgd->ri.ri_addr;
-		if (prev_rgd) {
-			prev_length = rgd->start - prev_rgd->start;
-			prev_rgd->length = prev_length;
-		}
-
-		if(gfs2_compute_bitstructs(sdp, rgd))
-			return -1;
-
-		(*count1)++;
-		prev_rgd = rgd;
-	}
-	if (prev_rgd)
-		prev_rgd->length = prev_length;
-	return 0;
-}
-
-/**
- * gfs1_ri_update - attach rgrps to the super block
- *                  Stolen from libgfs2/super.c, but modified to handle gfs1.
- * @sdp:
- *
- * Given the rgrp index inode, link in all rgrps into the super block
- * and be sure that they can be read.
- *
- * Returns: 0 on success, -1 on failure.
- */
-int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount)
-{
-	struct rgrp_list *rgd;
-	osi_list_t *tmp;
-	int count1 = 0, count2 = 0;
-	uint64_t errblock = 0;
-
-	if (gfs1_rindex_read(sdp, fd, &count1))
-	    goto fail;
-	for (tmp = sdp->rglist.next; tmp != &sdp->rglist; tmp = tmp->next) {
-		enum update_flags f;
-
-		f = not_updated;
-		rgd = osi_list_entry(tmp, struct rgrp_list, list);
-		errblock = gfs2_rgrp_read(sdp, rgd);
-		if (errblock)
-			return errblock;
-		else
-			gfs2_rgrp_relse(rgd, f);
-		count2++;
-		if (count2 % 100 == 0) {
-			printf(".");
-			fflush(stdout);
-		}
-	}
-
-	*rgcount = count1;
-	if (count1 != count2)
-		goto fail;
-
-	return 0;
-
- fail:
-	gfs2_rgrp_free(&sdp->rglist, not_updated);
-	return -1;
-}
-
-
 /*
  * get_gfs_struct_info - get block type and structure length
  *
@@ -562,7 +242,7 @@ void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 		old_block = indir_block;
 		save_block(sbd.device_fd, out_fd, indir_block);
 		if (height != hgt) { /* If not at max height */
-			nbh = bread(&sbd, indir_block);
+			nbh = bread(&sbd.buf_list, indir_block);
 			osi_list_add_prev(&nbh->b_altlist,
 					  cur_list);
 			brelse(nbh, not_updated);
@@ -570,42 +250,6 @@ void save_indirect_blocks(int out_fd, osi_list_t *cur_list,
 	} /* for all data on the indirect block */
 }
 
-struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
-				 struct gfs2_buffer_head *bh)
-{
-	struct gfs_dinode gfs1_dinode;
-	struct gfs2_inode *ip;
-
-	zalloc(ip, sizeof(struct gfs2_inode));
-	gfs_dinode_in(&gfs1_dinode, bh->b_data);
-	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.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_bh = bh;
-	ip->i_sbd = sdp;
-	return ip;
-}
-
 /*
  * save_inode_data - save off important data associated with an inode
  *
@@ -632,7 +276,7 @@ void save_inode_data(int out_fd)
 
 	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
 		osi_list_init(&metalist[i]);
-	metabh = bread(&sbd, block);
+	metabh = bread(&sbd.buf_list, block);
 	if (gfs1)
 		inode = inode_get(&sbd, metabh);
 	else
@@ -677,7 +321,7 @@ void save_inode_data(int out_fd)
 		struct gfs2_meta_header mh;
 		int e;
 
-		metabh = bread(&sbd, inode->i_di.di_eattr);
+		metabh = bread(&sbd.buf_list, inode->i_di.di_eattr);
 		save_block(sbd.device_fd, out_fd, inode->i_di.di_eattr);
 		gfs2_meta_header_in(&mh, metabh->b_data);
 		if (mh.mh_magic == GFS2_MAGIC) {
@@ -737,7 +381,7 @@ void get_journal_inode_blocks(void)
 			struct gfs_jindex ji;
 			char jbuf[sizeof(struct gfs_jindex)];
 
-			bh = bread(&sbd, sbd1->sb_jindex_di.no_addr);
+			bh = bread(&sbd.buf_list, sbd1->sb_jindex_di.no_addr);
 			j_inode = gfs_inode_get(&sbd, bh);
 			amt = gfs2_readi(j_inode, (void *)&jbuf,
 					 journal * sizeof(struct gfs_jindex),
@@ -752,7 +396,7 @@ 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, jblock);
+			bh = bread(&sbd.buf_list, jblock);
 			j_inode = inode_get(&sbd, bh);
 			gfs2_dinode_in(&jdi, bh->b_data);
 			inode_put(j_inode, not_updated);
@@ -796,14 +440,11 @@ void savemeta(char *out_fn, int saveoption)
 	if (!gfs1)
 		sbd.bsize = BUFSIZE;
 	if (!slow) {
-		int i;
-
 		device_geometry(&sbd);
 		fix_device_geometry(&sbd);
 		osi_list_init(&sbd.rglist);
-		osi_list_init(&sbd.buf_list);
-		for(i = 0; i < BUF_HASH_SIZE; i++)
-			osi_list_init(&sbd.buf_hash[i]);
+		init_buf_list(&sbd, &sbd.buf_list, 128 << 20);
+		init_buf_list(&sbd, &sbd.nvbuf_list, 0xffffffff);
 		if (!gfs1)
 			sbd.sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
 		compute_constants(&sbd);
@@ -846,7 +487,7 @@ void savemeta(char *out_fn, int saveoption)
 					    &sbd.md.riinode);
 			jindex_block = masterblock("jindex");
 		}
-		bh = bread(&sbd, jindex_block);
+		bh = bread(&sbd.buf_list, jindex_block);
 		gfs2_dinode_in(&di, bh->b_data);
 		if (!gfs1)
 			do_dinode_extended(&di, bh->b_data);
diff --git a/gfs2/fsck/fs_recovery.c b/gfs2/fsck/fs_recovery.c
index 9d95328..06e71bf 100644
--- a/gfs2/fsck/fs_recovery.c
+++ b/gfs2/fsck/fs_recovery.c
@@ -119,7 +119,7 @@ static int buf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
 		if (error)
 			return error;
 
-		bh_ip = bget(sdp, blkno);
+		bh_ip = bget(&sdp->buf_list, blkno);
 		memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
 
 		check_magic = ((struct gfs2_meta_header *)
@@ -218,7 +218,7 @@ static int databuf_lo_scan_elements(struct gfs2_inode *ip, unsigned int start,
 		if (error)
 			return error;
 
-		bh_ip = bget(sdp, blkno);
+		bh_ip = bget(&sdp->buf_list, blkno);
 		memcpy(bh_ip->b_data, bh_log->b_data, sdp->bsize);
 
 		/* Unescape */
@@ -422,6 +422,7 @@ int replay_journals(struct gfs2_sbd *sdp){
 	inode_put(sdp->master_dir, not_updated);
 	inode_put(sdp->md.jiinode, not_updated);
 	/* Sync the buffers to disk so we get a fresh start. */
-	bsync(sdp);
+	bsync(&sdp->buf_list);
+	bsync(&sdp->nvbuf_list);
 	return 0;
 }
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index bb395cb..83f5d4c 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -296,11 +296,11 @@ static int fill_super_block(struct gfs2_sbd *sdp)
 	 ********************************************************************/
 	log_info("Initializing lists...\n");
 	osi_list_init(&sdp->rglist);
-	osi_list_init(&sdp->buf_list);
+	init_buf_list(sdp, &sdp->buf_list, 128 << 20);
+	init_buf_list(sdp, &sdp->nvbuf_list, 0xffffffff);
 	for(i = 0; i < BUF_HASH_SIZE; i++) {
 		osi_list_init(&dir_hash[i]);
 		osi_list_init(&inode_hash[i]);
-		osi_list_init(&sdp->buf_hash[i]);
 	}
 
 	/********************************************************************
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 141fdf3..17c9772 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -371,7 +371,8 @@ int main(int argc, char **argv)
 
 	if (!opts.no)
 		log_notice("Writing changes to disk\n");
-	bsync(sbp);
+	bsync(&sbp->buf_list);
+	bsync(&sbp->nvbuf_list);
 	destroy(sbp);
 	log_notice("gfs2_fsck complete    \n");
 
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 24b7fc3..9915d8d 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -312,7 +312,7 @@ int check_leaf(struct gfs2_inode *ip, enum update_flags *update,
 				{
 					int factor = 0, divisor = ref_count;
 
-					lbh = bread(sbp, old_leaf);
+					lbh = bread(&sbp->buf_list, old_leaf);
 					while (divisor > 1) {
 						factor++;
 						divisor /= 2;
@@ -347,7 +347,7 @@ int check_leaf(struct gfs2_inode *ip, enum update_flags *update,
 
 			*update = not_updated;
 			/* Try to read in the leaf block. */
-			lbh = bread(sbp, leaf_no);
+			lbh = bread(&sbp->buf_list, leaf_no);
 			/* Make sure it's really a valid leaf block. */
 			if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) {
 				warn_and_patch(ip, &leaf_no, &bad_leaf,
@@ -414,7 +414,7 @@ int check_leaf(struct gfs2_inode *ip, enum update_flags *update,
 				if(update && (count != leaf.lf_entries)) {
 					enum update_flags f = not_updated;
 
-					lbh = bread(sbp, leaf_no);
+					lbh = bread(&sbp->buf_list, leaf_no);
 					gfs2_leaf_in(&leaf, lbh->b_data);
 
 					log_err("Leaf %"PRIu64" (0x%" PRIx64
@@ -681,7 +681,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
 	uint64_t *ptr, block;
 	int err;
 
-	metabh = bread(ip->i_sbd, ip->i_di.di_num.no_addr);
+	metabh = bread(&ip->i_sbd->buf_list, ip->i_di.di_num.no_addr);
 
 	osi_list_add(&metabh->b_altlist, &mlp[0]);
 
@@ -724,7 +724,8 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
 					continue;
 				}
 				if(!nbh)
-					nbh = bread(ip->i_sbd, block);
+					nbh = bread(&ip->i_sbd->buf_list,
+						    block);
 
 				osi_list_add(&nbh->b_altlist, cur_list);
 			} /* for all data on the indirect block */
@@ -857,7 +858,7 @@ int check_dir(struct gfs2_sbd *sbp, uint64_t block, struct metawalk_fxns *pass)
 	enum update_flags update = not_updated;
 	int error = 0;
 
-	bh = bread(sbp, block);
+	bh = bread(&sbp->buf_list, block);
 	ip = fsck_inode_get(sbp, bh);
 
 	if(ip->i_di.di_flags & GFS2_DIF_EXHASH) {
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 32f05f3..a33ad16 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -107,7 +107,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
 		gfs2_block_mark(ip->i_sbd, bl, block, gfs2_dup_block);
 		found_dup = 1;
 	}
-	nbh = bread(ip->i_sbd, block);
+	nbh = bread(&ip->i_sbd->buf_list, block);
 
 	if (gfs2_check_meta(nbh, GFS2_METATYPE_IN)){
 		log_debug("Bad indirect block pointer "
@@ -233,7 +233,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
 	   check if it really is an EA.  If it is, let duplicate
 	   handling sort it out.  If it isn't, clear it but don't
 	   count it as a duplicate. */
-	*bh = bread(sdp, indirect);
+	*bh = bread(&sdp->buf_list, indirect);
 	if(gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
 		if(q.block_type != gfs2_block_free) { /* Duplicate? */
 			if (!clear_eas(ip, bc, indirect, 1, want_updated,
@@ -321,7 +321,7 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
 		stack;
 		return -1;
 	}
-	el_buf = bread(sdp, el_blk);
+	el_buf = bread(&sdp->buf_list, el_blk);
 
 	/* Special duplicate processing:  If we have an EA block,
 	   check if it really is an EA.  If it is, let duplicate
@@ -390,7 +390,7 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 		   check if it really is an EA.  If it is, let duplicate
 		   handling sort it out.  If it isn't, clear it but don't
 		   count it as a duplicate. */
-		leaf_bh = bread(sdp, block);
+		leaf_bh = bread(&sdp->buf_list, block);
 		if(gfs2_check_meta(leaf_bh, GFS2_METATYPE_EA)) {
 			if(q.block_type != gfs2_block_free) { /* Duplicate? */
 				clear_eas(ip, bc, block, 1, want_updated,
@@ -886,7 +886,7 @@ int pass1(struct gfs2_sbd *sbp)
 				skip_this_pass = FALSE;
 				fflush(stdout);
 			}
-			bh = bread(sbp, block);
+			bh = bread(&sbp->buf_list, block);
 
 			if (scan_meta(sbp, bh, block)) {
 				stack;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 60ccf39..88306ad 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -72,7 +72,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 
 	*want_updated = not_updated;
 	inc_if_found(block, 0, private);
-	indir_bh = bread(sbp, block);
+	indir_bh = bread(&sbp->buf_list, block);
 	*bh = indir_bh;
 
 	return 0;
@@ -87,7 +87,7 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 
 	*want_updated = not_updated;
 	inc_if_found(block, 0, private);
-	leaf_bh = bread(sbp, block);
+	leaf_bh = bread(&sbp->buf_list, block);
 
 	*bh = leaf_bh;
 	return 0;
diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c
index ec097ad..fa0e0db 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -62,7 +62,7 @@ int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 		return 1;
 	}
 	else
-		indir_bh = bread(sbp, block);
+		indir_bh = bread(&sbp->buf_list, block);
 
 	*bh = indir_bh;
 	return 0;
@@ -97,7 +97,7 @@ int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 		return 1;
 	}
 	else 
-		*bh = bread(sbp, block);
+		*bh = bread(&sbp->buf_list, block);
 
 	return 0;
 }
@@ -243,7 +243,7 @@ int pass1c(struct gfs2_sbd *sbp)
 
 		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
 			return 0;
-		bh = bread(sbp, block_no);
+		bh = bread(&sbp->buf_list, block_no);
 		if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) { /* if a dinode */
 			log_info("EA in inode %"PRIu64" (0x%" PRIx64 ")\n",
 				 block_no, block_no);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 9e17758..3d29f88 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -78,7 +78,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
 			     enum update_flags *want_updated, void *private)
 {
 	*want_updated = not_updated;
-	*bh = bread(ip->i_sbd, block);
+	*bh = bread(&ip->i_sbd->buf_list, block);
 	return 0;
 }
 static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
@@ -86,7 +86,7 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
 			    enum update_flags *want_updated, void *private)
 {
 	*want_updated = not_updated;
-	*bh = bread(ip->i_sbd, block);
+	*bh = bread(&ip->i_sbd->buf_list, block);
 	return 0;
 }
 
@@ -727,7 +727,7 @@ int pass2(struct gfs2_sbd *sbp)
 			}
 			gfs2_block_set(sbp, bl, i, gfs2_meta_inval);
 		}
-		bh = bread(sbp, i);
+		bh = bread(&sbp->buf_list, i);
 		ip = fsck_inode_get(sbp, bh);
 		if(!ds.dotdir) {
 			log_err("No '.' entry found\n");
@@ -753,7 +753,7 @@ int pass2(struct gfs2_sbd *sbp)
 		}
 		fsck_inode_put(ip, not_updated); /* does a brelse */
 
-		bh = bread(sbp, i);
+		bh = bread(&sbp->buf_list, i);
 		ip = fsck_inode_get(sbp, bh);
 		if(ip->i_di.di_entries != ds.entry_count) {
 			log_err("Entries is %d - should be %d for inode block %" PRIu64
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index b02066a..fce2f17 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -53,7 +53,7 @@ void find_journaled_rgs(struct gfs2_sbd *sdp)
 				  not_updated);
 			if (!dblock)
 				break;
-			bh = bread(sdp, dblock);
+			bh = bread(&sdp->buf_list, dblock);
 			if (!gfs2_check_meta(bh, GFS2_METATYPE_RG)) {
 				log_debug("False RG found at block "
 					  "0x%" PRIx64 "\n", dblock);
@@ -127,7 +127,7 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 	for (blk = sdp->sb_addr + 1;
 	     blk < sdp->device.length && number_of_rgs < 6;
 	     blk++) {
-		bh = bread(sdp, blk);
+		bh = bread(&sdp->nvbuf_list, blk);
 		if (((blk == sdp->sb_addr + 1) ||
 		    (!gfs2_check_meta(bh, GFS2_METATYPE_RG))) &&
 		    !is_false_rg(blk)) {
@@ -204,7 +204,7 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 	for (blk = sdp->sb_addr + 1; blk <= sdp->device.length;
 	     blk += block_bump) {
 		log_debug("Block 0x%" PRIx64 "\n", blk);
-		bh = bread(sdp, blk);
+		bh = bread(&sdp->nvbuf_list, blk);
 		rg_was_fnd = (!gfs2_check_meta(bh, GFS2_METATYPE_RG));
 		brelse(bh, not_updated);
 		/* Allocate a new RG and index. */
@@ -238,7 +238,7 @@ int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, osi_list_t *ret_list,
 		for (fwd_block = blk + 1;
 		     fwd_block < sdp->device.length; 
 		     fwd_block++) {
-			bh = bread(sdp, fwd_block);
+			bh = bread(&sdp->nvbuf_list, fwd_block);
 			bitmap_was_fnd =
 				(!gfs2_check_meta(bh, GFS2_METATYPE_RB));
 			brelse(bh, not_updated);
@@ -375,7 +375,7 @@ int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_list *rg,
 	if (query(&opts, "Fix the RG? (y/n)")) {
 
 		log_err("Attempting to repair the RG.\n");
-		rg->bh[x] = bread(sdp, rg->ri.ri_addr + x);
+		rg->bh[x] = bread(&sdp->nvbuf_list, rg->ri.ri_addr + x);
 		if (x) {
 			struct gfs2_meta_header mh;
 
diff --git a/gfs2/libgfs2/Makefile b/gfs2/libgfs2/Makefile
index 14f7551..c327aef 100644
--- a/gfs2/libgfs2/Makefile
+++ b/gfs2/libgfs2/Makefile
@@ -9,6 +9,7 @@ OBJS=	bitmap.o \
 	fs_bits.o \
 	fs_geometry.o \
 	fs_ops.o \
+	gfs1.o \
 	locking.o \
 	gfs2_log.o \
 	misc.o \
diff --git a/gfs2/libgfs2/buf.c b/gfs2/libgfs2/buf.c
index e3c437b..710ded0 100644
--- a/gfs2/libgfs2/buf.c
+++ b/gfs2/libgfs2/buf.c
@@ -13,17 +13,19 @@
 #include "libgfs2.h"
 
 static __inline__ osi_list_t *
-blkno2head(struct gfs2_sbd *sdp, uint64_t blkno)
+blkno2head(struct buf_list *bl, uint64_t blkno)
 {
-	return sdp->buf_hash +
+	return bl->buf_hash +
 		(gfs2_disk_hash((char *)&blkno, sizeof(uint64_t)) & BUF_HASH_MASK);
 }
 
-void write_buffer(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
+static void write_buffer(struct buf_list *bl, struct gfs2_buffer_head *bh)
 {
+	struct gfs2_sbd *sdp = bl->sbp;
+
 	osi_list_del(&bh->b_list);
 	osi_list_del(&bh->b_hash);
-	sdp->num_bufs--;
+	bl->num_bufs--;
 	if (bh->b_changed) {
 		do_lseek(sdp->device_fd, bh->b_blocknr * sdp->bsize);
 		do_write(sdp->device_fd, bh->b_data, sdp->bsize);
@@ -32,31 +34,49 @@ void write_buffer(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
 	free(bh);
 }
 
+void init_buf_list(struct gfs2_sbd *sdp, struct buf_list *bl, uint32_t limit)
+{
+	int i;
+
+	bl->num_bufs = 0;
+	bl->spills = 0;
+	bl->limit = limit;
+	bl->sbp = sdp;
+	osi_list_init(&bl->list);
+	for(i = 0; i < BUF_HASH_SIZE; i++)
+		osi_list_init(&bl->buf_hash[i]);
+}
+
 static void
-add_buffer(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
+add_buffer(struct buf_list *bl, struct gfs2_buffer_head *bh)
 {
-	osi_list_t *head = blkno2head(sdp, bh->b_blocknr);
+	osi_list_t *head = blkno2head(bl, bh->b_blocknr);
 
-	osi_list_add(&bh->b_list, &sdp->buf_list);
+	osi_list_add(&bh->b_list, &bl->list);
 	osi_list_add(&bh->b_hash, head);
-	sdp->num_bufs++;
-
-	while (sdp->num_bufs * sdp->bsize > 128 << 20) {
-		bh = osi_list_entry(sdp->buf_list.prev, struct gfs2_buffer_head,
-							b_list);
-		if (bh->b_count) {
-			osi_list_del(&bh->b_list);
-			osi_list_add(&bh->b_list, &sdp->buf_list);
-			continue;
+	bl->num_bufs++;
+
+	if (bl->num_bufs * bl->sbp->bsize > bl->limit) {
+		int found = 0;
+		osi_list_t *tmp, *x;
+
+		osi_list_foreach_safe(tmp, &bl->list, x) {
+			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
+					    b_list);
+			if (!bh->b_count) {
+				write_buffer(bl, bh);
+				found++;
+				if (found >= 10)
+					break;
+			}
 		}
-		write_buffer(sdp, bh);
-		sdp->spills++;
-	} 
+		bl->spills++;
+	}
 }
 
-struct gfs2_buffer_head *bfind(struct gfs2_sbd *sdp, uint64_t num)
+struct gfs2_buffer_head *bfind(struct buf_list *bl, uint64_t num)
 {
-	osi_list_t *head = blkno2head(sdp, num);
+	osi_list_t *head = blkno2head(bl, num);
 	osi_list_t *tmp;
 	struct gfs2_buffer_head *bh;
 
@@ -64,7 +84,7 @@ struct gfs2_buffer_head *bfind(struct gfs2_sbd *sdp, uint64_t num)
 		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_hash);
 		if (bh->b_blocknr == num) {
 			osi_list_del(&bh->b_list);
-			osi_list_add(&bh->b_list, &sdp->buf_list);
+			osi_list_add(&bh->b_list, &bl->list);
 			osi_list_del(&bh->b_hash);
 			osi_list_add(&bh->b_hash, head);
 			bh->b_count++;
@@ -75,13 +95,14 @@ struct gfs2_buffer_head *bfind(struct gfs2_sbd *sdp, uint64_t num)
 	return NULL;
 }
 
-struct gfs2_buffer_head *bget_generic(struct gfs2_sbd *sdp, uint64_t num,
-									  int find_existing, int read_disk)
+struct gfs2_buffer_head *bget_generic(struct buf_list *bl, uint64_t num,
+				      int find_existing, int read_disk)
 {
 	struct gfs2_buffer_head *bh;
+	struct gfs2_sbd *sdp = bl->sbp;
 
 	if (find_existing) {
-		bh = bfind(sdp, num);
+		bh = bfind(bl, num);
 		if (bh)
 			return bh;
 	}
@@ -94,25 +115,25 @@ struct gfs2_buffer_head *bget_generic(struct gfs2_sbd *sdp, uint64_t num,
 		do_lseek(sdp->device_fd, num * sdp->bsize);
 		do_read(sdp->device_fd, bh->b_data, sdp->bsize);
 	}
-	add_buffer(sdp, bh);
+	add_buffer(bl, bh);
 	bh->b_changed = FALSE;
 
 	return bh;
 }
 
-struct gfs2_buffer_head *bget(struct gfs2_sbd *sdp, uint64_t num)
+struct gfs2_buffer_head *bget(struct buf_list *bl, uint64_t num)
 {
-	return bget_generic(sdp, num, TRUE, FALSE);
+	return bget_generic(bl, num, TRUE, FALSE);
 }
 
-struct gfs2_buffer_head *bread(struct gfs2_sbd *sdp, uint64_t num)
+struct gfs2_buffer_head *bread(struct buf_list *bl, uint64_t num)
 {
-	return bget_generic(sdp, num, TRUE, TRUE);
+	return bget_generic(bl, num, TRUE, TRUE);
 }
 
-struct gfs2_buffer_head *bget_zero(struct gfs2_sbd *sdp, uint64_t num)
+struct gfs2_buffer_head *bget_zero(struct buf_list *bl, uint64_t num)
 {
-	return bget_generic(sdp, num, FALSE, FALSE);
+	return bget_generic(bl, num, FALSE, FALSE);
 }
 
 struct gfs2_buffer_head *bhold(struct gfs2_buffer_head *bh)
@@ -136,33 +157,34 @@ void brelse(struct gfs2_buffer_head *bh, enum update_flags updated)
 	bh->b_count--;
 }
 
-void bsync(struct gfs2_sbd *sdp)
+void bsync(struct buf_list *bl)
 {
 	struct gfs2_buffer_head *bh;
 
-	while (!osi_list_empty(&sdp->buf_list)) {
-		bh = osi_list_entry(sdp->buf_list.prev, struct gfs2_buffer_head,
+	while (!osi_list_empty(&bl->list)) {
+		bh = osi_list_entry(bl->list.prev, struct gfs2_buffer_head,
 							b_list);
 		if (bh->b_count)
 			die("buffer still held for block: %" PRIu64 " (0x%" PRIx64")\n",
 				bh->b_blocknr, bh->b_blocknr);
-		write_buffer(sdp, bh);
+		write_buffer(bl, bh);
 	}
 }
 
 /* commit buffers to disk but do not discard */
-void bcommit(struct gfs2_sbd *sdp)
+void bcommit(struct buf_list *bl)
 {
 	osi_list_t *tmp, *x;
 	struct gfs2_buffer_head *bh;
+	struct gfs2_sbd *sdp = bl->sbp;
 
-	osi_list_foreach_safe(tmp, &sdp->buf_list, x) {
+	osi_list_foreach_safe(tmp, &bl->list, x) {
 		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_list);
 		if (!bh->b_count)             /* if not reserved for later */
-			write_buffer(sdp, bh);    /* write the data, free the memory */
+			write_buffer(bl, bh);/* write the data & free memory */
 		else if (bh->b_changed) {     /* if buffer has changed */
 			do_lseek(sdp->device_fd, bh->b_blocknr * sdp->bsize);
-			do_write(sdp->device_fd, bh->b_data, sdp->bsize); /* write it out */
+			do_write(sdp->device_fd, bh->b_data, sdp->bsize);
 			bh->b_changed = FALSE;    /* no longer changed */
 		}
 	}
@@ -170,12 +192,12 @@ void bcommit(struct gfs2_sbd *sdp)
 }
 
 /* Check for unreleased buffers */
-void bcheck(struct gfs2_sbd *sdp)
+void bcheck(struct buf_list *bl)
 {
 	osi_list_t *tmp;
 	struct gfs2_buffer_head *bh;
 
-	osi_list_foreach(tmp, &sdp->buf_list) {
+	osi_list_foreach(tmp, &bl->list) {
 		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_list);
 		if (bh->b_count)
 			die("buffer still held: %"PRIu64"\n", bh->b_blocknr);
diff --git a/gfs2/libgfs2/fs_geometry.c b/gfs2/libgfs2/fs_geometry.c
index e4428b5..f8a2695 100644
--- a/gfs2/libgfs2/fs_geometry.c
+++ b/gfs2/libgfs2/fs_geometry.c
@@ -213,7 +213,7 @@ void build_rgrps(struct gfs2_sbd *sdp, int write)
 
 		if (write) {
 			for (x = 0; x < bitblocks; x++) {
-				bh = bget(sdp, rl->start + x);
+				bh = bget(&sdp->nvbuf_list, rl->start + x);
 				if (x)
 					gfs2_meta_header_out(&mh, bh->b_data);
 				else
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 4b45b06..6285b7f 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -62,7 +62,7 @@ uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type)
 	rg = &rl->rg;
 
 	for (block = 0; block < ri->ri_length; block++) {
-		bh = bread(sdp, ri->ri_addr + block);
+		bh = bread(&sdp->nvbuf_list, ri->ri_addr + block);
 		x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
 
 		for (; x < sdp->bsize; x++)
@@ -104,7 +104,7 @@ uint64_t blk_alloc_i(struct gfs2_sbd *sdp, unsigned int type)
 
 	brelse(bh, updated);
 
-	bh = bread(sdp, ri->ri_addr);
+	bh = bread(&sdp->nvbuf_list, ri->ri_addr);
 	gfs2_rgrp_out(rg, bh->b_data);
 	brelse(bh, updated);
 
@@ -162,7 +162,7 @@ static void unstuff_dinode(struct gfs2_inode *ip)
 	if (ip->i_di.di_size) {
 		if (isdir) {
 			block = meta_alloc(ip);
-			bh = bget(sdp, block);
+			bh = bget(&sdp->buf_list, block);
 			{
 				struct gfs2_meta_header mh;
 				mh.mh_magic = GFS2_MAGIC;
@@ -178,7 +178,7 @@ static void unstuff_dinode(struct gfs2_inode *ip)
 			brelse(bh, updated);
 		} else {
 			block = data_alloc(ip);
-			bh = bget(sdp, block);
+			bh = bget(&sdp->buf_list, block);
 
 			buffer_copy_tail(sdp, bh, 0,
 					 ip->i_bh, sizeof(struct gfs2_dinode));
@@ -240,7 +240,7 @@ void build_height(struct gfs2_inode *ip, int height)
 
 		if (new_block) {
 			block = meta_alloc(ip);
-			bh = bget(sdp, block);
+			bh = bget(&sdp->buf_list, block);
 			{
 				struct gfs2_meta_header mh;
 				mh.mh_magic = GFS2_MAGIC;
@@ -266,11 +266,7 @@ void build_height(struct gfs2_inode *ip, int height)
 	}
 }
 
-struct metapath {
-	unsigned int mp_list[GFS2_MAX_META_HEIGHT];
-};
-
-static struct metapath *find_metapath(struct gfs2_inode *ip, uint64_t block)
+struct metapath *find_metapath(struct gfs2_inode *ip, uint64_t block)
 {
 	struct gfs2_sbd *sdp = ip->i_sbd;
 	struct metapath *mp;
@@ -285,16 +281,6 @@ static struct metapath *find_metapath(struct gfs2_inode *ip, uint64_t block)
 	return mp;
 }
 
-static __inline__ uint64_t *
-metapointer(struct gfs2_buffer_head *bh, unsigned int height,
-			struct metapath *mp)
-{
-	unsigned int head_size = (height > 0) ?
-		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
-
-	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
-}
-
 static void lookup_block(struct gfs2_inode *ip,
 	     struct gfs2_buffer_head *bh, unsigned int height, struct metapath *mp,
 	     int create, int *new, uint64_t *block)
@@ -373,13 +359,13 @@ void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 
 		if (*new) {
 			struct gfs2_meta_header mh;
-			bh = bget(sdp, *dblock);
+			bh = bget(&sdp->buf_list, *dblock);
 			mh.mh_magic = GFS2_MAGIC;
 			mh.mh_type = GFS2_METATYPE_IN;
 			mh.mh_format = GFS2_FORMAT_IN;
 			gfs2_meta_header_out(&mh, bh->b_data);
 		} else
-			bh = bread(sdp, *dblock);
+			bh = bread(&sdp->buf_list, *dblock);
 	}
 
 	if (!prealloc)
@@ -472,7 +458,7 @@ int gfs2_readi(struct gfs2_inode *ip, void *buf,
 				  FALSE, not_updated);
 
 		if (dblock) {
-			bh = bread(sdp, dblock);
+			bh = bread(&sdp->buf_list, dblock);
 			dblock++;
 			extlen--;
 		} else
@@ -546,7 +532,7 @@ int gfs2_writei(struct gfs2_inode *ip, void *buf,
 		}
 
 		if (new) {
-			bh = bget(sdp, dblock);
+			bh = bget(&sdp->buf_list, dblock);
 			if (isdir) {
 				struct gfs2_meta_header mh;
 				mh.mh_magic = GFS2_MAGIC;
@@ -555,7 +541,7 @@ int gfs2_writei(struct gfs2_inode *ip, void *buf,
 				gfs2_meta_header_out(&mh, bh->b_data);
 			}
 		} else
-			bh = bread(sdp, dblock);
+			bh = bread(&sdp->buf_list, dblock);
 		copy_from_mem(bh, &buf, o, amount);
 		brelse(bh, updated);
 
@@ -592,9 +578,9 @@ struct gfs2_buffer_head *get_file_buf(struct gfs2_inode *ip, uint64_t lbn,
 		ip->i_di.di_size = (lbn + 1) << sdp->sd_sb.sb_bsize_shift;
 
 	if (new)
-		return bget(sdp, dbn);
+		return bget(&sdp->buf_list, dbn);
 	else
-		return bread(sdp, dbn);
+		return bread(&sdp->buf_list, dbn);
 }
 
 int gfs2_dirent_first(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
@@ -748,7 +734,7 @@ dir_split_leaf(struct gfs2_inode *dip, uint32_t index, uint64_t leaf_no)
 	int count;
 
 	bn = meta_alloc(dip);
-	nbh = bget(dip->i_sbd, bn);
+	nbh = bget(&dip->i_sbd->buf_list, bn);
 	{
 		struct gfs2_meta_header mh;
 		mh.mh_magic = GFS2_MAGIC;
@@ -760,7 +746,7 @@ dir_split_leaf(struct gfs2_inode *dip, uint32_t index, uint64_t leaf_no)
 	nleaf = (struct gfs2_leaf *)nbh->b_data;
 	nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
 
-	obh = bread(dip->i_sbd, leaf_no);
+	obh = bread(&dip->i_sbd->buf_list, leaf_no);
 	oleaf = (struct gfs2_leaf *)obh->b_data;
 
 	len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
@@ -891,7 +877,7 @@ int gfs2_get_leaf(struct gfs2_inode *dip, uint64_t leaf_no,
 {
 	int error = 0;
 
-	*bhp = bread(dip->i_sbd, leaf_no);
+	*bhp = bread(&dip->i_sbd->buf_list, leaf_no);
 	if (error)
 		return error;
 	error = gfs2_check_meta(*bhp, GFS2_METATYPE_LF);
@@ -915,7 +901,7 @@ static int get_first_leaf(struct gfs2_inode *dip, uint32_t index,
 	uint64_t leaf_no;
 
 	gfs2_get_leaf_nr(dip, index, &leaf_no);
-	*bh_out = bget(dip->i_sbd, leaf_no);
+	*bh_out = bget(&dip->i_sbd->buf_list, leaf_no);
 	return 0;
 }
 
@@ -937,7 +923,7 @@ static int get_next_leaf(struct gfs2_inode *dip,struct gfs2_buffer_head *bh_in,
 
 	if (!leaf->lf_next)
 		return -1;
-	*bh_out = bget(dip->i_sbd, be64_to_cpu(leaf->lf_next));
+	*bh_out = bget(&dip->i_sbd->buf_list, be64_to_cpu(leaf->lf_next));
 	return 0;
 }
 
@@ -963,7 +949,7 @@ dir_e_add(struct gfs2_inode *dip, char *filename, int len,
 	gfs2_get_leaf_nr(dip, index, &leaf_no);
 
 	for (;;) {
-		bh = bread(dip->i_sbd, leaf_no);
+		bh = bread(&dip->i_sbd->buf_list, leaf_no);
 		leaf = (struct gfs2_leaf *)bh->b_data;
 
 		if (dirent_alloc(dip, bh, len, &dent)) {
@@ -985,7 +971,7 @@ dir_e_add(struct gfs2_inode *dip, char *filename, int len,
 
 			} else {
 				bn = meta_alloc(dip);
-				nbh = bget(dip->i_sbd, bn);
+				nbh = bget(&dip->i_sbd->buf_list, bn);
 				{
 					struct gfs2_meta_header mh;
 					mh.mh_magic = GFS2_MAGIC;
@@ -1036,7 +1022,7 @@ dir_make_exhash(struct gfs2_inode *dip)
 	uint64_t *lp, bn;
 
 	bn = meta_alloc(dip);
-	bh = bget(sdp, bn);
+	bh = bget(&sdp->buf_list, bn);
 	{
 		struct gfs2_meta_header mh;
 		mh.mh_magic = GFS2_MAGIC;
@@ -1120,7 +1106,7 @@ init_dinode(struct gfs2_sbd *sdp, struct gfs2_inum *inum,
 	struct gfs2_buffer_head *bh;
 	struct gfs2_dinode di;
 
-	bh = bget(sdp, inum->no_addr);
+	bh = bget(&sdp->buf_list, inum->no_addr);
 
 	memset(&di, 0, sizeof(struct gfs2_dinode));
 	di.di_header.mh_magic = GFS2_MAGIC;
@@ -1388,7 +1374,7 @@ static int dir_l_search(struct gfs2_inode *dip, const char *filename,
 	if(!inode_is_stuffed(dip))
 		return -1;
 
-	dibh = bread(dip->i_sbd, dip->i_di.di_num.no_addr);
+	dibh = bread(&dip->i_sbd->buf_list, dip->i_di.di_num.no_addr);
 	error = leaf_search(dip, dibh, filename, len, &dent, NULL);
 	if (!error) {
 		gfs2_inum_in(inum, (char *)&dent->de_inum);
@@ -1443,7 +1429,7 @@ static int dir_e_del(struct gfs2_inode *dip, const char *filename, int len)
 		gfs2_get_leaf_nr(dip, index, &leaf_no);
 
 		while(leaf_no && !found){
-			bh = bget(dip->i_sbd, leaf_no);
+			bh = bget(&dip->i_sbd->buf_list, leaf_no);
 			error = leaf_search(dip, bh, filename, len, &cur, &prev);
 			if (error) {
 				if(error != -ENOENT){
@@ -1477,7 +1463,7 @@ static int dir_l_del(struct gfs2_inode *dip, struct gfs2_buffer_head *dibh,
 		return -1;
 
 	if(!dibh) {
-		dibh = bread(dip->i_sbd, dip->i_di.di_num.no_addr);
+		dibh = bread(&dip->i_sbd->buf_list, dip->i_di.di_num.no_addr);
 		if (error)
 			return -1;
 		got_buf = 1;
@@ -1561,6 +1547,23 @@ int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
 }
 
 /**
+ * gfs2_free_block - free up a block given its block number
+ */
+void gfs2_free_block(struct gfs2_sbd *sdp, uint64_t block)
+{
+	struct gfs2_buffer_head *bh;
+	struct rgrp_list *rgd;
+
+	gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
+	/* Adjust the free space count for the freed block */
+	rgd = gfs2_blk2rgrpd(sdp, block); /* find the rg for indir block */
+	bh = bget(&sdp->nvbuf_list, rgd->ri.ri_addr); /* get the rg buffer */
+	rgd->rg.rg_free++; /* adjust the free count */
+	gfs2_rgrp_out(&rgd->rg, bh->b_data); /* back to the buffer */
+	brelse(bh, updated); /* release the buffer */
+}
+
+/**
  * gfs2_freedi - unlink a disk inode by block number.
  * Note: currently only works for regular files.
  */
@@ -1573,7 +1576,7 @@ int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t block)
 	unsigned char *buf;
 	struct rgrp_list *rgd;
 	
-	bh = bread(sdp, block);
+	bh = bread(&sdp->buf_list, block);
 	ip = inode_get(sdp, bh);
 	if (ip->i_di.di_height > 0) {
 		buf = (unsigned char *)bh->b_data;
@@ -1581,16 +1584,8 @@ int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t block)
 		for (x = sizeof(struct gfs2_dinode); x < sdp->bsize;
 			 x += sizeof(uint64_t)) {
 			p = be64_to_cpu(*(uint64_t *)(buf + x));
-			if (p) {
-				gfs2_set_bitmap(sdp, p, GFS2_BLKST_FREE);
-				/* We need to adjust the free space count for the freed */
-                /* indirect block. */
-				rgd = gfs2_blk2rgrpd(sdp, p); /* find the rg for indir block */
-				bh = bget(sdp, rgd->ri.ri_addr); /* get the buffer its rg */
-				rgd->rg.rg_free++; /* adjust the free count */
-				gfs2_rgrp_out(&rgd->rg, bh->b_data); /* back to the buffer */
-				brelse(bh, updated); /* release the buffer */
-			}
+			if (p)
+				gfs2_free_block(sdp, p);
 		}
 	}
 	/* Set the bitmap type for inode to free space: */
@@ -1601,7 +1596,7 @@ int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t block)
 	/* The rg itself is in memory as rgd->rg, but there's most likely a  */
 	/* buffer in memory for the rg on disk because we used it to fix the */
 	/* bitmaps, some of which are on the same block on disk.             */
-	bh = bread(sdp, rgd->ri.ri_addr); /* get the buffer */
+	bh = bread(&sdp->nvbuf_list, rgd->ri.ri_addr); /* get the buffer */
 	rgd->rg.rg_free++;
 	rgd->rg.rg_dinodes--; /* one less inode in use */
 	gfs2_rgrp_out(&rgd->rg, bh->b_data);
diff --git a/gfs2/libgfs2/gfs1.c b/gfs2/libgfs2/gfs1.c
new file mode 100644
index 0000000..c518e5a
--- /dev/null
+++ b/gfs2/libgfs2/gfs1.c
@@ -0,0 +1,395 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <linux/gfs2_ondisk.h>
+
+#include "osi_list.h"
+#include "libgfs2.h"
+
+/* GFS1 compatibility functions - so that programs like gfs2_convert
+   and gfs2_edit can examine/manipulate GFS1 file systems. */
+
+static __inline__ int fs_is_jdata(struct gfs2_inode *ip)
+{
+        return ip->i_di.di_flags & GFS2_DIF_JDATA;
+}
+
+static __inline__ uint64_t *
+gfs1_metapointer(struct gfs2_buffer_head *bh, unsigned int height,
+		 struct metapath *mp)
+{
+	unsigned int head_size = (height > 0) ?
+		sizeof(struct gfs_indirect) : sizeof(struct gfs_dinode);
+
+	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
+}
+
+void gfs1_lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
+		  unsigned int height, struct metapath *mp,
+		  int create, int *new, uint64_t *block)
+{
+	uint64_t *ptr = gfs1_metapointer(bh, height, mp);
+
+	if (*ptr) {
+		*block = be64_to_cpu(*ptr);
+		return;
+	}
+
+	*block = 0;
+
+	if (!create)
+		return;
+
+	if (height == ip->i_di.di_height - 1&&
+	    !(S_ISDIR(ip->i_di.di_mode)))
+		*block = data_alloc(ip);
+	else
+		*block = meta_alloc(ip);
+
+	*ptr = cpu_to_be64(*block);
+	ip->i_di.di_blocks++;
+
+	*new = 1;
+}
+
+void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
+		    uint64_t *dblock, uint32_t *extlen, int prealloc)
+{
+	struct gfs2_sbd *sdp = ip->i_sbd;
+	struct gfs2_buffer_head *bh;
+	struct metapath *mp;
+	int create = *new;
+	unsigned int bsize;
+	unsigned int height;
+	unsigned int end_of_metadata;
+	unsigned int x;
+	enum update_flags f;
+
+	f = not_updated;
+	*new = 0;
+	*dblock = 0;
+	if (extlen)
+		*extlen = 0;
+
+	if (!ip->i_di.di_height) { /* stuffed */
+		if (!lblock) {
+			*dblock = ip->i_di.di_num.no_addr;
+			if (extlen)
+				*extlen = 1;
+		}
+		return;
+	}
+
+	bsize = (fs_is_jdata(ip)) ? sdp->sd_jbsize : sdp->bsize;
+
+	height = calc_tree_height(ip, (lblock + 1) * bsize);
+	if (ip->i_di.di_height < height) {
+		if (!create)
+			return;
+
+		build_height(ip, height);
+	}
+
+	mp = find_metapath(ip, lblock);
+	end_of_metadata = ip->i_di.di_height - 1;
+
+	bh = bhold(ip->i_bh);
+
+	for (x = 0; x < end_of_metadata; x++) {
+		gfs1_lookup_block(ip, bh, x, mp, create, new, dblock);
+		brelse(bh, f);
+		if (!*dblock)
+			goto out;
+
+		if (*new) {
+			struct gfs2_meta_header mh;
+
+			bh = bget(&sdp->buf_list, *dblock);
+			mh.mh_magic = GFS2_MAGIC;
+			mh.mh_type = GFS2_METATYPE_IN;
+			mh.mh_format = GFS2_FORMAT_IN;
+			gfs2_meta_header_out(&mh, bh->b_data);
+			f = updated;
+		} else {
+			bh = bread(&sdp->buf_list, *dblock);
+			f = not_updated;
+		}
+	}
+
+	if (!prealloc)
+		gfs1_lookup_block(ip, bh, end_of_metadata, mp, create, new,
+				  dblock);
+
+	if (extlen && *dblock) {
+		*extlen = 1;
+
+		if (!*new) {
+			uint64_t tmp_dblock;
+			int tmp_new;
+			unsigned int nptrs;
+
+			nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
+
+			while (++mp->mp_list[end_of_metadata] < nptrs) {
+				gfs1_lookup_block(ip, bh, end_of_metadata, mp,
+						  FALSE, &tmp_new,
+						  &tmp_dblock);
+
+				if (*dblock + *extlen != tmp_dblock)
+					break;
+
+				(*extlen)++;
+			}
+		}
+	}
+
+	brelse(bh, f);
+
+ out:
+	free(mp);
+}
+
+int gfs1_readi(struct gfs2_inode *ip, void *buf,
+	       uint64_t offset, unsigned int size)
+{
+	struct gfs2_sbd *sdp = ip->i_sbd;
+	struct gfs2_buffer_head *bh;
+	uint64_t lblock, dblock = 0;
+	uint32_t extlen = 0;
+	unsigned int amount;
+	int not_new = 0;
+	int journaled = fs_is_jdata(ip);
+	int copied = 0;
+
+	if (offset >= ip->i_di.di_size)
+		return 0;
+
+	if ((offset + size) > ip->i_di.di_size)
+		size = ip->i_di.di_size - offset;
+
+	if (!size)
+		return 0;
+
+	if (journaled) {
+		lblock = offset / sdp->sd_jbsize;
+		offset %= sdp->sd_jbsize;
+	} else {
+		lblock = offset >> sdp->sd_sb.sb_bsize_shift;
+		offset &= sdp->sd_sb.sb_bsize - 1;
+	}
+
+	if (!ip->i_di.di_height) /* stuffed */
+		offset += sizeof(struct gfs_dinode);
+	else if (journaled)
+		offset += sizeof(struct gfs2_meta_header);
+
+	while (copied < size) {
+		amount = size - copied;
+		if (amount > sdp->bsize - offset)
+			amount = sdp->bsize - offset;
+
+		if (!extlen)
+			gfs1_block_map(ip, lblock, &not_new, &dblock,
+				       &extlen, FALSE);
+
+		if (dblock) {
+			bh = bread(&sdp->buf_list, dblock);
+			dblock++;
+			extlen--;
+		} else
+			bh = NULL;
+
+
+		if (bh) {
+			memcpy(buf+copied, bh->b_data + offset, amount);
+			brelse(bh, not_updated);
+		} else
+			memset(buf+copied, 0, amount);
+		copied += amount;
+		lblock++;
+
+		offset = (journaled) ? sizeof(struct gfs2_meta_header) : 0;
+	}
+
+	return copied;
+}
+
+/**
+ * gfs1_rindex_read - read in the rg index file
+ *                  Stolen from libgfs2/super.c, but modified to handle gfs1.
+ * @sdp: the incore superblock pointer
+ * fd: optional file handle for rindex file (if meta_fs file system is mounted)
+ *     (if fd is <= zero, it will read from raw device)
+ * @count1: return count of the rgs.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int gfs1_rindex_read(struct gfs2_sbd *sdp, int fd, int *count1)
+{
+	unsigned int rg;
+	int error;
+	struct gfs2_rindex buf;
+	struct rgrp_list *rgd, *prev_rgd;
+	uint64_t prev_length = 0;
+
+	*count1 = 0;
+	prev_rgd = NULL;
+	for (rg = 0; ; rg++) {
+		if (fd > 0)
+			error = read(fd, &buf, sizeof(struct gfs2_rindex));
+		else
+			error = gfs1_readi(sdp->md.riinode, (char *)&buf,
+					   (rg * sizeof(struct gfs2_rindex)),
+					   sizeof(struct gfs2_rindex));
+		if (!error)
+			break;
+		if (error != sizeof(struct gfs2_rindex))
+			return -1;
+
+		rgd = (struct rgrp_list *)malloc(sizeof(struct rgrp_list));
+		if (!rgd) {
+			log_crit("Cannot allocate memory for rindex.\n");
+			exit(-1);
+		}
+		memset(rgd, 0, sizeof(struct rgrp_list));
+		osi_list_add_prev(&rgd->list, &sdp->rglist);
+
+		gfs2_rindex_in(&rgd->ri, (char *)&buf);
+
+		rgd->start = rgd->ri.ri_addr;
+		if (prev_rgd) {
+			prev_length = rgd->start - prev_rgd->start;
+			prev_rgd->length = prev_length;
+		}
+
+		if(gfs2_compute_bitstructs(sdp, rgd))
+			return -1;
+
+		(*count1)++;
+		prev_rgd = rgd;
+	}
+	if (prev_rgd)
+		prev_rgd->length = prev_length;
+	return 0;
+}
+
+/**
+ * gfs1_ri_update - attach rgrps to the super block
+ *                  Stolen from libgfs2/super.c, but modified to handle gfs1.
+ * @sdp:
+ *
+ * Given the rgrp index inode, link in all rgrps into the super block
+ * and be sure that they can be read.
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount)
+{
+	struct rgrp_list *rgd;
+	osi_list_t *tmp;
+	int count1 = 0, count2 = 0;
+	uint64_t errblock = 0;
+
+	if (gfs1_rindex_read(sdp, fd, &count1))
+	    goto fail;
+	for (tmp = sdp->rglist.next; tmp != &sdp->rglist; tmp = tmp->next) {
+		enum update_flags f;
+
+		f = not_updated;
+		rgd = osi_list_entry(tmp, struct rgrp_list, list);
+		errblock = gfs2_rgrp_read(sdp, rgd);
+		if (errblock)
+			return errblock;
+		count2++;
+		if (count2 % 100 == 0) {
+			printf(".");
+			fflush(stdout);
+		}
+	}
+
+	*rgcount = count1;
+	if (count1 != count2)
+		goto fail;
+
+	return 0;
+
+ fail:
+	gfs2_rgrp_free(&sdp->rglist, not_updated);
+	return -1;
+}
+
+/* ------------------------------------------------------------------------ */
+/* gfs_dinode_in */
+/* ------------------------------------------------------------------------ */
+void gfs_dinode_in(struct gfs_dinode *di, char *buf)
+{
+	struct gfs_dinode *str = (struct gfs_dinode *)buf;
+
+	gfs2_meta_header_in(&di->di_header, buf);
+	gfs2_inum_in(&di->di_num, (char *)&str->di_num);
+
+	di->di_mode = be32_to_cpu(str->di_mode);
+	di->di_uid = be32_to_cpu(str->di_uid);
+	di->di_gid = be32_to_cpu(str->di_gid);
+	di->di_nlink = be32_to_cpu(str->di_nlink);
+	di->di_size = be64_to_cpu(str->di_size);
+	di->di_blocks = be64_to_cpu(str->di_blocks);
+	di->di_atime = be64_to_cpu(str->di_atime);
+	di->di_mtime = be64_to_cpu(str->di_mtime);
+	di->di_ctime = be64_to_cpu(str->di_ctime);
+	di->di_major = be32_to_cpu(str->di_major);
+	di->di_minor = be32_to_cpu(str->di_minor);
+	di->di_goal_dblk = be64_to_cpu(str->di_goal_dblk);
+	di->di_goal_mblk = be64_to_cpu(str->di_goal_mblk);
+	di->di_flags = be32_to_cpu(str->di_flags);
+	di->di_payload_format = be32_to_cpu(str->di_payload_format);
+	di->di_type = be16_to_cpu(str->di_type);
+	di->di_height = be16_to_cpu(str->di_height);
+	di->di_depth = be16_to_cpu(str->di_depth);
+	di->di_entries = be32_to_cpu(str->di_entries);
+	di->di_eattr = be64_to_cpu(str->di_eattr);
+}
+
+struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
+				 struct gfs2_buffer_head *bh)
+{
+	struct gfs_dinode gfs1_dinode;
+	struct gfs2_inode *ip;
+
+	zalloc(ip, sizeof(struct gfs2_inode));
+	gfs_dinode_in(&gfs1_dinode, bh->b_data);
+	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_bh = bh;
+	ip->i_sbd = sdp;
+	return ip;
+}
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 42487b9..dfdc376 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -160,6 +160,15 @@ struct master_dir
 	struct per_node *pn;              /* Array of per_node entries */
 };
 
+struct buf_list {
+	unsigned int num_bufs;
+	unsigned int spills;
+	uint32_t limit;
+	osi_list_t list;
+	struct gfs2_sbd *sbp;
+	osi_list_t buf_hash[BUF_HASH_SIZE];
+};
+
 struct gfs2_sbd {
 	struct gfs2_sb sd_sb;    /* a copy of the ondisk structure */
 	char lockproto[GFS2_LOCKNAME_LEN];
@@ -220,14 +229,12 @@ struct gfs2_sbd {
 
 	unsigned int orig_journals;
 
-	unsigned int num_bufs;
-	osi_list_t buf_list;
-	osi_list_t buf_hash[BUF_HASH_SIZE];
+	struct buf_list buf_list;   /* transient buffer list */
+	struct buf_list nvbuf_list; /* non-volatile buffer list */
 
 	struct gfs2_inode *master_dir;
 	struct master_dir md;
 
-	unsigned int spills;
 	unsigned int writes;
 	int metafs_fd;
 	char metafs_path[PATH_MAX]; /* where metafs is mounted */
@@ -236,6 +243,10 @@ struct gfs2_sbd {
 	struct special_blocks eattr_blocks;
 };
 
+struct metapath {
+	unsigned int mp_list[GFS2_MAX_META_HEIGHT];
+};
+
 extern char *prog_name;
 
 #define GFS2_DEFAULT_BSIZE          (4096)
@@ -364,17 +375,17 @@ void *gfs2_block_list_destroy(struct gfs2_sbd *sdp,
 			      struct gfs2_block_list *il);
 
 /* buf.c */
-struct gfs2_buffer_head *bget_generic(struct gfs2_sbd *sdp, uint64_t num,
+void init_buf_list(struct gfs2_sbd *sdp, struct buf_list *bl, uint32_t limit);
+struct gfs2_buffer_head *bget_generic(struct buf_list *bl, uint64_t num,
 				      int find_existing, int read_disk);
-struct gfs2_buffer_head *bget(struct gfs2_sbd *sdp, uint64_t num);
-struct gfs2_buffer_head *bread(struct gfs2_sbd *sdp, uint64_t num);
-struct gfs2_buffer_head *bget_zero(struct gfs2_sbd *sdp, uint64_t num);
+struct gfs2_buffer_head *bget(struct buf_list *bl, uint64_t num);
+struct gfs2_buffer_head *bread(struct buf_list *bl, uint64_t num);
+struct gfs2_buffer_head *bget_zero(struct buf_list *bl, uint64_t num);
 struct gfs2_buffer_head *bhold(struct gfs2_buffer_head *bh);
 void brelse(struct gfs2_buffer_head *bh, enum update_flags updated);
-void bsync(struct gfs2_sbd *sdp);
-void bcommit(struct gfs2_sbd *sdp);
-void bcheck(struct gfs2_sbd *sdp);
-void write_buffer(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh);
+void bsync(struct buf_list *bl);
+void bcommit(struct buf_list *bl);
+void bcheck(struct buf_list *bl);
 
 /* device_geometry.c */
 void device_geometry(struct gfs2_sbd *sdp);
@@ -412,6 +423,17 @@ void build_rgrps(struct gfs2_sbd *sdp, int write);
 #define IS_LEAF     (1)
 #define IS_DINODE   (2)
 
+static __inline__ uint64_t *
+metapointer(struct gfs2_buffer_head *bh, unsigned int height,
+	    struct metapath *mp)
+{
+	unsigned int head_size = (height > 0) ?
+		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
+
+	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
+}
+
+struct metapath *find_metapath(struct gfs2_inode *ip, uint64_t block);
 struct gfs2_inode *inode_get(struct gfs2_sbd *sdp,
 			     struct gfs2_buffer_head *bh);
 void inode_put(struct gfs2_inode *ip, enum update_flags updated);
@@ -445,7 +467,7 @@ void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
 void gfs2_get_leaf_nr(struct gfs2_inode *dip, uint32_t index,
 					  uint64_t *leaf_out);
 void gfs2_put_leaf_nr(struct gfs2_inode *dip, uint32_t inx, uint64_t leaf_out);
-
+void gfs2_free_block(struct gfs2_sbd *sdp, uint64_t block);
 int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t block);
 int gfs2_get_leaf(struct gfs2_inode *dip, uint64_t leaf_no,
 				  struct gfs2_buffer_head **bhp);
@@ -468,6 +490,71 @@ void write_journal(struct gfs2_sbd *sdp, struct gfs2_inode *ip, unsigned int j,
 
 int device_size(int fd, uint64_t *bytes);
 
+/* gfs1.c - GFS1 backward compatibility functions */
+struct gfs_indirect {
+	struct gfs2_meta_header in_header;
+
+	char in_reserved[64];
+};
+
+struct gfs_dinode {
+	struct gfs2_meta_header di_header;
+
+	struct gfs2_inum di_num; /* formal inode # and block address */
+
+	uint32_t di_mode;	/* mode of file */
+	uint32_t di_uid;	/* owner's user id */
+	uint32_t di_gid;	/* owner's group id */
+	uint32_t di_nlink;	/* number (qty) of links to this file */
+	uint64_t di_size;	/* number (qty) of bytes in file */
+	uint64_t di_blocks;	/* number (qty) of blocks in file */
+	int64_t di_atime;	/* time last accessed */
+	int64_t di_mtime;	/* time last modified */
+	int64_t di_ctime;	/* time last changed */
+
+	/*  Non-zero only for character or block device nodes  */
+	uint32_t di_major;	/* device major number */
+	uint32_t di_minor;	/* device minor number */
+
+	/*  Block allocation strategy  */
+	uint64_t di_rgrp;	/* dinode rgrp block number */
+	uint64_t di_goal_rgrp;	/* rgrp to alloc from next */
+	uint32_t di_goal_dblk;	/* data block goal */
+	uint32_t di_goal_mblk;	/* metadata block goal */
+
+	uint32_t di_flags;	/* GFS_DIF_... */
+
+	/*  struct gfs_rindex, struct gfs_jindex, or struct gfs_dirent */
+	uint32_t di_payload_format;  /* GFS_FORMAT_... */
+	uint16_t di_type;	/* GFS_FILE_... type of file */
+	uint16_t di_height;	/* height of metadata (0 == stuffed) */
+	uint32_t di_incarn;	/* incarnation (unused, see gfs_meta_header) */
+	uint16_t di_pad;
+
+	/*  These only apply to directories  */
+	uint16_t di_depth;	/* Number of bits in the table */
+	uint32_t di_entries;	/* The # (qty) of entries in the directory */
+
+	/*  This formed an on-disk chain of unused dinodes  */
+	struct gfs2_inum di_next_unused;  /* used in old versions only */
+
+	uint64_t di_eattr;	/* extended attribute block number */
+
+	char di_reserved[56];
+};
+
+void gfs1_lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
+		  unsigned int height, struct metapath *mp,
+		       int create, int *new, uint64_t *block);
+void gfs1_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
+		    uint64_t *dblock, uint32_t *extlen, int prealloc);
+int gfs1_readi(struct gfs2_inode *ip, void *buf, uint64_t offset,
+	       unsigned int size);
+int gfs1_rindex_read(struct gfs2_sbd *sdp, int fd, int *count1);
+int gfs1_ri_update(struct gfs2_sbd *sdp, int fd, int *rgcount);
+struct gfs2_inode *gfs_inode_get(struct gfs2_sbd *sdp,
+				 struct gfs2_buffer_head *bh);
+
 /* locking.c */
 void test_locking(char *lockproto, char *locktable);
 
@@ -542,7 +629,11 @@ int gfs2_query(int *setonabort, struct gfs2_options *opts,
 /* misc.c */
 #define SYS_BASE "/sys/fs/gfs2"
 
+uint32_t compute_heightsize(struct gfs2_sbd *sdp, uint64_t *heightsize,
+			    int diptrs, int inptrs);
 void compute_constants(struct gfs2_sbd *sdp);
+int find_gfs2_meta(struct gfs2_sbd *sdp);
+int dir_exists(const char *dir);
 void check_for_gfs2(struct gfs2_sbd *sdp);
 void mount_gfs2_meta(struct gfs2_sbd *sdp);
 void cleanup_metafs(struct gfs2_sbd *sdp);
diff --git a/gfs2/libgfs2/misc.c b/gfs2/libgfs2/misc.c
index 2f2d6b5..644a776 100644
--- a/gfs2/libgfs2/misc.c
+++ b/gfs2/libgfs2/misc.c
@@ -22,12 +22,35 @@
 
 static char sysfs_buf[PAGE_SIZE];
 
+uint32_t compute_heightsize(struct gfs2_sbd *sdp, uint64_t *heightsize,
+			    int diptrs, int inptrs)
+{
+	int x;
+
+	heightsize[0] = sdp->bsize - sizeof(struct gfs2_dinode);
+	heightsize[1] = sdp->bsize * diptrs;
+	for (x = 2;; x++) {
+		uint64_t space, d;
+		uint32_t m;
+
+		space = heightsize[x - 1] * inptrs;
+		d = space;
+		m = do_div(d, inptrs);
+
+		if (d != heightsize[x - 1] || m)
+			break;
+		heightsize[x] = space;
+	}
+	if (x > GFS2_MAX_META_HEIGHT)
+		die("bad constants (1)\n");
+	return x;
+}
+
 void
 compute_constants(struct gfs2_sbd *sdp)
 {
 	uint32_t hash_blocks, ind_blocks, leaf_blocks;
 	uint32_t tmp_blocks;
-	unsigned int x;
 
 	sdp->md.next_inum = 1;
 
@@ -61,41 +84,12 @@ compute_constants(struct gfs2_sbd *sdp)
 
 	sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
 
-	sdp->sd_heightsize[0] = sdp->bsize - sizeof(struct gfs2_dinode);
-	sdp->sd_heightsize[1] = sdp->bsize * sdp->sd_diptrs;
-	for (x = 2;; x++) {
-		uint64_t space, d;
-		uint32_t m;
-
-		space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
-		d = space;
-		m = do_div(d, sdp->sd_inptrs);
-
-		if (d != sdp->sd_heightsize[x - 1] || m)
-			break;
-		sdp->sd_heightsize[x] = space;
-	}
-	sdp->sd_max_height = x;
-	if (sdp->sd_max_height > GFS2_MAX_META_HEIGHT)
-		die("bad constants (1)\n");
-
-	sdp->sd_jheightsize[0] = sdp->bsize - sizeof(struct gfs2_dinode);
-	sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
-	for (x = 2;; x++) {
-		uint64_t space, d;
-		uint32_t m;
-
-		space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
-		d = space;
-		m = do_div(d, sdp->sd_inptrs);
-
-		if (d != sdp->sd_jheightsize[x - 1] || m)
-			break;
-		sdp->sd_jheightsize[x] = space;
-	}
-	sdp->sd_max_jheight = x;
-	if (sdp->sd_max_jheight > GFS2_MAX_META_HEIGHT)
-		die("bad constants (2)\n");
+	sdp->sd_max_height = compute_heightsize(sdp, sdp->sd_heightsize,
+						sdp->sd_diptrs,
+						sdp->sd_inptrs);
+	sdp->sd_max_jheight = compute_heightsize(sdp, sdp->sd_jheightsize,
+						sdp->sd_diptrs,
+						sdp->sd_inptrs);
 }
 
 void
diff --git a/gfs2/libgfs2/recovery.c b/gfs2/libgfs2/recovery.c
index 8e75d24..b10fe77 100644
--- a/gfs2/libgfs2/recovery.c
+++ b/gfs2/libgfs2/recovery.c
@@ -31,7 +31,7 @@ int gfs2_replay_read_block(struct gfs2_inode *ip, unsigned int blk,
 	if (!dblock)
 		return -EIO;
 
-	*bh = bread(ip->i_sbd, dblock);
+	*bh = bread(&ip->i_sbd->buf_list, dblock);
 	return 0;
 }
 
@@ -223,7 +223,7 @@ int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head)
 	if (!dblock)
 		return -EIO;
 
-	bh = bread(ip->i_sbd, dblock);
+	bh = bread(&ip->i_sbd->buf_list, dblock);
 	memset(bh->b_data, 0, ip->i_sbd->bsize);
 
 	lh = (struct gfs2_log_header *)bh->b_data;
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index d3b702e..15adb16 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -26,7 +26,7 @@ int gfs2_compute_bitstructs(struct gfs2_sbd *sdp, struct rgrp_list *rgd)
 	   be assured we should never have more than 2149 of them. */
 	if (length > 2149 || length == 0)
 		return -1;
-	if(!(rgd->bits = (struct gfs2_bitmap *)
+	if(rgd->bits == NULL && !(rgd->bits = (struct gfs2_bitmap *)
 		 malloc(length * sizeof(struct gfs2_bitmap))))
 		return -1;
 	if(!memset(rgd->bits, 0, length * sizeof(struct gfs2_bitmap)))
@@ -72,6 +72,8 @@ int gfs2_compute_bitstructs(struct gfs2_sbd *sdp, struct rgrp_list *rgd)
 	    rgd->bits[length - 1].bi_len) * GFS2_NBBY != rgd->ri.ri_data)
 		return -1;
 
+	if (rgd->bh)      /* If we already have a bh allocated */
+		return 0; /* don't want to allocate another */
 	if(!(rgd->bh = (struct gfs2_buffer_head **)
 		 malloc(length * sizeof(struct gfs2_buffer_head *))))
 		return -1;
@@ -117,7 +119,7 @@ uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_list *rgd)
 	int x, length = rgd->ri.ri_length;
 
 	for (x = 0; x < length; x++){
-		rgd->bh[x] = bread(sdp, rgd->ri.ri_addr + x);
+		rgd->bh[x] = bread(&sdp->nvbuf_list, rgd->ri.ri_addr + x);
 		if(gfs2_check_meta(rgd->bh[x],
 				   (x) ? GFS2_METATYPE_RB : GFS2_METATYPE_RG))
 		{
@@ -153,8 +155,10 @@ void gfs2_rgrp_free(osi_list_t *rglist, enum update_flags updated)
 			gfs2_rgrp_relse(rgd, updated); /* free them all. */
 		if(rgd->bits)
 			free(rgd->bits);
-		if(rgd->bh)
+		if(rgd->bh) {
 			free(rgd->bh);
+			rgd->bh = NULL;
+		}
 		osi_list_del(&rgd->list);
 		free(rgd);
 	}
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 002edb6..fdb9bdd 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -41,7 +41,7 @@ build_sb(struct gfs2_sbd *sdp)
 
 	/* Zero out the beginning of the device up to the superblock */
 	for (x = 0; x < sdp->sb_addr; x++) {
-		bh = bget(sdp, x);
+		bh = bget(&sdp->buf_list, x);
 		memset(bh->b_data, 0, sdp->bsize);
 		brelse(bh, updated);
 	}
@@ -69,7 +69,7 @@ build_sb(struct gfs2_sbd *sdp)
 		close(fd);
 	}
 #endif
-	bh = bget(sdp, sdp->sb_addr);
+	bh = bget(&sdp->buf_list, sdp->sb_addr);
 	gfs2_sb_out(&sb, bh->b_data);
 	brelse(bh, updated);
 
@@ -418,7 +418,7 @@ 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, block);
+	bh = bread(&sbp->buf_list, block);
 	ip = inode_get(sbp, bh);
 	return ip;
 }
@@ -589,7 +589,7 @@ int gfs2_next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_list *rgd,
 			brelse(bh, not_updated);
 		if (gfs2_next_rg_meta(rgd, block, first))
 			return -1;
-		bh = bread(sdp, *block);
+		bh = bread(&sdp->buf_list, *block);
 		first = 0;
 	} while(gfs2_check_meta(bh, type));
 	brelse(bh, not_updated);
diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
index c82221e..d521f99 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -58,7 +58,7 @@ int read_sb(struct gfs2_sbd *sdp)
 	unsigned int x;
 	int error;
 
-	bh = bread(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+	bh = bread(&sdp->buf_list, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
 	gfs2_sb_in(&sdp->sd_sb, bh->b_data);
 	brelse(bh, not_updated);
 
@@ -184,7 +184,10 @@ int rindex_read(struct gfs2_sbd *sdp, int fd, int *count1)
 			return -1;
 
 		rgd = (struct rgrp_list *)malloc(sizeof(struct rgrp_list));
-		// FIXME: handle failed malloc
+		if (!rgd) {
+			log_crit("Cannot allocate memory for rindex.\n");
+			exit(-1);
+		}
 		memset(rgd, 0, sizeof(struct rgrp_list));
 		osi_list_add_prev(&rgd->list, &sdp->rglist);
 
@@ -255,10 +258,11 @@ int write_sb(struct gfs2_sbd *sbp)
 {
 	struct gfs2_buffer_head *bh;
 
-	bh = bread(sbp, GFS2_SB_ADDR >> sbp->sd_fsb2bb_shift);
+	bh = bread(&sbp->buf_list, GFS2_SB_ADDR >> sbp->sd_fsb2bb_shift);
 	gfs2_sb_out(&sbp->sd_sb, bh->b_data);
 	brelse(bh, updated);
-	bcommit(sbp); /* make sure the change gets to disk ASAP */
+	bcommit(&sbp->buf_list); /* make sure the change gets to disk ASAP */
+	bcommit(&sbp->nvbuf_list); /* make sure the change gets to disk ASAP */
 	return 0;
 }
 
diff --git a/gfs2/mkfs/main_grow.c b/gfs2/mkfs/main_grow.c
index 44e1540..7c57a38 100644
--- a/gfs2/mkfs/main_grow.c
+++ b/gfs2/mkfs/main_grow.c
@@ -172,7 +172,8 @@ void initialize_new_portion(struct gfs2_sbd *sdp, int *old_rg_count)
 	inode_put(sdp->master_dir, not_updated);
 
 	/* We're done with the libgfs portion, so commit it to disk.      */
-	bsync(sdp);
+	bsync(&sdp->buf_list);
+	bsync(&sdp->nvbuf_list);
 }
 
 /**
@@ -243,7 +244,7 @@ void
 main_grow(int argc, char *argv[])
 {
 	struct gfs2_sbd sbd, *sdp = &sbd;
-	int rgcount, i, rindex_fd;
+	int rgcount, rindex_fd;
 	char rindex_name[PATH_MAX];
 	osi_list_t *head = &sdp->rglist;
 
@@ -272,9 +273,8 @@ main_grow(int argc, char *argv[])
 		fix_device_geometry(sdp);
 		log_info("Initializing lists...\n");
 		osi_list_init(&sdp->rglist);
-		osi_list_init(&sdp->buf_list);
-		for(i = 0; i < BUF_HASH_SIZE; i++)
-			osi_list_init(&sdp->buf_hash[i]);
+		init_buf_list(sdp, &sdp->buf_list, 128 << 20);
+		init_buf_list(sdp, &sdp->nvbuf_list, 0xffffffff);
 
 		sdp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
 		sdp->bsize = sdp->sd_sb.sb_bsize;
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index 1619ed2..f650163 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -361,7 +361,8 @@ print_results(struct gfs2_sbd *sdp, uint64_t real_device_size)
 
 	if (sdp->debug) {
 		printf("\n");
-		printf("Spills:                    %u\n", sdp->spills);
+		printf("Spills:                    %u\n",
+		       sdp->buf_list.spills);
 		printf("Writes:                    %u\n", sdp->writes);
 	}
 
@@ -379,7 +380,6 @@ void
 main_mkfs(int argc, char *argv[])
 {
 	struct gfs2_sbd sbd, *sdp = &sbd;
-	unsigned int x;
 	int error;
 	int rgsize_specified = 0;
 	uint64_t real_device_size;
@@ -393,9 +393,8 @@ main_mkfs(int argc, char *argv[])
 	strcpy(sdp->lockproto, GFS2_DEFAULT_LOCKPROTO);
 	sdp->time = time(NULL);
 	osi_list_init(&sdp->rglist);
-	osi_list_init(&sdp->buf_list);
-	for (x = 0; x < BUF_HASH_SIZE; x++)
-		osi_list_init(&sdp->buf_hash[x]);
+	init_buf_list(sdp, &sdp->buf_list, 128 << 20);
+	init_buf_list(sdp, &sdp->nvbuf_list, 0xffffffff);
 
 	decode_arguments(argc, argv, sdp);
 	if (sdp->rgsize == -1)                 /* if rg size not specified */
@@ -461,7 +460,8 @@ main_mkfs(int argc, char *argv[])
 	inode_put(sdp->master_dir, updated);
 	inode_put(sdp->md.inum, updated);
 	inode_put(sdp->md.statfs, updated);
-	bsync(sdp);
+	bsync(&sdp->buf_list);
+	bsync(&sdp->nvbuf_list);
 
 	error = fsync(sdp->device_fd);
 	if (error)
diff --git a/gfs2/tool/df.c b/gfs2/tool/df.c
index fe53afc..8174a92 100644
--- a/gfs2/tool/df.c
+++ b/gfs2/tool/df.c
@@ -32,7 +32,7 @@ do_df_one(char *path)
 	uint64_t rgrps;
 	unsigned int flags;
 	char *value, *fs;
- 	int x, statfs_fd;
+	int statfs_fd;
 	struct gfs2_sbd sbd;
 	char buf[GFS2_DEFAULT_BSIZE], statfs_fn[PATH_MAX];
 	struct gfs2_statfs_change sc;
@@ -52,9 +52,9 @@ do_df_one(char *path)
 	sbd.utsize = GFS2_DEFAULT_UTSIZE;
 	sbd.qcsize = GFS2_DEFAULT_QCSIZE;
 	osi_list_init(&sbd.rglist);
-	osi_list_init(&sbd.buf_list);
-	for (x = 0; x < BUF_HASH_SIZE; x++)
-		osi_list_init(&sbd.buf_hash[x]);
+	init_buf_list(&sbd, &sbd.buf_list, 128 << 20);
+	init_buf_list(&sbd, &sbd.nvbuf_list, 0xffffffff);
+
 	do_lseek(sbd.device_fd, 0x10 * sbd.bsize);
 	do_read(sbd.device_fd, buf, sbd.bsize); /* read in the superblock */
 


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