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@xxxxxxxxxx> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html