[Cluster-devel] [PATCH] GFS2: Speed up fiemap function by skipping holes

Bob Peterson rpeterso at redhat.com
Wed Oct 22 01:13:50 UTC 2014


Hi,

This is the GFS2 companion patch to the one I previously posted for fiemap.

Patch description:
This patch detects the new want_holesize bit in block_map requests.
If a hole is found during fiemap, it calculates the size of the hole
based on the current metapath information, then it sets the new
buffer_got_holesize bit and returns the hole size in b_size.
Since the metapath only represents a section of the file, it can
only extrapolate to a certain size based on the current metapath
buffers. Therefore, fiemap may call blockmap several times to get
the hole size. The hole size is determined by a new function.

Regards,

Bob Peterson
Red Hat File Systems

Signed-off-by: Bob Peterson <rpeterso at redhat.com> 
---
 fs/gfs2/bmap.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 68 insertions(+), 2 deletions(-)

diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index f0b945a..450ea17 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -587,6 +587,62 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
 }
 
 /**
+ * hole_size - figure out the size of a hole
+ * @ip: The inode
+ * @lblock: The logical starting block number
+ * @mp: The metapath
+ *
+ * Returns: The hole size in bytes
+ *
+ */
+static u64 hole_size(struct inode *inode, sector_t lblock,
+		     struct metapath *mp)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	unsigned int end_of_metadata = ip->i_height - 1;
+	u64 factor = 1;
+	int hgt = end_of_metadata;
+	u64 holesz = 0, holestep;
+	const __be64 *first, *end, *ptr;
+	const struct buffer_head *bh;
+	u64 isize = i_size_read(inode);
+	int zeroptrs;
+	struct metapath mp_eof;
+
+	/* Get a metapath to the very last byte */
+	find_metapath(sdp, (isize - 1) >> inode->i_blkbits, &mp_eof,
+		      ip->i_height);
+	for (hgt = end_of_metadata; hgt >= 0; hgt--) {
+		bh = mp->mp_bh[hgt];
+		if (bh) {
+			zeroptrs = 0;
+			first = metapointer(hgt, mp);
+			end = (const __be64 *)(bh->b_data + bh->b_size);
+
+			for (ptr = first; ptr < end; ptr++) {
+				if (*ptr)
+					break;
+				else
+					zeroptrs++;
+			}
+		} else {
+			zeroptrs = sdp->sd_inptrs;
+		}
+		holestep = min(factor * zeroptrs,
+			       isize - (lblock + (zeroptrs * holesz)));
+		holesz += holestep;
+		if (lblock + holesz >= isize)
+			return holesz << inode->i_blkbits;
+
+		factor *= sdp->sd_inptrs;
+		if (hgt && (mp->mp_list[hgt - 1] < mp_eof.mp_list[hgt - 1]))
+			(mp->mp_list[hgt - 1])++;
+	}
+	return holesz << inode->i_blkbits;
+}
+
+/**
  * gfs2_block_map - Map a block from an inode to a disk block
  * @inode: The inode
  * @lblock: The logical block number
@@ -645,11 +701,21 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
 	ret = lookup_metapath(ip, &mp);
 	if (ret < 0)
 		goto out;
-	if (ret != ip->i_height)
+	if (ret != ip->i_height) {
+		if (buffer_want_holesize(bh_map)) {
+			bh_map->b_size = hole_size(inode, lblock, &mp);
+			set_buffer_got_holesize(bh_map);
+		}
 		goto do_alloc;
+	}
 	ptr = metapointer(ip->i_height - 1, &mp);
-	if (*ptr == 0)
+	if (*ptr == 0) {
+		if (buffer_want_holesize(bh_map)) {
+			bh_map->b_size = hole_size(inode, lblock, &mp);
+			set_buffer_got_holesize(bh_map);
+		}
 		goto do_alloc;
+	}
 	map_bh(bh_map, inode->i_sb, be64_to_cpu(*ptr));
 	bh = mp.mp_bh[ip->i_height - 1];
 	len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, &eob);
-- 
1.9.3




More information about the Cluster-devel mailing list