[GFS2] Tidy up meta_io code

Fix a bug in the directory reading code, where we might have dereferenced
a NULL pointer in case of OOM. Updated the directory code to use the new
& improved version of gfs2_meta_ra() which now returns the first block
that was being read. Previously it was releasing it requiring following
code to grab the block again at each point it was called.

Also turned off readahead on directory lookups since we are reading a
hash table, and therefore reading the entries in order is very
unlikely. Readahead is still used for all other calls to the
directory reading function (e.g. when growing the hash table).

Removed the DIO_START constant. Everywhere this was used, it was
used to unconditionally start i/o aside from a couple of places, so
I've removed it and made the couple of exceptions to this rule into
separate functions.

Also hunted through the other DIO flags and removed them as arguments
from functions which were always called with the same combination of
arguments.

Updated gfs2_meta_indirect_buffer to be a bit more efficient and
hopefully also be a bit easier to read.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 19b9bfc..3fb9a26 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -448,6 +448,8 @@
 	u64 dblock = 0;
 	int boundary;
 
+	BUG_ON(maxlen == 0);
+
 	if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
 		return 0;
 
@@ -561,7 +563,7 @@
 	BUG_ON(!new);
 
 	bmap_lock(inode, create);
-	ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, *extlen);
+	ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, 32);
 	bmap_unlock(inode, create);
 	*extlen = bh.b_size >> inode->i_blkbits;
 	*dblock = bh.b_blocknr;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 7390286..40e94ac 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -106,7 +106,7 @@
 	struct buffer_head *bh;
 	int error;
 
-	error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh);
+	error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh);
 	if (error)
 		return error;
 	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
@@ -246,7 +246,7 @@
 }
 
 static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
-				 unsigned int offset, unsigned int size)
+				 u64 offset, unsigned int size)
 {
 	struct buffer_head *dibh;
 	int error;
@@ -271,8 +271,8 @@
  *
  * Returns: The amount of data actually copied or the error
  */
-static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,
-			      u64 offset, unsigned int size)
+static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
+			      unsigned int size, unsigned ra)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	u64 lblock, dblock;
@@ -291,8 +291,7 @@
 		return 0;
 
 	if (gfs2_is_stuffed(ip))
-		return gfs2_dir_read_stuffed(ip, buf, (unsigned int)offset,
-					     size);
+		return gfs2_dir_read_stuffed(ip, buf, offset, size);
 
 	if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
 		return -EINVAL;
@@ -313,34 +312,31 @@
 			new = 0;
 			error = gfs2_extent_map(&ip->i_inode, lblock, &new,
 						&dblock, &extlen);
+			if (error || !dblock)
+				goto fail;
+			BUG_ON(extlen < 1);
+			if (!ra)
+				extlen = 1;
+			bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+		}
+		if (!bh) {
+			error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
 			if (error)
 				goto fail;
 		}
-
-		if (extlen > 1)
-			gfs2_meta_ra(ip->i_gl, dblock, extlen);
-
-		if (dblock) {
-			if (new)
-				error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
-			else
-				error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
-			if (error)
-				goto fail;
-			dblock++;
-			extlen--;
-		} else
-			bh = NULL;
-
+		error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD);
+		if (error) {
+			brelse(bh);
+			goto fail;
+		}
+		dblock++;
+		extlen--;
 		memcpy(buf, bh->b_data + o, amount);
 		brelse(bh);
-		if (error)
-			goto fail;
-
+		bh = NULL;
 		buf += amount;
 		copied += amount;
 		lblock++;
-
 		o = sizeof(struct gfs2_meta_header);
 	}
 
@@ -701,7 +697,7 @@
 {
 	int error;
 
-	error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp);
+	error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp);
 	if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
 		/* printk(KERN_INFO "block num=%llu\n", leaf_no); */
 		error = -EIO;
