summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2019-06-05 11:04:47 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2019-06-09 13:06:19 -0400
commit64bf5ff58dff757253cf2142542672de4b21cd1a (patch)
tree45cacb386c21b2778cc9a0562e5ee3aa0b2924be
parentf16acc9d9b3761ae5e45219c9302f99e20919829 (diff)
vfs: no fallback for ->copy_file_range
Now that we have generic_copy_file_range(), remove it as a fallback case when offloads fail. This puts the responsibility for executing fallbacks on the filesystems that implement ->copy_file_range and allows us to add operational validity checks to generic_copy_file_range(). Rework vfs_copy_file_range() to call a new do_copy_file_range() helper to execute the copying callout, and move calls to generic_file_copy_range() into filesystem methods where they currently return failures. [Amir] overlayfs is not responsible of executing the fallback. It is the responsibility of the underlying filesystem. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/ceph/file.c21
-rw-r--r--fs/cifs/cifsfs.c4
-rw-r--r--fs/fuse/file.c21
-rw-r--r--fs/nfs/nfs4file.c20
-rw-r--r--fs/read_write.c25
5 files changed, 73 insertions, 18 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 183c37c0a8fc..31d450536175 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1889,9 +1889,9 @@ static int is_file_size_ok(struct inode *src_inode, struct inode *dst_inode,
1889 return 0; 1889 return 0;
1890} 1890}
1891 1891
1892static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off, 1892static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
1893 struct file *dst_file, loff_t dst_off, 1893 struct file *dst_file, loff_t dst_off,
1894 size_t len, unsigned int flags) 1894 size_t len, unsigned int flags)
1895{ 1895{
1896 struct inode *src_inode = file_inode(src_file); 1896 struct inode *src_inode = file_inode(src_file);
1897 struct inode *dst_inode = file_inode(dst_file); 1897 struct inode *dst_inode = file_inode(dst_file);
@@ -2100,6 +2100,21 @@ out:
2100 return ret; 2100 return ret;
2101} 2101}
2102 2102
2103static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off,
2104 struct file *dst_file, loff_t dst_off,
2105 size_t len, unsigned int flags)
2106{
2107 ssize_t ret;
2108
2109 ret = __ceph_copy_file_range(src_file, src_off, dst_file, dst_off,
2110 len, flags);
2111
2112 if (ret == -EOPNOTSUPP)
2113 ret = generic_copy_file_range(src_file, src_off, dst_file,
2114 dst_off, len, flags);
2115 return ret;
2116}
2117
2103const struct file_operations ceph_file_fops = { 2118const struct file_operations ceph_file_fops = {
2104 .open = ceph_open, 2119 .open = ceph_open,
2105 .release = ceph_release, 2120 .release = ceph_release,
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f5fcd6360056..c65823270313 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1148,6 +1148,10 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
1148 rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff, 1148 rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
1149 len, flags); 1149 len, flags);
1150 free_xid(xid); 1150 free_xid(xid);
1151
1152 if (rc == -EOPNOTSUPP)
1153 rc = generic_copy_file_range(src_file, off, dst_file,
1154 destoff, len, flags);
1151 return rc; 1155 return rc;
1152} 1156}
1153 1157
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b8f9c83835d5..4c20bf61d9c3 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3112,9 +3112,9 @@ out:
3112 return err; 3112 return err;
3113} 3113}
3114 3114
3115static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in, 3115static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
3116 struct file *file_out, loff_t pos_out, 3116 struct file *file_out, loff_t pos_out,
3117 size_t len, unsigned int flags) 3117 size_t len, unsigned int flags)
3118{ 3118{
3119 struct fuse_file *ff_in = file_in->private_data; 3119 struct fuse_file *ff_in = file_in->private_data;
3120 struct fuse_file *ff_out = file_out->private_data; 3120 struct fuse_file *ff_out = file_out->private_data;
@@ -3194,6 +3194,21 @@ out:
3194 return err; 3194 return err;
3195} 3195}
3196 3196
3197static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
3198 struct file *dst_file, loff_t dst_off,
3199 size_t len, unsigned int flags)
3200{
3201 ssize_t ret;
3202
3203 ret = __fuse_copy_file_range(src_file, src_off, dst_file, dst_off,
3204 len, flags);
3205
3206 if (ret == -EOPNOTSUPP)
3207 ret = generic_copy_file_range(src_file, src_off, dst_file,
3208 dst_off, len, flags);
3209 return ret;
3210}
3211
3197static const struct file_operations fuse_file_operations = { 3212static const struct file_operations fuse_file_operations = {
3198 .llseek = fuse_file_llseek, 3213 .llseek = fuse_file_llseek,
3199 .read_iter = fuse_file_read_iter, 3214 .read_iter = fuse_file_read_iter,
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index cf42a8b939e3..4842f3ab3161 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -129,9 +129,9 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
129} 129}
130 130
131#ifdef CONFIG_NFS_V4_2 131#ifdef CONFIG_NFS_V4_2
132static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, 132static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
133 struct file *file_out, loff_t pos_out, 133 struct file *file_out, loff_t pos_out,
134 size_t count, unsigned int flags) 134 size_t count, unsigned int flags)
135{ 135{
136 if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY)) 136 if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY))
137 return -EOPNOTSUPP; 137 return -EOPNOTSUPP;
@@ -140,6 +140,20 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
140 return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); 140 return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
141} 141}
142 142
143static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
144 struct file *file_out, loff_t pos_out,
145 size_t count, unsigned int flags)
146{
147 ssize_t ret;
148
149 ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count,
150 flags);
151 if (ret == -EOPNOTSUPP)
152 ret = generic_copy_file_range(file_in, pos_in, file_out,
153 pos_out, count, flags);
154 return ret;
155}
156
143static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) 157static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
144{ 158{
145 loff_t ret; 159 loff_t ret;
diff --git a/fs/read_write.c b/fs/read_write.c
index 676b02fae589..b63dcb4e4fe9 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1595,6 +1595,19 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
1595} 1595}
1596EXPORT_SYMBOL(generic_copy_file_range); 1596EXPORT_SYMBOL(generic_copy_file_range);
1597 1597
1598static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
1599 struct file *file_out, loff_t pos_out,
1600 size_t len, unsigned int flags)
1601{
1602 if (file_out->f_op->copy_file_range)
1603 return file_out->f_op->copy_file_range(file_in, pos_in,
1604 file_out, pos_out,
1605 len, flags);
1606
1607 return generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
1608 flags);
1609}
1610
1598/* 1611/*
1599 * copy_file_range() differs from regular file read and write in that it 1612 * copy_file_range() differs from regular file read and write in that it
1600 * specifically allows return partial success. When it does so is up to 1613 * specifically allows return partial success. When it does so is up to
@@ -1655,15 +1668,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
1655 } 1668 }
1656 } 1669 }
1657 1670
1658 if (file_out->f_op->copy_file_range) { 1671 ret = do_copy_file_range(file_in, pos_in, file_out, pos_out, len,
1659 ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out, 1672 flags);
1660 pos_out, len, flags); 1673 WARN_ON_ONCE(ret == -EOPNOTSUPP);
1661 if (ret != -EOPNOTSUPP)
1662 goto done;
1663 }
1664
1665 ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
1666 flags);
1667done: 1674done:
1668 if (ret > 0) { 1675 if (ret > 0) {
1669 fsnotify_access(file_in); 1676 fsnotify_access(file_in);