Skip to content

Commit 42ec3d4

Browse files
djwongdchinner
authored andcommitted
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>
1 parent 8dde90b commit 42ec3d4

File tree

18 files changed

+108
-82
lines changed

18 files changed

+108
-82
lines changed

Documentation/filesystems/vfs.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -883,9 +883,9 @@ struct file_operations {
883883
unsigned (*mmap_capabilities)(struct file *);
884884
#endif
885885
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,
887-
struct file *file_out, loff_t pos_out,
888-
u64 len, unsigned int remap_flags);
886+
loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
887+
struct file *file_out, loff_t pos_out,
888+
loff_t len, unsigned int remap_flags);
889889
int (*fadvise)(struct file *, loff_t, loff_t, int);
890890
};
891891

@@ -966,8 +966,8 @@ otherwise noted.
966966
implementation should remap len bytes at pos_in of the source file into
967967
the dest file at pos_out. Implementations must handle callers passing
968968
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
970-
negative error code if the remapping did not succeed completely.
969+
return value should the number of bytes remapped, or the usual
970+
negative error code if errors occurred before any bytes were remapped.
971971
The remap_flags parameter accepts REMAP_FILE_* flags. If
972972
REMAP_FILE_DEDUP is set then the implementation must only remap if the
973973
requested file ranges have identical contents.

fs/btrfs/ctree.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,9 +3247,9 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,
32473247
size_t num_pages, loff_t pos, size_t write_bytes,
32483248
struct extent_state **cached);
32493249
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,
3251-
struct file *file_out, loff_t pos_out, u64 len,
3252-
unsigned int remap_flags);
3250+
loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
3251+
struct file *file_out, loff_t pos_out,
3252+
loff_t len, unsigned int remap_flags);
32533253

32543254
/* tree-defrag.c */
32553255
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,

fs/btrfs/ioctl.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,10 +4328,12 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
43284328
return ret;
43294329
}
43304330

4331-
int btrfs_remap_file_range(struct file *src_file, loff_t off,
4332-
struct file *dst_file, loff_t destoff, u64 len,
4331+
loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
4332+
struct file *dst_file, loff_t destoff, loff_t len,
43334333
unsigned int remap_flags)
43344334
{
4335+
int ret;
4336+
43354337
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
43364338
return -EINVAL;
43374339

@@ -4349,10 +4351,11 @@ int btrfs_remap_file_range(struct file *src_file, loff_t off,
43494351
return -EINVAL;
43504352
}
43514353

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);
43534357
}
4354-
4355-
return btrfs_clone_files(dst_file, src_file, off, len, destoff);
4358+
return ret < 0 ? ret : len;
43564359
}
43574360

43584361
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)

fs/cifs/cifsfs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,8 @@ const struct inode_operations cifs_symlink_inode_ops = {
975975
.listxattr = cifs_listxattr,
976976
};
977977

978-
static int cifs_remap_file_range(struct file *src_file, loff_t off,
979-
struct file *dst_file, loff_t destoff, u64 len,
978+
static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
979+
struct file *dst_file, loff_t destoff, loff_t len,
980980
unsigned int remap_flags)
981981
{
982982
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,
10291029
unlock_two_nondirectories(src_inode, target_inode);
10301030
out:
10311031
free_xid(xid);
1032-
return rc;
1032+
return rc < 0 ? rc : len;
10331033
}
10341034

10351035
ssize_t cifs_file_copychunk_range(unsigned int xid,

fs/ioctl.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,22 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
223223
u64 off, u64 olen, u64 destoff)
224224
{
225225
struct fd src_file = fdget(srcfd);
226+
loff_t cloned;
226227
int ret;
227228

228229
if (!src_file.file)
229230
return -EBADF;
230231
ret = -EXDEV;
231232
if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
232233
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;
234242
fdput:
235243
fdput(src_file);
236244
return ret;

fs/nfs/nfs4file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t
180180
return nfs42_proc_allocate(filep, offset, len);
181181
}
182182

183-
static int nfs42_remap_file_range(struct file *src_file, loff_t src_off,
184-
struct file *dst_file, loff_t dst_off, u64 count,
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, loff_t count,
185185
unsigned int remap_flags)
186186
{
187187
struct inode *dst_inode = file_inode(dst_file);
@@ -244,7 +244,7 @@ static int nfs42_remap_file_range(struct file *src_file, loff_t src_off,
244244
inode_unlock(src_inode);
245245
}
246246
out:
247-
return ret;
247+
return ret < 0 ? ret : count;
248248
}
249249
#endif /* CONFIG_NFS_V4_2 */
250250

fs/nfsd/vfs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,12 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
541541
__be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
542542
u64 dst_pos, u64 count)
543543
{
544-
return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos,
545-
count));
544+
loff_t cloned;
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);
546550
}
547551

548552
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,

fs/ocfs2/file.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,18 +2527,18 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
25272527
return offset;
25282528
}
25292529

2530-
static int ocfs2_remap_file_range(struct file *file_in,
2531-
loff_t pos_in,
2532-
struct file *file_out,
2533-
loff_t pos_out,
2534-
u64 len,
2535-
unsigned int remap_flags)
2530+
static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in,
2531+
struct file *file_out, loff_t pos_out,
2532+
loff_t len, unsigned int remap_flags)
25362533
{
2534+
int ret;
2535+
25372536
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
25382537
return -EINVAL;
25392538

2540-
return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
2541-
len, remap_flags);
2539+
ret = ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
2540+
len, remap_flags);
2541+
return ret < 0 ? ret : len;
25422542
}
25432543

25442544
const struct inode_operations ocfs2_file_iops = {

fs/ocfs2/refcounttree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4824,7 +4824,7 @@ int ocfs2_reflink_remap_range(struct file *file_in,
48244824
loff_t pos_in,
48254825
struct file *file_out,
48264826
loff_t pos_out,
4827-
u64 len,
4827+
loff_t len,
48284828
unsigned int remap_flags)
48294829
{
48304830
struct inode *inode_in = file_inode(file_in);

fs/ocfs2/refcounttree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ int ocfs2_reflink_remap_range(struct file *file_in,
119119
loff_t pos_in,
120120
struct file *file_out,
121121
loff_t pos_out,
122-
u64 len,
122+
loff_t len,
123123
unsigned int remap_flags);
124124

125125
#endif /* OCFS2_REFCOUNTTREE_H */

fs/overlayfs/copy_up.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
125125
struct file *new_file;
126126
loff_t old_pos = 0;
127127
loff_t new_pos = 0;
128+
loff_t cloned;
128129
int error = 0;
129130

130131
if (len == 0)
@@ -141,11 +142,10 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
141142
}
142143

143144
/* 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-
if (!error)
145+
cloned = do_clone_file_range(old_file, 0, new_file, 0, len);
146+
if (cloned == len)
146147
goto out;
147148
/* Couldn't clone, so now we try to copy the data */
148-
error = 0;
149149

150150
/* FIXME: copy up sparse files efficiently */
151151
while (len) {

fs/overlayfs/file.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,14 @@ enum ovl_copyop {
434434
OVL_DEDUPE,
435435
};
436436

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,
438438
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)
440440
{
441441
struct inode *inode_out = file_inode(file_out);
442442
struct fd real_in, real_out;
443443
const struct cred *old_cred;
444-
ssize_t ret;
444+
loff_t ret;
445445

446446
ret = ovl_real_fdget(file_out, &real_out);
447447
if (ret)
@@ -489,9 +489,9 @@ static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
489489
OVL_COPY);
490490
}
491491