@@ -727,7 +723,7 @@
 
 	error = gfs2_dir_read_data(dip, (char *)&leaf_no,
 				    index * sizeof(u64),
-				    sizeof(u64));
+				    sizeof(u64), 0);
 	if (error != sizeof(u64))
 		return (error < 0) ? error : -EIO;
 
@@ -1095,7 +1091,7 @@
 	for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
 		error = gfs2_dir_read_data(dip, (char *)buf,
 					    block * sdp->sd_hash_bsize,
-					    sdp->sd_hash_bsize);
+					    sdp->sd_hash_bsize, 1);
 		if (error != sdp->sd_hash_bsize) {
 			if (error >= 0)
 				error = -EIO;
@@ -1375,7 +1371,7 @@
 		if (ht_offset_cur != ht_offset) {
 			error = gfs2_dir_read_data(dip, (char *)lp,
 						ht_offset * sizeof(u64),
-						sdp->sd_hash_bsize);
+						sdp->sd_hash_bsize, 1);
 			if (error != sdp->sd_hash_bsize) {
 				if (error >= 0)
 					error = -EIO;
@@ -1745,7 +1741,7 @@
 		if (ht_offset_cur != ht_offset) {
 			error = gfs2_dir_read_data(dip, (char *)lp,
 						ht_offset * sizeof(u64),
-						sdp->sd_hash_bsize);
+						sdp->sd_hash_bsize, 1);
 			if (error != sdp->sd_hash_bsize) {
 				if (error >= 0)
 					error = -EIO;
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
index 698942e..bd5ca60 100644
--- a/fs/gfs2/eattr.c
+++ b/fs/gfs2/eattr.c
@@ -115,7 +115,7 @@
 	u64 *eablk, *end;
 	int error;
 
-	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_START | DIO_WAIT, &bh);
+	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh);
 	if (error)
 		return error;
 
@@ -139,7 +139,7 @@
 			break;
 		bn = be64_to_cpu(*eablk);
 
-		error = gfs2_meta_read(ip->i_gl, bn, DIO_START | DIO_WAIT, &eabh);
+		error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh);
 		if (error)
 			break;
 		error = ea_foreach_i(ip, eabh, ea_call, data);
@@ -453,8 +453,8 @@
 		return -ENOMEM;
 
 	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs),
-				       DIO_START, bh + x);
+		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+				       bh + x);
 		if (error) {
 			while (x--)
 				brelse(bh[x]);
@@ -464,7 +464,7 @@
 	}
 
 	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT);
+		error = gfs2_meta_wait(sdp, bh[x]);
 		if (error) {
 			for (; x < nptrs; x++)
 				brelse(bh[x]);
@@ -938,8 +938,8 @@
 	if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
 		u64 *end;
 
-		error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr,
-				       DIO_START | DIO_WAIT, &indbh);
+		error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT,
+				       &indbh);
 		if (error)
 			return error;
 
@@ -1215,8 +1215,8 @@
 		goto out;
 
 	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs),
-				       DIO_START, bh + x);
+		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+				       bh + x);
 		if (error) {
 			while (x--)
 				brelse(bh[x]);
@@ -1226,7 +1226,7 @@
 	}
 
 	for (x = 0; x < nptrs; x++) {
-		error = gfs2_meta_reread(sdp, bh[x], DIO_WAIT);
+		error = gfs2_meta_wait(sdp, bh[x]);
 		if (error) {
 			for (; x < nptrs; x++)
 				brelse(bh[x]);
@@ -1310,8 +1310,7 @@
 
 	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
 
-	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr,
-			       DIO_START | DIO_WAIT, &indbh);
+	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh);
 	if (error)
 		return error;
 
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 9c046db..ef1492e 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -77,32 +77,24 @@
 }
 
 /**
- * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock
+ * gfs2_page_wait - Wait for writeback of data
  * @gl: the glock
- * @flags: DIO_START | DIO_WAIT
  *
  * Syncs data (not metadata) for a regular file.
  * No-op for all other types.
  */
 
-static void gfs2_page_sync(struct gfs2_glock *gl, int flags)
+static void gfs2_page_wait(struct gfs2_glock *gl)
 {
-	struct gfs2_inode *ip;
-	struct inode *inode;
-	struct address_space *mapping;
-	int error = 0;
+	struct gfs2_inode *ip = gl->gl_object;
+	struct inode *inode = &ip->i_inode;
+	struct address_space *mapping = inode->i_mapping;
+	int error;
 
-	ip = gl->gl_object;
-	inode = &ip->i_inode;
-	if (!ip || !S_ISREG(ip->i_di.di_mode))
+	if (!S_ISREG(ip->i_di.di_mode))
 		return;
 
-	mapping = inode->i_mapping;
-
-	if (flags & DIO_START)
-		filemap_fdatawrite(mapping);
-	if (!error && (flags & DIO_WAIT))
-		error = filemap_fdatawait(mapping);
+	error = filemap_fdatawait(mapping);
 
 	/* Put back any errors cleared by filemap_fdatawait()
 	   so they can be caught by someone who can pass them
@@ -115,6 +107,18 @@
 
 }
 
+static void gfs2_page_writeback(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip = gl->gl_object;
+	struct inode *inode = &ip->i_inode;
+	struct address_space *mapping = inode->i_mapping;
+
+	if (!S_ISREG(ip->i_di.di_mode))
+		return;
+
+	filemap_fdatawrite(mapping);
+}
+
 /**
  * meta_go_sync - sync out the metadata for this glock
  * @gl: the glock
@@ -132,7 +136,7 @@
 
 	if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
 		gfs2_log_flush(gl->gl_sbd, gl);
-		gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT);
+		gfs2_meta_sync(gl);
 		if (flags & DIO_RELEASE)
 			gfs2_ail_empty_gl(gl);
 	}
@@ -185,8 +189,7 @@
 
 	if (gl->gl_state != LM_ST_UNLOCKED &&
 	    (!gh || !(gh->gh_flags & GL_SKIP))) {
-		error = gfs2_meta_read(gl, gl->gl_name.ln_number, DIO_START,
-				       &bh);
+		error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh);
 		if (!error)
 			brelse(bh);
 	}
@@ -221,16 +224,18 @@
 
 	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
 		if (meta && data) {
-			gfs2_page_sync(gl, flags | DIO_START);
+			gfs2_page_writeback(gl);
 			gfs2_log_flush(gl->gl_sbd, gl);
-			gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT);
-			gfs2_page_sync(gl, flags | DIO_WAIT);
+			gfs2_meta_sync(gl);
+			gfs2_page_wait(gl);
 			clear_bit(GLF_DIRTY, &gl->gl_flags);
 		} else if (meta) {
 			gfs2_log_flush(gl->gl_sbd, gl);
-			gfs2_meta_sync(gl, flags | DIO_START | DIO_WAIT);
-		} else if (data)
-			gfs2_page_sync(gl, flags | DIO_START | DIO_WAIT);
+			gfs2_meta_sync(gl);
+		} else if (data) {
+			gfs2_page_writeback(gl);
+			gfs2_page_wait(gl);
+		}
 		if (flags & DIO_RELEASE)
 			gfs2_ail_empty_gl(gl);
 	}
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 7183dcf..118dc69 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -12,7 +12,6 @@
 
 #include <linux/fs.h>
 
-#define DIO_START	0x00000008
 #define DIO_WAIT	0x00000010
 #define DIO_METADATA	0x00000020
 #define DIO_DATA	0x00000040
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index e44d245..2a98cbe 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -248,13 +248,13 @@
 	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
 
 	if (error) {
-		gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT);
+		gfs2_meta_sync(ip->i_gl);
 		return;
 	}
 	if (pass != 1)
 		return;
 
-	gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT);
+	gfs2_meta_sync(ip->i_gl);
 
 	fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n",
 	        jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
@@ -726,15 +726,14 @@
 	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
 
 	if (error) {
-		gfs2_meta_sync(ip->i_gl,
-			       DIO_START | DIO_WAIT);
+		gfs2_meta_sync(ip->i_gl);
 		return;
 	}
 	if (pass != 1)
 		return;
 
 	/* data sync? */
-	gfs2_meta_sync(ip->i_gl, DIO_START | DIO_WAIT);
+	gfs2_meta_sync(ip->i_gl);
 
 	fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n",
 		jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 6b52aac..d3708af 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -273,19 +273,16 @@
 /**
  * gfs2_meta_sync - Sync all buffers associated with a glock
  * @gl: The glock
- * @flags: DIO_START | DIO_WAIT
  *
  */
 
-void gfs2_meta_sync(struct gfs2_glock *gl, int flags)
+void gfs2_meta_sync(struct gfs2_glock *gl)
 {
 	struct address_space *mapping = gl->gl_aspace->i_mapping;
-	int error = 0;
+	int error;
 
-	if (flags & DIO_START)
-		filemap_fdatawrite(mapping);
-	if (!error && (flags & DIO_WAIT))
-		error = filemap_fdatawait(mapping);
+	filemap_fdatawrite(mapping);
+	error = filemap_fdatawait(mapping);
 
 	if (error)
 		gfs2_io_error(gl->gl_sbd);
@@ -377,7 +374,7 @@
  * gfs2_meta_read - Read a block from disk
  * @gl: The glock covering the block
  * @blkno: The block number
- * @flags: flags to gfs2_dreread()
+ * @flags: flags
  * @bhp: the place where the buffer is returned (NULL on failure)
  *
  * Returns: errno
@@ -386,45 +383,43 @@
 int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
 		   struct buffer_head **bhp)
 {
-	int error;
-
 	*bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
-	error = gfs2_meta_reread(gl->gl_sbd, *bhp, flags);
-	if (error)
-		brelse(*bhp);
+	if (!buffer_uptodate(*bhp))
+		ll_rw_block(READ, 1, bhp);
+	if (flags & DIO_WAIT) {
+		int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
+		if (error) {
+			brelse(*bhp);
+			return error;
+		}
+	}
 
-	return error;
+	return 0;
 }
 
 /**
- * gfs2_meta_reread - Reread a block from disk
+ * gfs2_meta_wait - Reread a block from disk
  * @sdp: the filesystem
- * @bh: The block to read
- * @flags: Flags that control the read
+ * @bh: The block to wait for
  *
  * Returns: errno
  */
 
-int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags)
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
 	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
 		return -EIO;
 
