]>
git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - fs/remap_range.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/slab.h>
3 #include <linux/stat.h>
4 #include <linux/sched/xacct.h>
5 #include <linux/fcntl.h>
6 #include <linux/file.h>
8 #include <linux/fsnotify.h>
9 #include <linux/security.h>
10 #include <linux/export.h>
11 #include <linux/syscalls.h>
12 #include <linux/pagemap.h>
13 #include <linux/splice.h>
14 #include <linux/compat.h>
15 #include <linux/mount.h>
19 #include <linux/uaccess.h>
20 #include <asm/unistd.h>
23 * Performs necessary checks before doing a clone.
25 * Can adjust amount of bytes to clone via @req_count argument.
26 * Returns appropriate error code that caller should return or
27 * zero in case the clone should be allowed.
29 int generic_remap_checks(struct file
*file_in
, loff_t pos_in
,
30 struct file
*file_out
, loff_t pos_out
,
31 loff_t
*req_count
, unsigned int remap_flags
)
33 struct inode
*inode_in
= file_in
->f_mapping
->host
;
34 struct inode
*inode_out
= file_out
->f_mapping
->host
;
35 uint64_t count
= *req_count
;
37 loff_t size_in
, size_out
;
38 loff_t bs
= inode_out
->i_sb
->s_blocksize
;
41 /* The start of both ranges must be aligned to an fs block. */
42 if (!IS_ALIGNED(pos_in
, bs
) || !IS_ALIGNED(pos_out
, bs
))
45 /* Ensure offsets don't wrap. */
46 if (pos_in
+ count
< pos_in
|| pos_out
+ count
< pos_out
)
49 size_in
= i_size_read(inode_in
);
50 size_out
= i_size_read(inode_out
);
52 /* Dedupe requires both ranges to be within EOF. */
53 if ((remap_flags
& REMAP_FILE_DEDUP
) &&
54 (pos_in
>= size_in
|| pos_in
+ count
> size_in
||
55 pos_out
>= size_out
|| pos_out
+ count
> size_out
))
58 /* Ensure the infile range is within the infile. */
59 if (pos_in
>= size_in
)
61 count
= min(count
, size_in
- (uint64_t)pos_in
);
63 ret
= generic_write_check_limits(file_out
, pos_out
, &count
);
68 * If the user wanted us to link to the infile's EOF, round up to the
69 * next block boundary for this check.
71 * Otherwise, make sure the count is also block-aligned, having
72 * already confirmed the starting offsets' block alignment.
74 if (pos_in
+ count
== size_in
) {
75 bcount
= ALIGN(size_in
, bs
) - pos_in
;
77 if (!IS_ALIGNED(count
, bs
))
78 count
= ALIGN_DOWN(count
, bs
);
82 /* Don't allow overlapped cloning within the same file. */
83 if (inode_in
== inode_out
&&
84 pos_out
+ bcount
> pos_in
&&
85 pos_out
< pos_in
+ bcount
)
89 * We shortened the request but the caller can't deal with that, so
90 * bounce the request back to userspace.
92 if (*req_count
!= count
&& !(remap_flags
& REMAP_FILE_CAN_SHORTEN
))