[PATCH 73/76] xfs: use new vfs reflink and dedup function pointers
Darrick J. Wong
darrick.wong at oracle.com
Sat Dec 19 03:04:29 CST 2015
Use the new VFS function pointers for copy_file_range and dedupe_data.
Signed-off-by: Darrick J. Wong <darrick.wong at oracle.com>
---
fs/xfs/xfs_file.c | 61 ++++++++++++++++
fs/xfs/xfs_ioctl.c | 199 ----------------------------------------------------
2 files changed, 60 insertions(+), 200 deletions(-)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e6bc6ab..0d96a37 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1081,7 +1081,7 @@ xfs_file_wait_for_io(
}
/* Hook up to the VFS reflink function */
-int
+STATIC int
xfs_file_share_range(
struct file *file_in,
loff_t pos_in,
@@ -1175,6 +1175,62 @@ out_unlock:
return ret;
}
+STATIC ssize_t
+xfs_file_copy_range(
+ struct file *file_in,
+ loff_t pos_in,
+ struct file *file_out,
+ loff_t pos_out,
+ size_t len,
+ unsigned int flags)
+{
+ int error;
+
+ error = xfs_file_share_range(file_in, pos_in, file_out, pos_out,
+ len, false);
+ if (error)
+ return error;
+ return len;
+}
+
+STATIC int
+xfs_file_clone_range(
+ struct file *file_in,
+ loff_t pos_in,
+ struct file *file_out,
+ loff_t pos_out,
+ u64 len)
+{
+ return xfs_file_share_range(file_in, pos_in, file_out, pos_out,
+ len, false);
+}
+
+#define XFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
+STATIC ssize_t
+xfs_file_dedupe_range(
+ struct file *src_file,
+ u64 loff,
+ u64 len,
+ struct file *dst_file,
+ u64 dst_loff)
+{
+ int error;
+
+ /*
+ * Limit the total length we will dedupe for each operation.
+ * This is intended to bound the total time spent in this
+ * ioctl to something sane.
+ */
+ if (len > XFS_MAX_DEDUPE_LEN)
+ len = XFS_MAX_DEDUPE_LEN;
+
+ error = xfs_file_share_range(src_file, loff, dst_file, dst_loff,
+ len, true);
+ if (error)
+ return error;
+ return len;
+}
+
STATIC int
xfs_file_open(
struct inode *inode,
@@ -1811,6 +1867,9 @@ const struct file_operations xfs_file_operations = {
.release = xfs_file_release,
.fsync = xfs_file_fsync,
.fallocate = xfs_file_fallocate,
+ .copy_file_range = xfs_file_copy_range,
+ .clone_file_range = xfs_file_clone_range,
+ .dedupe_file_range = xfs_file_dedupe_range,
};
const struct file_operations xfs_dir_file_operations = {
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 29dc36c..7562f14 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1536,159 +1536,6 @@ xfs_ioc_swapext(
return error;
}
-extern int xfs_file_share_range(struct file *file_in, loff_t pos_in,
- struct file *file_out, loff_t pos_out, size_t len,
- bool is_dedupe);
-
-/*
- * For reflink, validate the VFS parameters, convert them into the XFS
- * equivalents, and then call the internal reflink function.
- */
-STATIC int
-xfs_ioctl_reflink(
- struct file *file_in,
- loff_t pos_in,
- struct file *file_out,
- loff_t pos_out,
- size_t len,
- bool is_dedupe)
-{
- int error;
-
- /* Do we have the correct permissions? */
- if (!(file_in->f_mode & FMODE_READ) ||
- !(file_out->f_mode & FMODE_WRITE) ||
- (file_out->f_flags & O_APPEND))
- return -EBADF;
-
- error = mnt_want_write_file(file_out);
- if (error)
- return error;
-
- error = xfs_file_share_range(file_in, pos_in, file_out, pos_out, len,
- is_dedupe);
- if (error)
- goto out_drop;
-
- fsnotify_access(file_in);
- add_rchar(current, len);
- fsnotify_modify(file_out);
- add_wchar(current, len);
- inc_syscr(current);
- inc_syscw(current);
-
-out_drop:
- mnt_drop_write_file(file_out);
- return error;
-}
-
-#define XFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
-
-static long
-xfs_ioctl_file_extent_same(
- struct file *file,
- struct xfs_extent_data __user *argp)
-{
- struct xfs_extent_data *same = NULL;
- struct xfs_extent_data_info *info;
- struct inode *src;
- u64 off;
- u64 len;
- int i;
- int ret;
- unsigned long size;
- bool is_admin;
- u16 count;
-
- is_admin = capable(CAP_SYS_ADMIN);
- src = file_inode(file);
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- if (get_user(count, &argp->dest_count)) {
- ret = -EFAULT;
- goto out;
- }
-
- size = offsetof(struct xfs_extent_data __user,
- info[count]);
-
- same = memdup_user(argp, size);
-
- if (IS_ERR(same)) {
- ret = PTR_ERR(same);
- goto out;
- }
-
- off = same->logical_offset;
- len = same->length;
-
- /*
- * Limit the total length we will dedupe for each operation.
- * This is intended to bound the total time spent in this
- * ioctl to something sane.
- */
- if (len > XFS_MAX_DEDUPE_LEN)
- len = XFS_MAX_DEDUPE_LEN;
-
- ret = -EISDIR;
- if (S_ISDIR(src->i_mode))
- goto out;
-
- ret = -EACCES;
- if (!S_ISREG(src->i_mode))
- goto out;
-
- /* pre-format output fields to sane values */
- for (i = 0; i < count; i++) {
- same->info[i].bytes_deduped = 0ULL;
- same->info[i].status = 0;
- }
-
- for (i = 0, info = same->info; i < count; i++, info++) {
- struct inode *dst;
- struct fd dst_file = fdget(info->fd);
-
- if (!dst_file.file) {
- info->status = -EBADF;
- continue;
- }
- dst = file_inode(dst_file.file);
-
- trace_xfs_ioctl_file_extent_same(file_inode(file), off, len,
- dst, info->logical_offset);
-
- info->bytes_deduped = 0;
- if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
- info->status = -EINVAL;
- } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
- info->status = -EXDEV;
- } else if (S_ISDIR(dst->i_mode)) {
- info->status = -EISDIR;
- } else if (!S_ISREG(dst->i_mode)) {
- info->status = -EOPNOTSUPP;
- } else {
- ret = xfs_ioctl_reflink(file, off, dst_file.file,
- info->logical_offset, len, true);
- if (ret == -EBADE)
- info->status = XFS_EXTENT_DATA_DIFFERS;
- else if (ret == 0)
- info->bytes_deduped = len;
- else
- info->status = ret;
- }
- fdput(dst_file);
- }
-
- ret = copy_to_user(argp, same, size);
- if (ret)
- ret = -EFAULT;
-
-out:
- kfree(same);
- return ret;
-}
-
/*
* Note: some of the ioctl's return positive numbers as a
* byte count indicating success, such as readlink_by_handle.
@@ -1987,52 +1834,6 @@ xfs_file_ioctl(
return xfs_icache_free_eofblocks(mp, &keofb);
}
- case XFS_IOC_CLONE: {
- struct fd src;
-
- src = fdget(p);
- if (!src.file)
- return -EBADF;
-
- trace_xfs_ioctl_clone(file_inode(src.file), file_inode(filp));
-
- error = xfs_ioctl_reflink(src.file, 0, filp, 0, ~0ULL, false);
- fdput(src);
- if (error > 0)
- error = 0;
-
- return error;
- }
-
- case XFS_IOC_CLONE_RANGE: {
- struct fd src;
- struct xfs_clone_args args;
-
- if (copy_from_user(&args, arg, sizeof(args)))
- return -EFAULT;
- src = fdget(args.src_fd);
- if (!src.file)
- return -EBADF;
- if (args.src_length == 0)
- args.src_length = ~0ULL;
-
- trace_xfs_ioctl_clone_range(file_inode(src.file),
- args.src_offset, args.src_length,
- file_inode(filp), args.dest_offset);
-
- error = xfs_ioctl_reflink(src.file, args.src_offset, filp,
- args.dest_offset, args.src_length,
- false);
- fdput(src);
- if (error > 0)
- error = 0;
-
- return error;
- }
-
- case XFS_IOC_FILE_EXTENT_SAME:
- return xfs_ioctl_file_extent_same(filp, arg);
-
default:
return -ENOTTY;
}
More information about the xfs
mailing list