diff options
author | Dave Chinner <dchinner@redhat.com> | 2019-06-05 11:04:47 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2019-06-09 13:06:19 -0400 |
commit | 64bf5ff58dff757253cf2142542672de4b21cd1a (patch) | |
tree | 45cacb386c21b2778cc9a0562e5ee3aa0b2924be | |
parent | f16acc9d9b3761ae5e45219c9302f99e20919829 (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.c | 21 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 4 | ||||
-rw-r--r-- | fs/fuse/file.c | 21 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 20 | ||||
-rw-r--r-- | fs/read_write.c | 25 |
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 | ||
1892 | static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off, | 1892 | static 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 | ||
2103 | static 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 | |||
2103 | const struct file_operations ceph_file_fops = { | 2118 | const 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 | ||
3115 | static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in, | 3115 | static 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 | ||
3197 | static 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 | |||
3197 | static const struct file_operations fuse_file_operations = { | 3212 | static 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 |
132 | static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | 132 | static 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 | ||
143 | static 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 | |||
143 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | 157 | static 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 | } |
1596 | EXPORT_SYMBOL(generic_copy_file_range); | 1596 | EXPORT_SYMBOL(generic_copy_file_range); |
1597 | 1597 | ||
1598 | static 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); | ||
1667 | done: | 1674 | done: |
1668 | if (ret > 0) { | 1675 | if (ret > 0) { |
1669 | fsnotify_access(file_in); | 1676 | fsnotify_access(file_in); |