492-
static int ovl_remap_file_range(struct file *file_in, loff_t pos_in,
493-
struct file *file_out, loff_t pos_out,
494-
u64 len, unsigned int remap_flags)
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,
494+
loff_t len, unsigned int remap_flags)
495495
{
496496
enum ovl_copyop op;
497497

fs/read_write.c

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,10 +1589,13 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
15891589
* more efficient if both clone and copy are supported (e.g. NFS).
15901590
*/
15911591
if (file_in->f_op->remap_file_range) {
1592-
ret = file_in->f_op->remap_file_range(file_in, pos_in,
1593-
file_out, pos_out, len, 0);
1594-
if (ret == 0) {
1595-
ret = len;
1592+
loff_t cloned;
1593+
1594+
cloned = file_in->f_op->remap_file_range(file_in, pos_in,
1595+
file_out, pos_out,
1596+
min_t(loff_t, MAX_RW_COUNT, len), 0);
1597+
if (cloned > 0) {
1598+
ret = cloned;
15961599
goto done;
15971600
}
15981601
}
@@ -1686,11 +1689,12 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
16861689
return ret;
16871690
}
16881691

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)
16901694
{
16911695
struct inode *inode = file_inode(file);
16921696

1693-
if (unlikely(pos < 0))
1697+
if (unlikely(pos < 0 || len < 0))
16941698
return -EINVAL;
16951699

16961700
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)
17211725
static int generic_remap_check_len(struct inode *inode_in,
17221726
struct inode *inode_out,
17231727
loff_t pos_out,
1724-
u64 *len,
1728+
loff_t *len,
17251729
unsigned int remap_flags)
17261730
{
17271731
u64 blkmask = i_blocksize(inode_in) - 1;
@@ -1747,7 +1751,7 @@ static int generic_remap_check_len(struct inode *inode_in,
17471751
*/
17481752
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
17491753
struct file *file_out, loff_t pos_out,
1750-
u64 *len, unsigned int remap_flags)
1754+
loff_t *len, unsigned int remap_flags)
17511755
{
17521756
struct inode *inode_in = file_inode(file_in);
17531757
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,
18431847
}
18441848
EXPORT_SYMBOL(generic_remap_file_range_prep);
18451849

1846-
int do_clone_file_range(struct file *file_in, loff_t pos_in,
1847-
struct file *file_out, loff_t pos_out, u64 len)
1850+
loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
1851+
struct file *file_out, loff_t pos_out, loff_t len)
18481852
{
18491853
struct inode *inode_in = file_inode(file_in);
18501854
struct inode *inode_out = file_inode(file_out);
1851-
int ret;
1855+
loff_t ret;
18521856

18531857
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
18541858
return -EISDIR;
@@ -1881,19 +1885,19 @@ int do_clone_file_range(struct file *file_in, loff_t pos_in,
18811885

18821886
ret = file_in->f_op->remap_file_range(file_in, pos_in,
18831887
file_out, pos_out, len, 0);
1884-
if (!ret) {
1885-
fsnotify_access(file_in);
1886-
fsnotify_modify(file_out);
1887-
}
1888+
if (ret < 0)
1889+
return ret;
18881890

1891+
fsnotify_access(file_in);
1892+
fsnotify_modify(file_out);
18891893
return ret;
18901894
}
18911895
EXPORT_SYMBOL(do_clone_file_range);
18921896

1893-
int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
1894-
struct file *file_out, loff_t pos_out, u64 len)
1897+
loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
1898+
struct file *file_out, loff_t pos_out, loff_t len)
18951899
{
1896-
int ret;
1900+
loff_t ret;
18971901

18981902
file_start_write(file_out);
18991903
ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len);
@@ -1999,10 +2003,11 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
19992003
}
20002004
EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
20012005

2002-
int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
2003-
struct file *dst_file, loff_t dst_pos, u64 len)
2006+
loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
2007+
struct file *dst_file, loff_t dst_pos,
2008+
loff_t len)
20042009
{
2005-
s64 ret;
2010+
loff_t ret;
20062011

20072012
ret = mnt_want_write_file(dst_file);
20082013
if (ret)
@@ -2051,7 +2056,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
20512056
int i;
20522057
int ret;
20532058
u16 count = same->dest_count;
2054-
int deduped;
2059+
loff_t deduped;
20552060

20562061
if (!(file->f_mode & FMODE_READ))
20572062
return -EINVAL;

fs/xfs/xfs_file.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -919,20 +919,23 @@ xfs_file_fallocate(
919919
return error;
920920
}
921921

922-
STATIC int
922+
STATIC loff_t
923923
xfs_file_remap_range(
924924
struct file *file_in,
925925
loff_t pos_in,
926926
struct file *file_out,
927927
loff_t pos_out,
928-
u64 len,
928+
loff_t len,
929929
unsigned int remap_flags)
930930
{
931+
int ret;
932+
931933
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
932934
return -EINVAL;
933935

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,
935937
len, remap_flags);
938+
return ret < 0 ? ret : len;
936939
}
937940

938941
STATIC int

0 commit comments

Comments
 (0)