-	if ((flags & DIO_START) && !buffer_uptodate(bh))
-		ll_rw_block(READ, 1, &bh);
+	wait_on_buffer(bh);
 
-	if (flags & DIO_WAIT) {
-		wait_on_buffer(bh);
-
-		if (!buffer_uptodate(bh)) {
-			struct gfs2_trans *tr = current->journal_info;
-			if (tr && tr->tr_touched)
-				gfs2_io_error_bh(sdp, bh);
-			return -EIO;
-		}
-		if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
-			return -EIO;
+	if (!buffer_uptodate(bh)) {
+		struct gfs2_trans *tr = current->journal_info;
+		if (tr && tr->tr_touched)
+			gfs2_io_error_bh(sdp, bh);
+		return -EIO;
 	}
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		return -EIO;
 
 	return 0;
 }
@@ -635,67 +630,57 @@
 int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
 			      int new, struct buffer_head **bhp)
 {
-	struct buffer_head *bh, **bh_slot = ip->i_cache + height;
-	int error;
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_glock *gl = ip->i_gl;
+	struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
+	int in_cache = 0;
 
 	spin_lock(&ip->i_spin);
-	bh = *bh_slot;
-	if (bh) {
-		if (bh->b_blocknr == num)
-			get_bh(bh);
-		else
-			bh = NULL;
+	if (*bh_slot && (*bh_slot)->b_blocknr == num) {
+		bh = *bh_slot;
+		get_bh(bh);
+		in_cache = 1;
 	}
 	spin_unlock(&ip->i_spin);
 
-	if (bh) {
-		if (new)
-			meta_prep_new(bh);
-		else {
-			error = gfs2_meta_reread(GFS2_SB(&ip->i_inode), bh,
-						 DIO_START | DIO_WAIT);
-			if (error) {
-				brelse(bh);
-				return error;
-			}
-		}
-	} else {
-		if (new)
-			bh = gfs2_meta_new(ip->i_gl, num);
-		else {
-			error = gfs2_meta_read(ip->i_gl, num,
-					       DIO_START | DIO_WAIT, &bh);
-			if (error)
-				return error;
-		}
+	if (!bh)
+		bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE);
 
-		spin_lock(&ip->i_spin);
-		if (*bh_slot != bh) {
-			brelse(*bh_slot);
-			*bh_slot = bh;
-			get_bh(bh);
-		}
-		spin_unlock(&ip->i_spin);
-	}
+	if (!bh)
+		return -ENOBUFS;
 
 	if (new) {
-		if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), height)) {
-			brelse(bh);
-			return -EIO;
-		}
+		if (gfs2_assert_warn(sdp, height))
+			goto err;
+		meta_prep_new(bh);
 		gfs2_trans_add_bh(ip->i_gl, bh, 1);
 		gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
 		gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+	} else {
+		u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
+		if (!buffer_uptodate(bh)) {
+			ll_rw_block(READ, 1, &bh);
+			if (gfs2_meta_wait(sdp, bh))
+				goto err;
+		}
+		if (gfs2_metatype_check(sdp, bh, mtype))
+			goto err;
+	}
 
