|
@@ -53,6 +53,7 @@
|
|
#include <linux/namei.h>
|
|
#include <linux/namei.h>
|
|
#include <linux/security.h>
|
|
#include <linux/security.h>
|
|
#include <linux/falloc.h>
|
|
#include <linux/falloc.h>
|
|
|
|
+#include <linux/fiemap.h>
|
|
|
|
|
|
/*
|
|
/*
|
|
* Bring the atime in the XFS inode uptodate.
|
|
* Bring the atime in the XFS inode uptodate.
|
|
@@ -661,6 +662,88 @@ out_error:
|
|
return error;
|
|
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 = {
|
|
static const struct inode_operations xfs_inode_operations = {
|
|
.permission = xfs_vn_permission,
|
|
.permission = xfs_vn_permission,
|
|
.truncate = xfs_vn_truncate,
|
|
.truncate = xfs_vn_truncate,
|
|
@@ -671,6 +754,7 @@ static const struct inode_operations xfs_inode_operations = {
|
|
.removexattr = generic_removexattr,
|
|
.removexattr = generic_removexattr,
|
|
.listxattr = xfs_vn_listxattr,
|
|
.listxattr = xfs_vn_listxattr,
|
|
.fallocate = xfs_vn_fallocate,
|
|
.fallocate = xfs_vn_fallocate,
|
|
|
|
+ .fiemap = xfs_vn_fiemap,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct inode_operations xfs_dir_inode_operations = {
|
|
static const struct inode_operations xfs_dir_inode_operations = {
|