diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2018-10-29 19:41:49 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2018-10-29 19:41:49 -0400 |
commit | 42ec3d4c02187a18e27ff94b409ec27234bf2ffd (patch) | |
tree | c9db04db8187c370718a43e6067af0e5aa944500 | |
parent | 8dde90bca6fca3736ea20109654bcf6dcf2ecf1d (diff) |
vfs: make remap_file_range functions take and return bytes completed
Change the remap_file_range functions to take a number of bytes to
operate upon and return the number of bytes they operated on. This is a
requirement for allowing fs implementations to return short clone/dedupe
results to the user, which will enable us to obey resource limits in a
graceful manner.
A subsequent patch will enable copy_file_range to signal to the
->clone_file_range implementation that it can handle a short length,
which will be returned in the function's return value. For now the
short return is not implemented anywhere so the behavior won't change --
either copy_file_range manages to clone the entire range or it tries an
alternative.
Neither clone ioctl can take advantage of this, alas.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | Documentation/filesystems/vfs.txt | 10 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 6 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 13 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 6 | ||||
-rw-r--r-- | fs/ioctl.c | 10 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 6 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 8 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 16 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 2 | ||||
-rw-r--r-- | fs/overlayfs/copy_up.c | 6 | ||||
-rw-r--r-- | fs/overlayfs/file.c | 12 | ||||
-rw-r--r-- | fs/read_write.c | 49 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.h | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 27 | ||||
-rw-r--r-- | mm/filemap.c | 2 |
18 files changed, 108 insertions, 82 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 6f5babfee27b..1bd2919deaca 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -883,9 +883,9 @@ struct file_operations { | |||
883 | unsigned (*mmap_capabilities)(struct file *); | 883 | unsigned (*mmap_capabilities)(struct file *); |
884 | #endif | 884 | #endif |
885 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); | 885 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); |
886 | int (*remap_file_range)(struct file *file_in, loff_t pos_in, | 886 | loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, |
887 | struct file *file_out, loff_t pos_out, | 887 | struct file *file_out, loff_t pos_out, |
888 | u64 len, unsigned int remap_flags); | 888 | loff_t len, unsigned int remap_flags); |
889 | int (*fadvise)(struct file *, loff_t, loff_t, int); | 889 | int (*fadvise)(struct file *, loff_t, loff_t, int); |
890 | }; | 890 | }; |
891 | 891 | ||
@@ -966,8 +966,8 @@ otherwise noted. | |||
966 | implementation should remap len bytes at pos_in of the source file into | 966 | implementation should remap len bytes at pos_in of the source file into |
967 | the dest file at pos_out. Implementations must handle callers passing | 967 | the dest file at pos_out. Implementations must handle callers passing |
968 | in len == 0; this means "remap to the end of the source file". The | 968 | in len == 0; this means "remap to the end of the source file". The |
969 | return value should be zero if all bytes were remapped, or the usual | 969 | return value should the number of bytes remapped, or the usual |
970 | negative error code if the remapping did not succeed completely. | 970 | negative error code if errors occurred before any bytes were remapped. |
971 | The remap_flags parameter accepts REMAP_FILE_* flags. If | 971 | The remap_flags parameter accepts REMAP_FILE_* flags. If |
972 | REMAP_FILE_DEDUP is set then the implementation must only remap if the | 972 | REMAP_FILE_DEDUP is set then the implementation must only remap if the |
973 | requested file ranges have identical contents. | 973 | requested file ranges have identical contents. |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 124a05662fc2..771a961d77ad 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3247,9 +3247,9 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages, | |||
3247 | size_t num_pages, loff_t pos, size_t write_bytes, | 3247 | size_t num_pages, loff_t pos, size_t write_bytes, |
3248 | struct extent_state **cached); | 3248 | struct extent_state **cached); |
3249 | int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); | 3249 | int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); |
3250 | int btrfs_remap_file_range(struct file *file_in, loff_t pos_in, | 3250 | loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in, |
3251 | struct file *file_out, loff_t pos_out, u64 len, | 3251 | struct file *file_out, loff_t pos_out, |
3252 | unsigned int remap_flags); | 3252 | loff_t len, unsigned int remap_flags); |
3253 | 3253 | ||
3254 | /* tree-defrag.c */ | 3254 | /* tree-defrag.c */ |
3255 | int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | 3255 | int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index bfd99c66723e..b0c513e10977 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -4328,10 +4328,12 @@ out_unlock: | |||
4328 | return ret; | 4328 | return ret; |
4329 | } | 4329 | } |
4330 | 4330 | ||
4331 | int btrfs_remap_file_range(struct file *src_file, loff_t off, | 4331 | loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, |
4332 | struct file *dst_file, loff_t destoff, u64 len, | 4332 | struct file *dst_file, loff_t destoff, loff_t len, |
4333 | unsigned int remap_flags) | 4333 | unsigned int remap_flags) |
4334 | { | 4334 | { |
4335 | int ret; | ||
4336 | |||
4335 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) | 4337 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
4336 | return -EINVAL; | 4338 | return -EINVAL; |
4337 | 4339 | ||
@@ -4349,10 +4351,11 @@ int btrfs_remap_file_range(struct file *src_file, loff_t off, | |||
4349 | return -EINVAL; | 4351 | return -EINVAL; |
4350 | } | 4352 | } |
4351 | 4353 | ||
4352 | return btrfs_extent_same(src, off, len, dst, destoff); | 4354 | ret = btrfs_extent_same(src, off, len, dst, destoff); |
4355 | } else { | ||
4356 | ret = btrfs_clone_files(dst_file, src_file, off, len, destoff); | ||
4353 | } | 4357 | } |
4354 | 4358 | return ret < 0 ? ret : len; | |
4355 | return btrfs_clone_files(dst_file, src_file, off, len, destoff); | ||
4356 | } | 4359 | } |
4357 | 4360 | ||
4358 | static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | 4361 | static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e8144d0dcde2..5ca71c6c8be2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -975,8 +975,8 @@ const struct inode_operations cifs_symlink_inode_ops = { | |||
975 | .listxattr = cifs_listxattr, | 975 | .listxattr = cifs_listxattr, |
976 | }; | 976 | }; |
977 | 977 | ||
978 | static int cifs_remap_file_range(struct file *src_file, loff_t off, | 978 | static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, |
979 | struct file *dst_file, loff_t destoff, u64 len, | 979 | struct file *dst_file, loff_t destoff, loff_t len, |
980 | unsigned int remap_flags) | 980 | unsigned int remap_flags) |
981 | { | 981 | { |
982 | struct inode *src_inode = file_inode(src_file); | 982 | struct inode *src_inode = file_inode(src_file); |
@@ -1029,7 +1029,7 @@ static int cifs_remap_file_range(struct file *src_file, loff_t off, | |||
1029 | unlock_two_nondirectories(src_inode, target_inode); | 1029 | unlock_two_nondirectories(src_inode, target_inode); |
1030 | out: | 1030 | out: |
1031 | free_xid(xid); | 1031 | free_xid(xid); |
1032 | return rc; | 1032 | return rc < 0 ? rc : len; |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | ssize_t cifs_file_copychunk_range(unsigned int xid, | 1035 | ssize_t cifs_file_copychunk_range(unsigned int xid, |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 2005529af560..72537b68c272 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -223,6 +223,7 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, | |||
223 | u64 off, u64 olen, u64 destoff) | 223 | u64 off, u64 olen, u64 destoff) |
224 | { | 224 | { |
225 | struct fd src_file = fdget(srcfd); | 225 | struct fd src_file = fdget(srcfd); |
226 | loff_t cloned; | ||
226 | int ret; | 227 | int ret; |
227 | 228 | ||
228 | if (!src_file.file) | 229 | if (!src_file.file) |
@@ -230,7 +231,14 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, | |||
230 | ret = -EXDEV; | 231 | ret = -EXDEV; |
231 | if (src_file.file->f_path.mnt != dst_file->f_path.mnt) | 232 | if (src_file.file->f_path.mnt != dst_file->f_path.mnt) |
232 | goto fdput; | 233 | goto fdput; |
233 | ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen); | 234 | cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff, |
235 | olen); | ||
236 | if (cloned < 0) | ||
237 | ret = cloned; | ||
238 | else if (olen && cloned != olen) | ||
239 | ret = -EINVAL; | ||
240 | else | ||
241 | ret = 0; | ||
234 | fdput: | 242 | fdput: |
235 | fdput(src_file); | 243 | fdput(src_file); |
236 | return ret; | 244 | return ret; |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index ae5780ce41dc..46d691ba04bc 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -180,8 +180,8 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t | |||
180 | return nfs42_proc_allocate(filep, offset, len); | 180 | return nfs42_proc_allocate(filep, offset, len); |
181 | } | 181 | } |
182 | 182 | ||
183 | static int nfs42_remap_file_range(struct file *src_file, loff_t src_off, | 183 | static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off, |
184 | struct file *dst_file, loff_t dst_off, u64 count, | 184 | struct file *dst_file, loff_t dst_off, loff_t count, |
185 | unsigned int remap_flags) | 185 | unsigned int remap_flags) |
186 | { | 186 | { |
187 | struct inode *dst_inode = file_inode(dst_file); | 187 | struct inode *dst_inode = file_inode(dst_file); |
@@ -244,7 +244,7 @@ out_unlock: | |||
244 | inode_unlock(src_inode); | 244 | inode_unlock(src_inode); |
245 | } | 245 | } |
246 | out: | 246 | out: |
247 | return ret; | 247 | return ret < 0 ? ret : count; |
248 | } | 248 | } |
249 | #endif /* CONFIG_NFS_V4_2 */ | 249 | #endif /* CONFIG_NFS_V4_2 */ |
250 | 250 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b53e76391e52..ac6cb6101cbe 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -541,8 +541,12 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
541 | __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst, | 541 | __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst, |
542 | u64 dst_pos, u64 count) | 542 | u64 dst_pos, u64 count) |
543 | { | 543 | { |
544 | return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos, | 544 | loff_t cloned; |
545 | count)); | 545 | |
546 | cloned = vfs_clone_file_range(src, src_pos, dst, dst_pos, count); | ||
547 | if (count && cloned != count) | ||
548 | cloned = -EINVAL; | ||
549 | return nfserrno(cloned < 0 ? cloned : 0); | ||
546 | } | 550 | } |
547 | 551 | ||
548 | ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst, | 552 | ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst, |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 9809b0e5746f..fbaeafe44b5f 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2527,18 +2527,18 @@ out: | |||
2527 | return offset; | 2527 | return offset; |
2528 | } | 2528 | } |
2529 | 2529 | ||
2530 | static int ocfs2_remap_file_range(struct file *file_in, | 2530 | static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in, |
2531 | loff_t pos_in, | 2531 | struct file *file_out, loff_t pos_out, |
2532 | struct file *file_out, | 2532 | loff_t len, unsigned int remap_flags) |
2533 | loff_t pos_out, | ||
2534 | u64 len, | ||
2535 | unsigned int remap_flags) | ||
2536 | { | 2533 | { |
2534 | int ret; | ||
2535 | |||
2537 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) | 2536 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
2538 | return -EINVAL; | 2537 | return -EINVAL; |
2539 | 2538 | ||
2540 | return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, | 2539 | ret = ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
2541 | len, remap_flags); | 2540 | len, remap_flags); |
2541 | return ret < 0 ? ret : len; | ||
2542 | } | 2542 | } |
2543 | 2543 | ||
2544 | const struct inode_operations ocfs2_file_iops = { | 2544 | const struct inode_operations ocfs2_file_iops = { |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index df9781567ec0..6a42c04ac0ab 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -4824,7 +4824,7 @@ int ocfs2_reflink_remap_range(struct file *file_in, | |||
4824 | loff_t pos_in, | 4824 | loff_t pos_in, |
4825 | struct file *file_out, | 4825 | struct file *file_out, |
4826 | loff_t pos_out, | 4826 | loff_t pos_out, |
4827 | u64 len, | 4827 | loff_t len, |
4828 | unsigned int remap_flags) | 4828 | unsigned int remap_flags) |
4829 | { | 4829 | { |
4830 | struct inode *inode_in = file_inode(file_in); | 4830 | struct inode *inode_in = file_inode(file_in); |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index d2c5f526edff..eb65c1d0843c 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -119,7 +119,7 @@ int ocfs2_reflink_remap_range(struct file *file_in, | |||
119 | loff_t pos_in, | 119 | loff_t pos_in, |
120 | struct file *file_out, | 120 | struct file *file_out, |
121 | loff_t pos_out, | 121 | loff_t pos_out, |
122 | u64 len, | 122 | loff_t len, |
123 | unsigned int remap_flags); | 123 | unsigned int remap_flags); |
124 | 124 | ||
125 | #endif /* OCFS2_REFCOUNTTREE_H */ | 125 | #endif /* OCFS2_REFCOUNTTREE_H */ |
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 1cc797a08a5b..8750b7235516 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -125,6 +125,7 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) | |||
125 | struct file *new_file; | 125 | struct file *new_file; |
126 | loff_t old_pos = 0; | 126 | loff_t old_pos = 0; |
127 | loff_t new_pos = 0; | 127 | loff_t new_pos = 0; |
128 | loff_t cloned; | ||
128 | int error = 0; | 129 | int error = 0; |
129 | 130 | ||
130 | if (len == 0) | 131 | if (len == 0) |
@@ -141,11 +142,10 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) | |||
141 | } | 142 | } |
142 | 143 | ||
143 | /* Try to use clone_file_range to clone up within the same fs */ | 144 | /* Try to use clone_file_range to clone up within the same fs */ |
144 | error = do_clone_file_range(old_file, 0, new_file, 0, len); | 145 | cloned = do_clone_file_range(old_file, 0, new_file, 0, len); |
145 | if (!error) | 146 | if (cloned == len) |
146 | goto out; | 147 | goto out; |
147 | /* Couldn't clone, so now we try to copy the data */ | 148 | /* Couldn't clone, so now we try to copy the data */ |
148 | error = 0; | ||
149 | 149 | ||
150 | /* FIXME: copy up sparse files efficiently */ | 150 | /* FIXME: copy up sparse files efficiently */ |
151 | while (len) { | 151 | while (len) { |
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index fffb36fd5920..6c3fec6168e9 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c | |||
@@ -434,14 +434,14 @@ enum ovl_copyop { | |||
434 | OVL_DEDUPE, | 434 | OVL_DEDUPE, |
435 | }; | 435 | }; |
436 | 436 | ||
437 | static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in, | 437 | static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, |
438 | struct file *file_out, loff_t pos_out, | 438 | struct file *file_out, loff_t pos_out, |
439 | u64 len, unsigned int flags, enum ovl_copyop op) | 439 | loff_t len, unsigned int flags, enum ovl_copyop op) |
440 | { | 440 | { |
441 | struct inode *inode_out = file_inode(file_out); | 441 | struct inode *inode_out = file_inode(file_out); |
442 | struct fd real_in, real_out; | 442 | struct fd real_in, real_out; |
443 | const struct cred *old_cred; | 443 | const struct cred *old_cred; |
444 | ssize_t ret; | 444 | loff_t ret; |
445 | 445 | ||
446 | ret = ovl_real_fdget(file_out, &real_out); | 446 | ret = ovl_real_fdget(file_out, &real_out); |
447 | if (ret) | 447 | if (ret) |
@@ -489,9 +489,9 @@ static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in, | |||
489 | OVL_COPY); | 489 | OVL_COPY); |
490 | } | 490 | } |
491 | 491 | ||
492 | static int ovl_remap_file_range(struct file *file_in, loff_t pos_in, | 492 | static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in, |
493 | struct file *file_out, loff_t pos_out, | 493 | struct file *file_out, loff_t pos_out, |
494 | u64 len, unsigned int remap_flags) | 494 | loff_t len, unsigned int remap_flags) |
495 | { | 495 | { |
496 | enum ovl_copyop op; | 496 | enum ovl_copyop op; |
497 | 497 | ||
diff --git a/fs/read_write.c b/fs/read_write.c index b61bd3fc7154..356641afa487 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -1589,10 +1589,13 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, | |||
1589 | * more efficient if both clone and copy are supported (e.g. NFS). | 1589 | * more efficient if both clone and copy are supported (e.g. NFS). |
1590 | */ | 1590 | */ |
1591 | if (file_in->f_op->remap_file_range) { | 1591 | if (file_in->f_op->remap_file_range) { |
1592 | ret = file_in->f_op->remap_file_range(file_in, pos_in, | 1592 | loff_t cloned; |
1593 | file_out, pos_out, len, 0); | 1593 | |
1594 | if (ret == 0) { | 1594 | cloned = file_in->f_op->remap_file_range(file_in, pos_in, |
1595 | ret = len; | 1595 | file_out, pos_out, |
1596 | min_t(loff_t, MAX_RW_COUNT, len), 0); | ||
1597 | if (cloned > 0) { | ||
1598 | ret = cloned; | ||
1596 | goto done; | 1599 | goto done; |
1597 | } | 1600 | } |
1598 | } | 1601 | } |
@@ -1686,11 +1689,12 @@ out2: | |||
1686 | return ret; | 1689 | return ret; |
1687 | } | 1690 | } |
1688 | 1691 | ||
1689 | static int remap_verify_area(struct file *file, loff_t pos, u64 len, bool write) | 1692 | static int remap_verify_area(struct file *file, loff_t pos, loff_t len, |
1693 | bool write) | ||
1690 | { | 1694 | { |
1691 | struct inode *inode = file_inode(file); | 1695 | struct inode *inode = file_inode(file); |
1692 | 1696 | ||
1693 | if (unlikely(pos < 0)) | 1697 | if (unlikely(pos < 0 || len < 0)) |
1694 | return -EINVAL; | 1698 | return -EINVAL; |
1695 | 1699 | ||
1696 | if (unlikely((loff_t) (pos + len) < 0)) | 1700 | if (unlikely((loff_t) (pos + len) < 0)) |
@@ -1721,7 +1725,7 @@ static int remap_verify_area(struct file *file, loff_t pos, u64 len, bool write) | |||
1721 | static int generic_remap_check_len(struct inode *inode_in, | 1725 | static int generic_remap_check_len(struct inode *inode_in, |
1722 | struct inode *inode_out, | 1726 | struct inode *inode_out, |
1723 | loff_t pos_out, | 1727 | loff_t pos_out, |
1724 | u64 *len, | 1728 | loff_t *len, |
1725 | unsigned int remap_flags) | 1729 | unsigned int remap_flags) |
1726 | { | 1730 | { |
1727 | u64 blkmask = i_blocksize(inode_in) - 1; | 1731 | u64 blkmask = i_blocksize(inode_in) - 1; |
@@ -1747,7 +1751,7 @@ static int generic_remap_check_len(struct inode *inode_in, | |||
1747 | */ | 1751 | */ |
1748 | int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, | 1752 | int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, |
1749 | struct file *file_out, loff_t pos_out, | 1753 | struct file *file_out, loff_t pos_out, |
1750 | u64 *len, unsigned int remap_flags) | 1754 | loff_t *len, unsigned int remap_flags) |
1751 | { | 1755 | { |
1752 | struct inode *inode_in = file_inode(file_in); | 1756 | struct inode *inode_in = file_inode(file_in); |
1753 | struct inode *inode_out = file_inode(file_out); | 1757 | struct inode *inode_out = file_inode(file_out); |
@@ -1843,12 +1847,12 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, | |||
1843 | } | 1847 | } |
1844 | EXPORT_SYMBOL(generic_remap_file_range_prep); | 1848 | EXPORT_SYMBOL(generic_remap_file_range_prep); |
1845 | 1849 | ||
1846 | int do_clone_file_range(struct file *file_in, loff_t pos_in, | 1850 | loff_t do_clone_file_range(struct file *file_in, loff_t pos_in, |
1847 | struct file *file_out, loff_t pos_out, u64 len) | 1851 | struct file *file_out, loff_t pos_out, loff_t len) |
1848 | { | 1852 | { |
1849 | struct inode *inode_in = file_inode(file_in); | 1853 | struct inode *inode_in = file_inode(file_in); |
1850 | struct inode *inode_out = file_inode(file_out); | 1854 | struct inode *inode_out = file_inode(file_out); |
1851 | int ret; | 1855 | loff_t ret; |
1852 | 1856 | ||
1853 | if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) | 1857 | if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) |
1854 | return -EISDIR; | 1858 | return -EISDIR; |
@@ -1881,19 +1885,19 @@ int do_clone_file_range(struct file *file_in, loff_t pos_in, | |||
1881 | 1885 | ||
1882 | ret = file_in->f_op->remap_file_range(file_in, pos_in, | 1886 | ret = file_in->f_op->remap_file_range(file_in, pos_in, |
1883 | file_out, pos_out, len, 0); | 1887 | file_out, pos_out, len, 0); |
1884 | if (!ret) { | 1888 | if (ret < 0) |
1885 | fsnotify_access(file_in); | 1889 | return ret; |
1886 | fsnotify_modify(file_out); | ||
1887 | } | ||
1888 | 1890 | ||
1891 | fsnotify_access(file_in); | ||
1892 | fsnotify_modify(file_out); | ||
1889 | return ret; | 1893 | return ret; |
1890 | } | 1894 | } |
1891 | EXPORT_SYMBOL(do_clone_file_range); | 1895 | EXPORT_SYMBOL(do_clone_file_range); |
1892 | 1896 | ||
1893 | int vfs_clone_file_range(struct file *file_in, loff_t pos_in, | 1897 | loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, |
1894 | struct file *file_out, loff_t pos_out, u64 len) | 1898 | struct file *file_out, loff_t pos_out, loff_t len) |
1895 | { | 1899 | { |
1896 | int ret; | 1900 | loff_t ret; |
1897 | 1901 | ||
1898 | file_start_write(file_out); | 1902 | file_start_write(file_out); |
1899 | ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len); | 1903 | ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len); |
@@ -1999,10 +2003,11 @@ out_error: | |||
1999 | } | 2003 | } |
2000 | EXPORT_SYMBOL(vfs_dedupe_file_range_compare); | 2004 | EXPORT_SYMBOL(vfs_dedupe_file_range_compare); |
2001 | 2005 | ||
2002 | int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, | 2006 | loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, |
2003 | struct file *dst_file, loff_t dst_pos, u64 len) | 2007 | struct file *dst_file, loff_t dst_pos, |
2008 | loff_t len) | ||
2004 | { | 2009 | { |
2005 | s64 ret; | 2010 | loff_t ret; |
2006 | 2011 | ||
2007 | ret = mnt_want_write_file(dst_file); | 2012 | ret = mnt_want_write_file(dst_file); |
2008 | if (ret) | 2013 | if (ret) |
@@ -2051,7 +2056,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) | |||
2051 | int i; | 2056 | int i; |
2052 | int ret; | 2057 | int ret; |
2053 | u16 count = same->dest_count; | 2058 | u16 count = same->dest_count; |
2054 | int deduped; | 2059 | loff_t deduped; |
2055 | 2060 | ||
2056 | if (!(file->f_mode & FMODE_READ)) | 2061 | if (!(file->f_mode & FMODE_READ)) |
2057 | return -EINVAL; | 2062 | return -EINVAL; |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 20314eb4677a..38fde4e11714 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -919,20 +919,23 @@ out_unlock: | |||
919 | return error; | 919 | return error; |
920 | } | 920 | } |
921 | 921 | ||
922 | STATIC int | 922 | STATIC loff_t |
923 | xfs_file_remap_range( | 923 | xfs_file_remap_range( |
924 | struct file *file_in, | 924 | struct file *file_in, |
925 | loff_t pos_in, | 925 | loff_t pos_in, |
926 | struct file *file_out, | 926 | struct file *file_out, |
927 | loff_t pos_out, | 927 | loff_t pos_out, |
928 | u64 len, | 928 | loff_t len, |
929 | unsigned int remap_flags) | 929 | unsigned int remap_flags) |
930 | { | 930 | { |
931 | int ret; | ||
932 | |||
931 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) | 933 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
932 | return -EINVAL; | 934 | return -EINVAL; |
933 | 935 | ||
934 | return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, | 936 | ret = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
935 | len, remap_flags); | 937 | len, remap_flags); |
938 | return ret < 0 ? ret : len; | ||
936 | } | 939 | } |
937 | 940 | ||
938 | STATIC int | 941 | STATIC int |
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 2d7dd8b28d7c..3dbe5fb7e9c0 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c | |||
@@ -1296,7 +1296,7 @@ xfs_reflink_remap_prep( | |||
1296 | loff_t pos_in, | 1296 | loff_t pos_in, |
1297 | struct file *file_out, | 1297 | struct file *file_out, |
1298 | loff_t pos_out, | 1298 | loff_t pos_out, |
1299 | u64 *len, | 1299 | loff_t *len, |
1300 | unsigned int remap_flags) | 1300 | unsigned int remap_flags) |
1301 | { | 1301 | { |
1302 | struct inode *inode_in = file_inode(file_in); | 1302 | struct inode *inode_in = file_inode(file_in); |
@@ -1387,7 +1387,7 @@ xfs_reflink_remap_range( | |||
1387 | loff_t pos_in, | 1387 | loff_t pos_in, |
1388 | struct file *file_out, | 1388 | struct file *file_out, |
1389 | loff_t pos_out, | 1389 | loff_t pos_out, |
1390 | u64 len, | 1390 | loff_t len, |
1391 | unsigned int remap_flags) | 1391 | unsigned int remap_flags) |
1392 | { | 1392 | { |
1393 | struct inode *inode_in = file_inode(file_in); | 1393 | struct inode *inode_in = file_inode(file_in); |
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index 6f82d628bf17..c3c46c276fe1 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h | |||
@@ -28,7 +28,7 @@ extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset, | |||
28 | xfs_off_t count); | 28 | xfs_off_t count); |
29 | extern int xfs_reflink_recover_cow(struct xfs_mount *mp); | 29 | extern int xfs_reflink_recover_cow(struct xfs_mount *mp); |
30 | extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in, | 30 | extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in, |
31 | struct file *file_out, loff_t pos_out, u64 len, | 31 | struct file *file_out, loff_t pos_out, loff_t len, |
32 | unsigned int remap_flags); | 32 | unsigned int remap_flags); |
33 | extern int xfs_reflink_inode_has_shared_extents(struct xfs_trans *tp, | 33 | extern int xfs_reflink_inode_has_shared_extents(struct xfs_trans *tp, |
34 | struct xfs_inode *ip, bool *has_shared); | 34 | struct xfs_inode *ip, bool *has_shared); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index c5435ca81132..c72d8c3c065a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1777,9 +1777,9 @@ struct file_operations { | |||
1777 | #endif | 1777 | #endif |
1778 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, | 1778 | ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, |
1779 | loff_t, size_t, unsigned int); | 1779 | loff_t, size_t, unsigned int); |
1780 | int (*remap_file_range)(struct file *file_in, loff_t pos_in, | 1780 | loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, |
1781 | struct file *file_out, loff_t pos_out, | 1781 | struct file *file_out, loff_t pos_out, |
1782 | u64 len, unsigned int remap_flags); | 1782 | loff_t len, unsigned int remap_flags); |
1783 | int (*fadvise)(struct file *, loff_t, loff_t, int); | 1783 | int (*fadvise)(struct file *, loff_t, loff_t, int); |
1784 | } __randomize_layout; | 1784 | } __randomize_layout; |
1785 | 1785 | ||
@@ -1844,19 +1844,22 @@ extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *, | |||
1844 | loff_t, size_t, unsigned int); | 1844 | loff_t, size_t, unsigned int); |
1845 | extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, | 1845 | extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, |
1846 | struct file *file_out, loff_t pos_out, | 1846 | struct file *file_out, loff_t pos_out, |
1847 | u64 *count, unsigned int remap_flags); | 1847 | loff_t *count, |
1848 | extern int do_clone_file_range(struct file *file_in, loff_t pos_in, | 1848 | unsigned int remap_flags); |
1849 | struct file *file_out, loff_t pos_out, u64 len); | 1849 | extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in, |
1850 | extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in, | 1850 | struct file *file_out, loff_t pos_out, |
1851 | struct file *file_out, loff_t pos_out, u64 len); | 1851 | loff_t len); |
1852 | extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in, | ||
1853 | struct file *file_out, loff_t pos_out, | ||
1854 | loff_t len); | ||
1852 | extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, | 1855 | extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, |
1853 | struct inode *dest, loff_t destoff, | 1856 | struct inode *dest, loff_t destoff, |
1854 | loff_t len, bool *is_same); | 1857 | loff_t len, bool *is_same); |
1855 | extern int vfs_dedupe_file_range(struct file *file, | 1858 | extern int vfs_dedupe_file_range(struct file *file, |
1856 | struct file_dedupe_range *same); | 1859 | struct file_dedupe_range *same); |
1857 | extern int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, | 1860 | extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, |
1858 | struct file *dst_file, loff_t dst_pos, | 1861 | struct file *dst_file, loff_t dst_pos, |
1859 | u64 len); | 1862 | loff_t len); |
1860 | 1863 | ||
1861 | 1864 | ||
1862 | struct super_operations { | 1865 | struct super_operations { |
@@ -2986,7 +2989,7 @@ extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); | |||
2986 | extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); | 2989 | extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); |
2987 | extern int generic_remap_checks(struct file *file_in, loff_t pos_in, | 2990 | extern int generic_remap_checks(struct file *file_in, loff_t pos_in, |
2988 | struct file *file_out, loff_t pos_out, | 2991 | struct file *file_out, loff_t pos_out, |
2989 | uint64_t *count, unsigned int remap_flags); | 2992 | loff_t *count, unsigned int remap_flags); |
2990 | extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); | 2993 | extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); |
2991 | extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); | 2994 | extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); |
2992 | extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); | 2995 | extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); |
diff --git a/mm/filemap.c b/mm/filemap.c index 410dc58f7b16..e9091d731f84 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2994,7 +2994,7 @@ EXPORT_SYMBOL(generic_write_checks); | |||
2994 | */ | 2994 | */ |
2995 | int generic_remap_checks(struct file *file_in, loff_t pos_in, | 2995 | int generic_remap_checks(struct file *file_in, loff_t pos_in, |
2996 | struct file *file_out, loff_t pos_out, | 2996 | struct file *file_out, loff_t pos_out, |
2997 | uint64_t *req_count, unsigned int remap_flags) | 2997 | loff_t *req_count, unsigned int remap_flags) |
2998 | { | 2998 | { |
2999 | struct inode *inode_in = file_in->f_mapping->host; | 2999 | struct inode *inode_in = file_in->f_mapping->host; |
3000 | struct inode *inode_out = file_out->f_mapping->host; | 3000 | struct inode *inode_out = file_out->f_mapping->host; |