Hi,
Function gfs2_block_map was re-reading blocks used to store indirect
block pointers on every call. This patch tries to find the buffers
associated with those blocks in the le_list and, if found, re-uses them
instead of re-reading them every time.
The buffers are only used for block lookups (not modified) so I don't
think this should impact anything, except being a bit faster.
There's also a slight optimization in function find_metapath, which is
used a lot.
Regards,
Bob Peterson
Red Hat GFS
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
--
.../fs/gfs2/bmap.c | 46 +++++++++++++++++---
1 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/gfs2-2.6.git.patch7/fs/gfs2/bmap.c b/gfs2-2.6.git.patch8/fs/gfs2/bmap.c
index 0974912..9b6e871 100644
--- a/gfs2-2.6.git.patch7/fs/gfs2/bmap.c
+++ b/gfs2-2.6.git.patch8/fs/gfs2/bmap.c
@@ -342,11 +342,10 @@ static void find_metapath(struct gfs2_inode *ip, u64 block,
struct metapath *mp)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- u64 b = block;
unsigned int i;
for (i = ip->i_di.di_height; i--

- mp->mp_list[i] = do_div(b, sdp->sd_inptrs);
+ mp->mp_list[i] = do_div(block, sdp->sd_inptrs);
}
@@ -441,6 +440,31 @@ static inline void bmap_unlock(struct inode *inode, int create)
}
/**
+ * find_bh - Try to locate a buffer head for a given data block
+ * @sdp: the filesystem
+ * @lblock: The logical block number
+ * @bhp: Pointer to a pointer to a buffer head to contain the one found
+ *
+ * Returns: 1 if a bh was found for dblock, or 0 if dblock was not found
+ */
+static int find_bh(struct gfs2_sbd *sdp, u64 dblock, struct buffer_head **bhp)
+{
+ struct gfs2_bufdata *bd = NULL;
+ struct buffer_head *bh;
+ int ret = 0;
+
+ list_for_each_entry(bd, &sdp->sd_log_le_buf, bd_le.le_list) {
+ bh = bd->bd_bh;
+ if (bh && buffer_mapped(bh) && bh->b_blocknr == dblock) {
+ *bhp = bh;
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
* gfs2_block_map - Map a block from an inode to a disk block
* @inode: The inode
* @lblock: The logical block number
@@ -470,6 +494,7 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
struct metapath mp;
u64 size;
struct buffer_head *dibh = NULL;
+ int existing_bh;
BUG_ON(maxlen == 0);
@@ -502,16 +527,22 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
goto out_fail;
dibh = bh;
get_bh(dibh);
+ existing_bh = 0;
for (x = 0; x < end_of_metadata; x++) {
lookup_block(ip, bh, x, &mp, create, &new, &dblock);
- brelse(bh);
+ if (!existing_bh)
+ brelse(bh);
if (!dblock)
goto out_ok;
- error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
- if (error)
- goto out_fail;
+ existing_bh = new ? 0 : find_bh(sdp, dblock, &bh);
+ if (!existing_bh) {
+ error = gfs2_meta_indirect_buffer(ip, x+1, dblock,
+ new, &bh);
+ if (error)
+ goto out_fail;
+ }
}
boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock);
@@ -538,7 +569,8 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
}
}
out_brelse:
- brelse(bh);
+ if (!existing_bh)
+ brelse(bh);
out_ok:
error = 0;
out_fail: