@@ -10,6 +10,8 @@
#include <linux/export.h>
#include <linux/fsnotify.h>
+#include "internal.h"
+
/**
* vfs_copy_range - copy range of bytes from source file to existing file
* @file_in: source regular file
@@ -52,7 +54,7 @@ ssize_t vfs_copy_range(struct file *file_in, loff_t pos_in,
if (!(file_in->f_mode & FMODE_READ) ||
!(file_out->f_mode & FMODE_WRITE) ||
(file_out->f_flags & O_APPEND) ||
- !file_in->f_op || !file_in->f_op->copy_range)
+ !file_in->f_op)
return -EINVAL;
inode_in = file_inode(file_in);
@@ -82,8 +84,10 @@ ssize_t vfs_copy_range(struct file *file_in, loff_t pos_in,
if (ret)
return ret;
- ret = file_in->f_op->copy_range(file_in, pos_in, file_out, pos_out,
- count);
+ if (file_in->f_op->copy_range)
+ ret = file_in->f_op->copy_range(file_in, pos_in, file_out, pos_out, count);
+ else
+ ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, count, 0);
if (ret > 0) {
fsnotify_access(file_in);
add_rchar(current, ret);
@@ -485,6 +485,7 @@ asmlinkage long sys_sendfile(int out_fd, int in_fd,
off_t __user *offset, size_t count);
asmlinkage long sys_sendfile64(int out_fd, int in_fd,
loff_t __user *offset, size_t count);
+asmlinkage long sys_copy_range(int, loff_t __user *, int, loff_t __user *, size_t);
asmlinkage long sys_readlink(const char __user *path,
char __user *buf, int bufsiz);
asmlinkage long sys_creat(const char __user *pathname, umode_t mode);
From: Bryan Schumaker <bjschuma@netapp.com> I added in a fallback to do_splice_direct() if the filesystem doesn't support the copy_range call. This is because the declaration of do_splice_direct() is now found in fs/internal.h and can't be used by other filesystems. I also had to add sys_copy_range to include/linux/syscalls.h to get my test program to recognize the new syscall. Other thoughts: - Pass count = 0 to mean "copy the entire file" - rw_verify_area() limits count to values that can fit in an int, so files larger than about 2GB cannot be copied. --- fs/copy_range.c | 10 +++++++--- include/linux/syscalls.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-)