[XFS] Hook up the fiemap ioctl.
This adds the fiemap inode_operation, which for us converts the fiemap values & flags into a getbmapx structure which can be sent to xfs_getbmap. The formatter then copies the bmv array back into the user's fiemap buffer via the fiemap helpers. If we wanted to be more clever, we could also return mapping data for in-inode attributes, but I'm not terribly motivated to do that just yet. Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Niv Sardi <xaiki@sgi.com>
This commit is contained in:
parent
5af317c942
commit
f35642e2f8
1 changed files with 84 additions and 0 deletions
|
@ -53,6 +53,7 @@
|
|||
#include <linux/namei.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
/*
|
||||
* Bring the atime in the XFS inode uptodate.
|
||||
|
@ -661,6 +662,88 @@ xfs_vn_fallocate(
|
|||
return error;
|
||||
}
|
||||
|
||||
#define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
|
||||
|
||||
/*
|
||||
* Call fiemap helper to fill in user data.
|
||||
* Returns positive errors to xfs_getbmap.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_fiemap_format(
|
||||
void **arg,
|
||||
struct getbmapx *bmv,
|
||||
int *full)
|
||||
{
|
||||
int error;
|
||||
struct fiemap_extent_info *fieinfo = *arg;
|
||||
u32 fiemap_flags = 0;
|
||||
u64 logical, physical, length;
|
||||
|
||||
/* Do nothing for a hole */
|
||||
if (bmv->bmv_block == -1LL)
|
||||
return 0;
|
||||
|
||||
logical = BBTOB(bmv->bmv_offset);
|
||||
physical = BBTOB(bmv->bmv_block);
|
||||
length = BBTOB(bmv->bmv_length);
|
||||
|
||||
if (bmv->bmv_oflags & BMV_OF_PREALLOC)
|
||||
fiemap_flags |= FIEMAP_EXTENT_UNWRITTEN;
|
||||
else if (bmv->bmv_oflags & BMV_OF_DELALLOC) {
|
||||
fiemap_flags |= FIEMAP_EXTENT_DELALLOC;
|
||||
physical = 0; /* no block yet */
|
||||
}
|
||||
if (bmv->bmv_oflags & BMV_OF_LAST)
|
||||
fiemap_flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
error = fiemap_fill_next_extent(fieinfo, logical, physical,
|
||||
length, fiemap_flags);
|
||||
if (error > 0) {
|
||||
error = 0;
|
||||
*full = 1; /* user array now full */
|
||||
}
|
||||
|
||||
return -error;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_vn_fiemap(
|
||||
struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo,
|
||||
u64 start,
|
||||
u64 length)
|
||||
{
|
||||
xfs_inode_t *ip = XFS_I(inode);
|
||||
struct getbmapx bm;
|
||||
int error;
|
||||
|
||||
error = fiemap_check_flags(fieinfo, XFS_FIEMAP_FLAGS);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Set up bmap header for xfs internal routine */
|
||||
bm.bmv_offset = BTOBB(start);
|
||||
/* Special case for whole file */
|
||||
if (length == FIEMAP_MAX_OFFSET)
|
||||
bm.bmv_length = -1LL;
|
||||
else
|
||||
bm.bmv_length = BTOBB(length);
|
||||
|
||||
/* our formatter will tell xfs_getbmap when to stop. */
|
||||
bm.bmv_count = MAXEXTNUM;
|
||||
bm.bmv_iflags = BMV_IF_PREALLOC;
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR)
|
||||
bm.bmv_iflags |= BMV_IF_ATTRFORK;
|
||||
if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC))
|
||||
bm.bmv_iflags |= BMV_IF_DELALLOC;
|
||||
|
||||
error = xfs_getbmap(ip, &bm, xfs_fiemap_format, fieinfo);
|
||||
if (error)
|
||||
return -error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct inode_operations xfs_inode_operations = {
|
||||
.permission = xfs_vn_permission,
|
||||
.truncate = xfs_vn_truncate,
|
||||
|
@ -671,6 +754,7 @@ static const struct inode_operations xfs_inode_operations = {
|
|||
.removexattr = generic_removexattr,
|
||||
.listxattr = xfs_vn_listxattr,
|
||||
.fallocate = xfs_vn_fallocate,
|
||||
.fiemap = xfs_vn_fiemap,
|
||||
};
|
||||
|
||||
static const struct inode_operations xfs_dir_inode_operations = {
|
||||
|
|
Loading…
Reference in a new issue