-	} else if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh,
-			     (height) ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)) {
-		brelse(bh);
-		return -EIO;
+	if (!in_cache) {
+		spin_lock(&ip->i_spin);
+		if (*bh_slot)
+			brelse(*bh_slot);
+		*bh_slot = bh;
+		get_bh(bh);
+		spin_unlock(&ip->i_spin);
 	}
 
 	*bhp = bh;
-
 	return 0;
+err:
+	brelse(bh);
+	return -EIO;
 }
 
 /**
@@ -704,19 +689,21 @@
  * @dblock: the starting disk block
  * @extlen: the number of blocks in the extent
  *
+ * returns: the first buffer in the extent
  */
 
-void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	struct inode *aspace = gl->gl_aspace;
 	struct buffer_head *first_bh, *bh;
 	u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >>
 			  sdp->sd_sb.sb_bsize_shift;
-	int error;
 
-	if (!extlen || !max_ra)
-		return;
+	BUG_ON(!extlen);
+
+	if (max_ra < 1)
+		max_ra = 1;
 	if (extlen > max_ra)
 		extlen = max_ra;
 
@@ -724,11 +711,8 @@
 
 	if (buffer_uptodate(first_bh))
 		goto out;
-	if (!buffer_locked(first_bh)) {
-		error = gfs2_meta_reread(sdp, first_bh, DIO_START);
-		if (error)
-			goto out;
-	}
+	if (!buffer_locked(first_bh))
+		ll_rw_block(READ, 1, &first_bh);
 
 	dblock++;
 	extlen--;
@@ -736,23 +720,18 @@
 	while (extlen) {
 		bh = getbuf(sdp, aspace, dblock, CREATE);
 
-		if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
-			error = gfs2_meta_reread(sdp, bh, DIO_START);
-			brelse(bh);
-			if (error)
-				goto out;
-		} else
-			brelse(bh);
-
+		if (!buffer_uptodate(bh) && !buffer_locked(bh))
+			ll_rw_block(READA, 1, &bh);
+		brelse(bh);
 		dblock++;
 		extlen--;
