]> git.karo-electronics.de Git - linux-beck.git/commitdiff
vfs: allow vfs_clone_file_range() across mount points
authorAmir Goldstein <amir73il@gmail.com>
Fri, 23 Sep 2016 08:38:10 +0000 (11:38 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 16 Dec 2016 10:02:54 +0000 (11:02 +0100)
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>
fs/ioctl.c
fs/read_write.c

index c415668c86d4cc727460ae0f0eb5a6d1f5840f61..6715b7208835cb76d070e77b9dd213f7571c4408 100644 (file)
@@ -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;
 }
index 3d810a11102c661414342be3a98a2f8ef14e808e..175d30e3b603bed26ff449655bf2eacdfd4977dd 100644 (file)
@@ -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))