|
@@ -3779,17 +3779,16 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|
|
- u64 off, u64 olen, u64 destoff)
|
|
|
+static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
|
|
|
+ u64 off, u64 olen, u64 destoff)
|
|
|
{
|
|
|
struct inode *inode = file_inode(file);
|
|
|
+ struct inode *src = file_inode(file_src);
|
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
|
- struct fd src_file;
|
|
|
- struct inode *src;
|
|
|
int ret;
|
|
|
u64 len = olen;
|
|
|
u64 bs = root->fs_info->sb->s_blocksize;
|
|
|
- int same_inode = 0;
|
|
|
+ int same_inode = src == inode;
|
|
|
|
|
|
/*
|
|
|
* TODO:
|
|
@@ -3802,49 +3801,20 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|
|
* be either compressed or non-compressed.
|
|
|
*/
|
|
|
|
|
|
- /* the destination must be opened for writing */
|
|
|
- if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
if (btrfs_root_readonly(root))
|
|
|
return -EROFS;
|
|
|
|
|
|
- ret = mnt_want_write_file(file);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- src_file = fdget(srcfd);
|
|
|
- if (!src_file.file) {
|
|
|
- ret = -EBADF;
|
|
|
- goto out_drop_write;
|
|
|
- }
|
|
|
-
|
|
|
- ret = -EXDEV;
|
|
|
- if (src_file.file->f_path.mnt != file->f_path.mnt)
|
|
|
- goto out_fput;
|
|
|
-
|
|
|
- src = file_inode(src_file.file);
|
|
|
-
|
|
|
- ret = -EINVAL;
|
|
|
- if (src == inode)
|
|
|
- same_inode = 1;
|
|
|
-
|
|
|
- /* the src must be open for reading */
|
|
|
- if (!(src_file.file->f_mode & FMODE_READ))
|
|
|
- goto out_fput;
|
|
|
+ if (file_src->f_path.mnt != file->f_path.mnt ||
|
|
|
+ src->i_sb != inode->i_sb)
|
|
|
+ return -EXDEV;
|
|
|
|
|
|
/* don't make the dst file partly checksummed */
|
|
|
if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
|
|
|
(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
|
|
|
- goto out_fput;
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- ret = -EISDIR;
|
|
|
if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
|
|
|
- goto out_fput;
|
|
|
-
|
|
|
- ret = -EXDEV;
|
|
|
- if (src->i_sb != inode->i_sb)
|
|
|
- goto out_fput;
|
|
|
+ return -EISDIR;
|
|
|
|
|
|
if (!same_inode) {
|
|
|
btrfs_double_inode_lock(src, inode);
|
|
@@ -3921,6 +3891,49 @@ out_unlock:
|
|
|
btrfs_double_inode_unlock(src, inode);
|
|
|
else
|
|
|
mutex_unlock(&src->i_mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|
|
+ struct file *file_out, loff_t pos_out,
|
|
|
+ size_t len, unsigned int flags)
|
|
|
+{
|
|
|
+ ssize_t ret;
|
|
|
+
|
|
|
+ ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out);
|
|
|
+ if (ret == 0)
|
|
|
+ ret = len;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
|
|
+ u64 off, u64 olen, u64 destoff)
|
|
|
+{
|
|
|
+ struct fd src_file;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* the destination must be opened for writing */
|
|
|
+ if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ret = mnt_want_write_file(file);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ src_file = fdget(srcfd);
|
|
|
+ if (!src_file.file) {
|
|
|
+ ret = -EBADF;
|
|
|
+ goto out_drop_write;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* the src must be open for reading */
|
|
|
+ if (!(src_file.file->f_mode & FMODE_READ)) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto out_fput;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = btrfs_clone_files(file, src_file.file, off, olen, destoff);
|
|
|
+
|
|
|
out_fput:
|
|
|
fdput(src_file);
|
|
|
out_drop_write:
|