-
-		if (buffer_uptodate(first_bh))
-			break;
+		if (!buffer_locked(first_bh) && buffer_uptodate(first_bh))
+			goto out;
 	}
 
+	wait_on_buffer(first_bh);
 out:
-	brelse(first_bh);
+	return first_bh;
 }
 
 /**
diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
index 086a472df..3323e6d 100644
--- a/fs/gfs2/meta_io.h
+++ b/fs/gfs2/meta_io.h
@@ -46,12 +46,12 @@
 void gfs2_ail_empty_gl(struct gfs2_glock *gl);
 
 void gfs2_meta_inval(struct gfs2_glock *gl);
-void gfs2_meta_sync(struct gfs2_glock *gl, int flags);
+void gfs2_meta_sync(struct gfs2_glock *gl);
 
 struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
 int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
 		   int flags, struct buffer_head **bhp);
-int gfs2_meta_reread(struct gfs2_sbd *sdp, struct buffer_head *bh, int flags);
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
 
 void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
 			 int meta);
@@ -71,7 +71,7 @@
 	return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp);
 }
 
-void gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen);
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen);
 void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
 
 #endif /* __DIO_DOT_H__ */
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 3f9da7c..8b18e97 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -65,7 +65,7 @@
 int gfs2_get_block(struct inode *inode, sector_t lblock,
 	           struct buffer_head *bh_result, int create)
 {
-	return gfs2_block_map(inode, lblock, create, bh_result, 4);
+	return gfs2_block_map(inode, lblock, create, bh_result, 32);
 }
 
 /**
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index c5eb6c646..da46e14 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -265,7 +265,7 @@
 	error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1);
 	if (error)
 		goto fail;
-	error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_START | DIO_WAIT, &bh);
+	error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
 	if (error)
 		goto fail;
 	error = -EIO;
@@ -1059,8 +1059,7 @@
 	u32 extlen = 0;
 	int error;
 
-	if (!ip->i_di.di_size ||
-	    ip->i_di.di_size > (64 << 20) ||
+	if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) ||
 	    ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) {
 		gfs2_consist_inode(ip);
 		return -EIO;		
@@ -1091,19 +1090,16 @@
 			if (error)
 				goto fail;
 		}
-		gfs2_meta_ra(ip->i_gl,  dblock, extlen);
-		error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT,
-				       &bh);
-		if (error)
-			goto fail;
 		error = -EIO;
+		bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+		if (!bh)
+			goto fail;
 		if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) {
 			brelse(bh);
 			goto fail;
 		}
 
-		for (y = 0;
-		     y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
+		for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
 		     y++, slot++) {
 			struct gfs2_quota_change qc;
 			struct gfs2_quota_data *qd;
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 518f912..4d4ea7e 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -47,8 +47,7 @@
 		return -EIO;
 	}
 
-	gfs2_meta_ra(gl, dblock, extlen);
-	error = gfs2_meta_read(gl, dblock, DIO_START | DIO_WAIT, bh);
+	*bh = gfs2_meta_ra(gl, dblock, extlen);
 
 	return error;
 }
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 113b4ac..5f8e225 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -575,15 +575,14 @@
 
 	for (x = 0; x < length; x++) {
 		bi = rgd->rd_bits + x;
-		error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, DIO_START,
-				       &bi->bi_bh);
+		error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &bi->bi_bh);
 		if (error)
 			goto fail;
 	}
 
 	for (y = length; y--;) {
 		bi = rgd->rd_bits + y;
-		error = gfs2_meta_reread(sdp, bi->bi_bh, DIO_WAIT);
+		error = gfs2_meta_wait(sdp, bi->bi_bh);
 		if (error)
 			goto fail;
 		if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB :