When len is less than one block, it will be extended to one block. If start + len exceeds the boundary of the original block because of the extension, one needless block will be returned. And this patch only tries to map blocks within range instead of mapping as many contiguous blocks as possible at once. That's because comparing to extent-based files, find mapping for indirect-based files could be time-consuming, especially after we found the last extent we need, we don't care how long the next extent, and should return right after find a mapped block or EOF. Signed-off-by: Fan Li <fanofcode.li@xxxxxxxxxxx> --- fs/ioctl.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/fs/ioctl.c b/fs/ioctl.c index 13a3e96..5d54377 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -276,23 +276,21 @@ int __generic_block_fiemap(struct inode *inode, len = isize - start; } - /* - * Some filesystems can't deal with being asked to map less than - * blocksize, so make sure our len is at least block length. - */ - if (logical_to_blk(inode, len) == 0) - len = blk_to_logical(inode, 1); - start_blk = logical_to_blk(inode, start); last_blk = logical_to_blk(inode, start + len - 1); do { + memset(&map_bh, 0, sizeof(struct buffer_head)); /* - * we set b_size to the total size we want so it will map as - * many contiguous blocks as possible at once + * Some filesystems would round down b_size to align + * with block size, if len isn't aligned already, the last + * block may not be returned. Let's round it up first. */ - memset(&map_bh, 0, sizeof(struct buffer_head)); - map_bh.b_size = len; + if (last_blk > start_blk) + map_bh.b_size = blk_to_logical(inode, + last_blk - start_blk + 1); + else + map_bh.b_size = blk_to_logical(inode, 1); ret = get_block(inode, start_blk, &map_bh, 0); if (ret) -- 1.7.9.5 -- 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