mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-01 12:04:08 +00:00
vfs: enable remap callers that can handle short operations
Plumb in a remap flag that enables the filesystem remap handler to shorten remapping requests for callers that can handle it. Now copy_file_range can report partial success (in case we run up against alignment problems, resource limits, etc.). We also enable CAN_SHORTEN for fideduperange to maintain existing userspace-visible behavior where xfs/btrfs shorten the dedupe range to avoid stale post-eof data exposure. 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>
This commit is contained in:
parent
df36583619
commit
eca3654e3c
4 changed files with 33 additions and 15 deletions
|
@ -970,7 +970,9 @@ otherwise noted.
|
||||||
negative error code if errors occurred before any bytes were remapped.
|
negative error code if errors occurred before any bytes were remapped.
|
||||||
The remap_flags parameter accepts REMAP_FILE_* flags. If
|
The remap_flags parameter accepts REMAP_FILE_* flags. If
|
||||||
REMAP_FILE_DEDUP is set then the implementation must only remap if the
|
REMAP_FILE_DEDUP is set then the implementation must only remap if the
|
||||||
requested file ranges have identical contents.
|
requested file ranges have identical contents. If REMAP_CAN_SHORTEN is
|
||||||
|
set, the caller is ok with the implementation shortening the request
|
||||||
|
length to satisfy alignment or EOF requirements (or any other reason).
|
||||||
|
|
||||||
fadvise: possibly called by the fadvise64() system call.
|
fadvise: possibly called by the fadvise64() system call.
|
||||||
|
|
||||||
|
|
|
@ -1593,7 +1593,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||||
|
|
||||||
cloned = file_in->f_op->remap_file_range(file_in, pos_in,
|
cloned = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||||
file_out, pos_out,
|
file_out, pos_out,
|
||||||
min_t(loff_t, MAX_RW_COUNT, len), 0);
|
min_t(loff_t, MAX_RW_COUNT, len),
|
||||||
|
REMAP_FILE_CAN_SHORTEN);
|
||||||
if (cloned > 0) {
|
if (cloned > 0) {
|
||||||
ret = cloned;
|
ret = cloned;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -1721,6 +1722,8 @@ static int remap_verify_area(struct file *file, loff_t pos, loff_t len,
|
||||||
* can't meaningfully compare post-EOF contents.
|
* can't meaningfully compare post-EOF contents.
|
||||||
*
|
*
|
||||||
* For clone we only link a partial EOF block above the destination file's EOF.
|
* For clone we only link a partial EOF block above the destination file's EOF.
|
||||||
|
*
|
||||||
|
* Shorten the request if possible.
|
||||||
*/
|
*/
|
||||||
static int generic_remap_check_len(struct inode *inode_in,
|
static int generic_remap_check_len(struct inode *inode_in,
|
||||||
struct inode *inode_out,
|
struct inode *inode_out,
|
||||||
|
@ -1729,16 +1732,24 @@ static int generic_remap_check_len(struct inode *inode_in,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
u64 blkmask = i_blocksize(inode_in) - 1;
|
u64 blkmask = i_blocksize(inode_in) - 1;
|
||||||
|
loff_t new_len = *len;
|
||||||
|
|
||||||
if ((*len & blkmask) == 0)
|
if ((*len & blkmask) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (remap_flags & REMAP_FILE_DEDUP)
|
if ((remap_flags & REMAP_FILE_DEDUP) ||
|
||||||
*len &= ~blkmask;
|
pos_out + *len < i_size_read(inode_out))
|
||||||
else if (pos_out + *len < i_size_read(inode_out))
|
new_len &= ~blkmask;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
|
if (new_len == *len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (remap_flags & REMAP_FILE_CAN_SHORTEN) {
|
||||||
|
*len = new_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (remap_flags & REMAP_FILE_DEDUP) ? -EBADE : -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2014,7 +2025,8 @@ loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
||||||
{
|
{
|
||||||
loff_t ret;
|
loff_t ret;
|
||||||
|
|
||||||
WARN_ON_ONCE(remap_flags & ~(REMAP_FILE_DEDUP));
|
WARN_ON_ONCE(remap_flags & ~(REMAP_FILE_DEDUP |
|
||||||
|
REMAP_FILE_CAN_SHORTEN));
|
||||||
|
|
||||||
ret = mnt_want_write_file(dst_file);
|
ret = mnt_want_write_file(dst_file);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -2115,7 +2127,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
||||||
|
|
||||||
deduped = vfs_dedupe_file_range_one(file, off, dst_file,
|
deduped = vfs_dedupe_file_range_one(file, off, dst_file,
|
||||||
info->dest_offset, len,
|
info->dest_offset, len,
|
||||||
0);
|
REMAP_FILE_CAN_SHORTEN);
|
||||||
if (deduped == -EBADE)
|
if (deduped == -EBADE)
|
||||||
info->status = FILE_DEDUPE_RANGE_DIFFERS;
|
info->status = FILE_DEDUPE_RANGE_DIFFERS;
|
||||||
else if (deduped < 0)
|
else if (deduped < 0)
|
||||||
|
|
|
@ -1727,8 +1727,10 @@ struct block_device_operations;
|
||||||
* See Documentation/filesystems/vfs.txt for more details about this call.
|
* See Documentation/filesystems/vfs.txt for more details about this call.
|
||||||
*
|
*
|
||||||
* REMAP_FILE_DEDUP: only remap if contents identical (i.e. deduplicate)
|
* REMAP_FILE_DEDUP: only remap if contents identical (i.e. deduplicate)
|
||||||
|
* REMAP_FILE_CAN_SHORTEN: caller can handle a shortened request
|
||||||
*/
|
*/
|
||||||
#define REMAP_FILE_DEDUP (1 << 0)
|
#define REMAP_FILE_DEDUP (1 << 0)
|
||||||
|
#define REMAP_FILE_CAN_SHORTEN (1 << 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These flags signal that the caller is ok with altering various aspects of
|
* These flags signal that the caller is ok with altering various aspects of
|
||||||
|
@ -1736,9 +1738,8 @@ struct block_device_operations;
|
||||||
* implementation; the vfs remap helper functions can take advantage of them.
|
* implementation; the vfs remap helper functions can take advantage of them.
|
||||||
* Flags in this category exist to preserve the quirky behavior of the hoisted
|
* Flags in this category exist to preserve the quirky behavior of the hoisted
|
||||||
* btrfs clone/dedupe ioctls.
|
* btrfs clone/dedupe ioctls.
|
||||||
* There are no flags yet, but subsequent commits will add some.
|
|
||||||
*/
|
*/
|
||||||
#define REMAP_FILE_ADVISORY (0)
|
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
|
||||||
|
|
||||||
struct iov_iter;
|
struct iov_iter;
|
||||||
|
|
||||||
|
|
11
mm/filemap.c
11
mm/filemap.c
|
@ -3045,8 +3045,7 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
||||||
bcount = ALIGN(size_in, bs) - pos_in;
|
bcount = ALIGN(size_in, bs) - pos_in;
|
||||||
} else {
|
} else {
|
||||||
if (!IS_ALIGNED(count, bs))
|
if (!IS_ALIGNED(count, bs))
|
||||||
return -EINVAL;
|
count = ALIGN_DOWN(count, bs);
|
||||||
|
|
||||||
bcount = count;
|
bcount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3056,10 +3055,14 @@ int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
||||||
pos_out < pos_in + bcount)
|
pos_out < pos_in + bcount)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* For now we don't support changing the length. */
|
/*
|
||||||
if (*req_count != count)
|
* We shortened the request but the caller can't deal with that, so
|
||||||
|
* bounce the request back to userspace.
|
||||||
|
*/
|
||||||
|
if (*req_count != count && !(remap_flags & REMAP_FILE_CAN_SHORTEN))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
*req_count = count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue