aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Brown <zab@redhat.com>2015-11-10 16:53:32 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-12-01 14:00:54 -0500
commit3db11b2eecc02dc0eee943e71822c6d929281aa7 (patch)
tree4c3e92e765c730a4b6a4acc4c444e043fd66c573
parentcb4c4e8091e86e08cb2d48e7ae6bf454245c36cb (diff)
btrfs: add .copy_file_range file operation
This rearranges the existing COPY_RANGE ioctl implementation so that the .copy_file_range file operation can call the core loop that copies file data extent items. The extent copying loop is lifted up into its own function. It retains the core btrfs error checks that should be shared. Signed-off-by: Zach Brown <zab@redhat.com> [Anna Schumaker: Make flags an unsigned int, Check for COPY_FR_REFLINK] Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> Reviewed-by: Josef Bacik <jbacik@fb.com> Reviewed-by: David Sterba <dsterba@suse.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/file.c1
-rw-r--r--fs/btrfs/ioctl.c91
3 files changed, 56 insertions, 39 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 35489e7129a7..ede7277c167f 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -4055,6 +4055,9 @@ int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
4055 loff_t pos, size_t write_bytes, 4055 loff_t pos, size_t write_bytes,
4056 struct extent_state **cached); 4056 struct extent_state **cached);
4057int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); 4057int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
4058ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
4059 struct file *file_out, loff_t pos_out,
4060 size_t len, unsigned int flags);
4058 4061
4059/* tree-defrag.c */ 4062/* tree-defrag.c */
4060int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, 4063int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 72e73461c064..e67fe6ab8c9e 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2924,6 +2924,7 @@ const struct file_operations btrfs_file_operations = {
2924#ifdef CONFIG_COMPAT 2924#ifdef CONFIG_COMPAT
2925 .compat_ioctl = btrfs_ioctl, 2925 .compat_ioctl = btrfs_ioctl,
2926#endif 2926#endif
2927 .copy_file_range = btrfs_copy_file_range,
2927}; 2928};
2928 2929
2929void btrfs_auto_defrag_exit(void) 2930void btrfs_auto_defrag_exit(void)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index da94138eb85e..0f92735299d3 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3779,17 +3779,16 @@ out:
3779 return ret; 3779 return ret;
3780} 3780}
3781 3781
3782static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, 3782static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
3783 u64 off, u64 olen, u64 destoff) 3783 u64 off, u64 olen, u64 destoff)
3784{ 3784{
3785 struct inode *inode = file_inode(file); 3785 struct inode *inode = file_inode(file);
3786 struct inode *src = file_inode(file_src);
3786 struct btrfs_root *root = BTRFS_I(inode)->root; 3787 struct btrfs_root *root = BTRFS_I(inode)->root;
3787 struct fd src_file;
3788 struct inode *src;
3789 int ret; 3788 int ret;
3790 u64 len = olen; 3789 u64 len = olen;
3791 u64 bs = root->fs_info->sb->s_blocksize; 3790 u64 bs = root->fs_info->sb->s_blocksize;
3792 int same_inode = 0; 3791 int same_inode = src == inode;
3793 3792
3794 /* 3793 /*
3795 * TODO: 3794 * TODO:
@@ -3802,49 +3801,20 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3802 * be either compressed or non-compressed. 3801 * be either compressed or non-compressed.
3803 */ 3802 */
3804 3803
3805 /* the destination must be opened for writing */
3806 if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
3807 return -EINVAL;
3808
3809 if (btrfs_root_readonly(root)) 3804 if (btrfs_root_readonly(root))
3810 return -EROFS; 3805 return -EROFS;
3811 3806
3812 ret = mnt_want_write_file(file); 3807 if (file_src->f_path.mnt != file->f_path.mnt ||
3813 if (ret) 3808 src->i_sb != inode->i_sb)
3814 return ret; 3809 return -EXDEV;
3815
3816 src_file = fdget(srcfd);
3817 if (!src_file.file) {
3818 ret = -EBADF;
3819 goto out_drop_write;
3820 }
3821
3822 ret = -EXDEV;
3823 if (src_file.file->f_path.mnt != file->f_path.mnt)
3824 goto out_fput;
3825
3826 src = file_inode(src_file.file);
3827
3828 ret = -EINVAL;
3829 if (src == inode)
3830 same_inode = 1;
3831
3832 /* the src must be open for reading */
3833 if (!(src_file.file->f_mode & FMODE_READ))
3834 goto out_fput;
3835 3810
3836 /* don't make the dst file partly checksummed */ 3811 /* don't make the dst file partly checksummed */
3837 if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != 3812 if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
3838 (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) 3813 (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
3839 goto out_fput; 3814 return -EINVAL;
3840 3815
3841 ret = -EISDIR;
3842 if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) 3816 if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
3843 goto out_fput; 3817 return -EISDIR;
3844
3845 ret = -EXDEV;
3846 if (src->i_sb != inode->i_sb)
3847 goto out_fput;
3848 3818
3849 if (!same_inode) { 3819 if (!same_inode) {
3850 btrfs_double_inode_lock(src, inode); 3820 btrfs_double_inode_lock(src, inode);
@@ -3921,6 +3891,49 @@ out_unlock:
3921 btrfs_double_inode_unlock(src, inode); 3891 btrfs_double_inode_unlock(src, inode);
3922 else 3892 else
3923 mutex_unlock(&src->i_mutex); 3893 mutex_unlock(&src->i_mutex);
3894 return ret;
3895}
3896
3897ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
3898 struct file *file_out, loff_t pos_out,
3899 size_t len, unsigned int flags)
3900{
3901 ssize_t ret;
3902
3903 ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out);
3904 if (ret == 0)
3905 ret = len;
3906 return ret;
3907}
3908
3909static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3910 u64 off, u64 olen, u64 destoff)
3911{
3912 struct fd src_file;
3913 int ret;
3914
3915 /* the destination must be opened for writing */
3916 if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
3917 return -EINVAL;
3918
3919 ret = mnt_want_write_file(file);
3920 if (ret)
3921 return ret;
3922
3923 src_file = fdget(srcfd);
3924 if (!src_file.file) {
3925 ret = -EBADF;
3926 goto out_drop_write;
3927 }
3928
3929 /* the src must be open for reading */
3930 if (!(src_file.file->f_mode & FMODE_READ)) {
3931 ret = -EINVAL;
3932 goto out_fput;
3933 }
3934
3935 ret = btrfs_clone_files(file, src_file.file, off, olen, destoff);
3936
3924out_fput: 3937out_fput:
3925 fdput(src_file); 3938 fdput(src_file);
3926out_drop_write: 3939out_drop_write: