Merge branch 'work.copy_file_range' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs copy_file_range updates from Al Viro: "Several series around copy_file_range/CLONE" * 'work.copy_file_range' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: btrfs: use new dedupe data function pointer vfs: hoist the btrfs deduplication ioctl to the vfs vfs: wire up compat ioctl for CLONE/CLONE_RANGE cifs: avoid unused variable and label nfsd: implement the NFSv4.2 CLONE operation nfsd: Pass filehandle to nfs4_preprocess_stateid_op() vfs: pull btrfs clone API to vfs layer locks: new locks_mandatory_area calling convention vfs: Add vfs_copy_file_range() support for pagecache copies btrfs: add .copy_file_range file operation x86: add sys_copy_file_range to syscall tables vfs: add copy_file_range syscall and vfs helper
This commit is contained in:
@@ -195,65 +195,27 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t
|
||||
return nfs42_proc_allocate(filep, offset, len);
|
||||
}
|
||||
|
||||
static noinline long
|
||||
nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
|
||||
u64 src_off, u64 dst_off, u64 count)
|
||||
static int nfs42_clone_file_range(struct file *src_file, loff_t src_off,
|
||||
struct file *dst_file, loff_t dst_off, u64 count)
|
||||
{
|
||||
struct inode *dst_inode = file_inode(dst_file);
|
||||
struct nfs_server *server = NFS_SERVER(dst_inode);
|
||||
struct fd src_file;
|
||||
struct inode *src_inode;
|
||||
struct inode *src_inode = file_inode(src_file);
|
||||
unsigned int bs = server->clone_blksize;
|
||||
bool same_inode = false;
|
||||
int ret;
|
||||
|
||||
/* dst file must be opened for writing */
|
||||
if (!(dst_file->f_mode & FMODE_WRITE))
|
||||
return -EINVAL;
|
||||
|
||||
ret = mnt_want_write_file(dst_file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
src_file = fdget(srcfd);
|
||||
if (!src_file.file) {
|
||||
ret = -EBADF;
|
||||
goto out_drop_write;
|
||||
}
|
||||
|
||||
src_inode = file_inode(src_file.file);
|
||||
|
||||
if (src_inode == dst_inode)
|
||||
same_inode = true;
|
||||
|
||||
/* src file must be opened for reading */
|
||||
if (!(src_file.file->f_mode & FMODE_READ))
|
||||
goto out_fput;
|
||||
|
||||
/* src and dst must be regular files */
|
||||
ret = -EISDIR;
|
||||
if (!S_ISREG(src_inode->i_mode) || !S_ISREG(dst_inode->i_mode))
|
||||
goto out_fput;
|
||||
|
||||
ret = -EXDEV;
|
||||
if (src_file.file->f_path.mnt != dst_file->f_path.mnt ||
|
||||
src_inode->i_sb != dst_inode->i_sb)
|
||||
goto out_fput;
|
||||
|
||||
/* check alignment w.r.t. clone_blksize */
|
||||
ret = -EINVAL;
|
||||
if (bs) {
|
||||
if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs))
|
||||
goto out_fput;
|
||||
goto out;
|
||||
if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count))
|
||||
goto out_fput;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* verify if ranges are overlapped within the same file */
|
||||
if (same_inode) {
|
||||
if (dst_off + count > src_off && dst_off < src_off + count)
|
||||
goto out_fput;
|
||||
}
|
||||
if (src_inode == dst_inode)
|
||||
same_inode = true;
|
||||
|
||||
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
|
||||
if (same_inode) {
|
||||
@@ -275,7 +237,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
ret = nfs42_proc_clone(src_file.file, dst_file, src_off, dst_off, count);
|
||||
ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count);
|
||||
|
||||
/* truncate inode page cache of the dst range so that future reads can fetch
|
||||
* new data from server */
|
||||
@@ -292,37 +254,9 @@ out_unlock:
|
||||
mutex_unlock(&dst_inode->i_mutex);
|
||||
mutex_unlock(&src_inode->i_mutex);
|
||||
}
|
||||
out_fput:
|
||||
fdput(src_file);
|
||||
out_drop_write:
|
||||
mnt_drop_write_file(dst_file);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
|
||||
{
|
||||
struct btrfs_ioctl_clone_range_args args;
|
||||
|
||||
if (copy_from_user(&args, argp, sizeof(args)))
|
||||
return -EFAULT;
|
||||
|
||||
return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset,
|
||||
args.dest_offset, args.src_length);
|
||||
}
|
||||
|
||||
long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
case BTRFS_IOC_CLONE:
|
||||
return nfs42_ioctl_clone(file, arg, 0, 0, 0);
|
||||
case BTRFS_IOC_CLONE_RANGE:
|
||||
return nfs42_ioctl_clone_range(file, argp);
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
const struct file_operations nfs4_file_operations = {
|
||||
@@ -342,8 +276,7 @@ const struct file_operations nfs4_file_operations = {
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
.llseek = nfs4_file_llseek,
|
||||
.fallocate = nfs42_fallocate,
|
||||
.unlocked_ioctl = nfs4_ioctl,
|
||||
.compat_ioctl = nfs4_ioctl,
|
||||
.clone_file_range = nfs42_clone_file_range,
|
||||
#else
|
||||
.llseek = nfs_file_llseek,
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user