summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2016-09-23 11:38:10 +0300
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-16 11:02:54 +0100
commit913b86e92e1f68ab9db00ccb0fecf594732511e5 (patch)
tree5336fd4aef2feec90dc4c5fa25567813b6154332
parent3616119da484699e7045957c009c13d778563874 (diff)
downloadlinux-913b86e92e1f68ab9db00ccb0fecf594732511e5.tar.bz2
vfs: allow vfs_clone_file_range() across mount points
FICLONE/FICLONERANGE ioctls return -EXDEV if src and dest files are not on the same mount point. Practically, clone only requires that src and dest files are on the same file system. Move the check for same mount point to ioctl handler and keep only the check for same super block in the vfs helper. A following patch is going to use the vfs_clone_file_range() helper in overlayfs to copy up between lower and upper mount points on the same file system. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/read_write.c8
2 files changed, 10 insertions, 2 deletions
diff --git a/fs/ioctl.c b/fs/ioctl.c
index c415668c86d4..6715b7208835 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -223,7 +223,11 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
if (!src_file.file)
return -EBADF;
+ ret = -EXDEV;
+ if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
+ goto fdput;
ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen);
+fdput:
fdput(src_file);
return ret;
}
diff --git a/fs/read_write.c b/fs/read_write.c
index 3d810a11102c..175d30e3b603 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1655,8 +1655,12 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
struct inode *inode_out = file_inode(file_out);
int ret;
- if (inode_in->i_sb != inode_out->i_sb ||
- file_in->f_path.mnt != file_out->f_path.mnt)
+ /*
+ * FICLONE/FICLONERANGE ioctls enforce that src and dest files are on
+ * the same mount. Practically, they only need to be on the same file
+ * system.
+ */
+ if (inode_in->i_sb != inode_out->i_sb)
return -EXDEV;
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))