This patch adds a new function __generic_iomap_fiemap similar to __generic_block_fiemap, but it uses the new iomap interface. Signed-off-by: Bob Peterson <rpeterso@xxxxxxxxxx> --- fs/ioctl.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 11 +++++- include/linux/iomap.h | 5 +++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/fs/ioctl.c b/fs/ioctl.c index 29466c3..04b3799 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -15,6 +15,8 @@ #include <linux/writeback.h> #include <linux/buffer_head.h> #include <linux/falloc.h> +#include <linux/iomap.h> + #include "internal.h" #include <asm/ioctls.h> @@ -251,6 +253,100 @@ static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) } /** + * __generic_iomap_fiemap - FIEMAP for iomap based inodes (no locking) + * @inode: the inode to map + * @fieinfo: the fiemap info struct that will be passed back to userspace + * @start: where to start mapping in the inode + * @len: how much space to map + * + * This does FIEMAP for iomap based inodes. Basically it will just loop + * through iomap until we hit the number of extents we want to map, or we + * go past the end of the file and hit a hole. + * + * If it is possible to have data blocks beyond a hole past @inode->i_size, then + * please do not use this function, it will stop at the first unmapped block + * beyond i_size. + * + * If you use this function directly, you need to do your own locking. Use + * generic_iomap_fiemap if you want the locking done for you. + */ + +int __generic_iomap_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, loff_t start, + loff_t len, iomap_get_t iomap) +{ + struct iomap iom, prev_iom; + loff_t isize = i_size_read(inode); + int ret = 0; + + ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); + memset(&prev_iom, 0, sizeof(prev_iom)); + if (len >= isize) + len = isize; + + while ((ret == 0) && (start < isize) && len) { + memset(&iom, 0, sizeof(iom)); + ret = iomap(inode->i_mapping, start, len, &iom); + if (ret) + break; + + if (!iomap_needs_allocation(&iom)) { + if (prev_iom.blkno) + ret = fiemap_fill_next_extent(fieinfo, + prev_iom.offset, + blk_to_logical(inode, + prev_iom.blkno), + prev_iom.length, + FIEMAP_EXTENT_MERGED); + prev_iom = iom; + } + start += iom.length; + if (len < iom.length) + break; + len -= iom.length; + cond_resched(); + } + + if (prev_iom.blkno) + ret = fiemap_fill_next_extent(fieinfo, prev_iom.offset, + blk_to_logical(inode, + prev_iom.blkno), + prev_iom.length, + FIEMAP_EXTENT_MERGED | + FIEMAP_EXTENT_LAST); + /* If ret is 1 then we just hit the end of the extent array */ + if (ret == 1) + ret = 0; + + return ret; +} +EXPORT_SYMBOL(__generic_iomap_fiemap); + +/** + * generic_iomap_fiemap - FIEMAP for block based inodes + * @inode: The inode to map + * @fieinfo: The mapping information + * @start: The initial block to map + * @len: The length of the extect to attempt to map + * @get_block: The block mapping function for the fs + * + * Calls __generic_block_fiemap to map the inode, after taking + * the inode's mutex lock. + */ + +int generic_iomap_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, u64 start, + u64 len, iomap_get_t iomap) +{ + int ret; + mutex_lock(&inode->i_mutex); + ret = __generic_iomap_fiemap(inode, fieinfo, start, len, iomap); + mutex_unlock(&inode->i_mutex); + return ret; +} +EXPORT_SYMBOL(generic_iomap_fiemap); + +/** * __generic_block_fiemap - FIEMAP for block based inodes (no locking) * @inode: the inode to map * @fieinfo: the fiemap info struct that will be passed back to userspace diff --git a/include/linux/fs.h b/include/linux/fs.h index daf399d..c253d94 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -68,8 +68,12 @@ extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; struct buffer_head; +struct address_space; +struct iomap; typedef int (get_block_t)(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); +typedef int (iomap_get_t)(struct address_space *mapping, loff_t pos, + ssize_t length, struct iomap *iomap); typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, ssize_t bytes, void *private); typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate); @@ -314,7 +318,6 @@ enum positive_aop_returns { * oh the beauties of C type declarations. */ struct page; -struct address_space; struct writeback_control; #define IOCB_EVENTFD (1 << 0) @@ -2777,6 +2780,12 @@ extern int vfs_lstat(const char __user *, struct kstat *); extern int vfs_fstat(unsigned int, struct kstat *); extern int vfs_fstatat(int , const char __user *, struct kstat *, int); +extern int __generic_iomap_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, + loff_t start, loff_t len, iomap_get_t iomap); +extern int generic_iomap_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo, u64 start, + u64 len, iomap_get_t iomap); extern int __generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, loff_t start, loff_t len, diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 161c1c9..05a0645 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -17,4 +17,9 @@ struct iomap { void *priv; /* fs private data associated with map */ }; +static inline bool iomap_needs_allocation(struct iomap *iomap) +{ + return iomap->type == IOMAP_HOLE; +} + #endif /* _IOMAP_H */ -- 2.5.0 -- 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