Hi, The problem: If you do a fiemap operation on a very large sparse file, it can take an extremely long amount of time (we're talking days here) because function __generic_block_fiemap does a block-for-block search when it encounters a hole. The solution: Is to allow the file system to return the hole size so that function __generic_block_fiemap can quickly skip the hole. Preamble: This is my third attempt at this patch. This one is even shorter than the previous. In the previous version of the patch, I added the concept of a fs-specific get_hole_size() function. This version is much simpler: In cases where the fs-specific block_map() function finds a hole, it can return the hole size in b_size. This is more efficient too, because the file system doesn't need to figure out block mapping a second time to determine the hole size. The patch repurposes the buffer_meta flag to tell when the fs-specific block_map() is passing back the hole_size: If the fs-specific block_map() doesn't set the buffer_meta bit, function __generic_block_fiemap() assumes a hole size of 1 as before. Other file systems that want to take advantage of the new "hole size" functionality need only write their own function to determine the hole size, call it from their respective block_map() function, and set_buffer_meta to put it into use. I've written a simple patch to GFS2 that does just that, as a follow-on. Patch description: This patch changes function __generic_block_fiemap so that if the fs-specific block_map sets the buffer_meta flag corresponding to a hole, it takes the returned b_size to be the size of the hole, in bytes. This is much faster than trying each block individually when large holes are encountered. Regards, Bob Peterson Red Hat File Systems Signed-off-by: Bob Peterson <rpeterso@xxxxxxxxxx> --- diff --git a/fs/ioctl.c b/fs/ioctl.c index 8ac3fad..954d1c3 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -291,13 +291,18 @@ int __generic_block_fiemap(struct inode *inode, memset(&map_bh, 0, sizeof(struct buffer_head)); map_bh.b_size = len; + clear_buffer_meta(&map_bh); ret = get_block(inode, start_blk, &map_bh, 0); if (ret) break; /* HOLE */ if (!buffer_mapped(&map_bh)) { - start_blk++; + if (buffer_meta(&map_bh)) + start_blk += logical_to_blk(inode, + map_bh.b_size); + else + start_blk++; /* * We want to handle the case where there is an -- 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