Skip to content

Commit

Permalink
[XFS] Hook up the fiemap ioctl.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Sandeen authored and Niv Sardi committed Dec 1, 2008
1 parent 5af317c commit f35642e
Showing 1 changed file with 84 additions and 0 deletions.
84 changes: 84 additions & 0 deletions fs/xfs/linux-2.6/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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 = {
Expand Down

0 comments on commit f35642e

Please sign in to comment.