forked from Minki/linux
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>
This commit is contained in:
parent
8dde90bca6
commit
42ec3d4c02
@ -883,9 +883,9 @@ struct file_operations {
|
|||||||
unsigned (*mmap_capabilities)(struct file *);
|
unsigned (*mmap_capabilities)(struct file *);
|
||||||
#endif
|
#endif
|
||||||
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int);
|
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int);
|
||||||
int (*remap_file_range)(struct file *file_in, loff_t pos_in,
|
loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 len, unsigned int remap_flags);
|
loff_t len, unsigned int remap_flags);
|
||||||
int (*fadvise)(struct file *, loff_t, loff_t, int);
|
int (*fadvise)(struct file *, loff_t, loff_t, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -966,8 +966,8 @@ otherwise noted.
|
|||||||
implementation should remap len bytes at pos_in of the source file into
|
implementation should remap len bytes at pos_in of the source file into
|
||||||
the dest file at pos_out. Implementations must handle callers passing
|
the dest file at pos_out. Implementations must handle callers passing
|
||||||
in len == 0; this means "remap to the end of the source file". The
|
in len == 0; this means "remap to the end of the source file". The
|
||||||
return value should be zero if all bytes were remapped, or the usual
|
return value should the number of bytes remapped, or the usual
|
||||||
negative error code if the remapping did not succeed completely.
|
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.
|
||||||
|
@ -3247,9 +3247,9 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,
|
|||||||
size_t num_pages, loff_t pos, size_t write_bytes,
|
size_t num_pages, loff_t pos, size_t write_bytes,
|
||||||
struct extent_state **cached);
|
struct extent_state **cached);
|
||||||
int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
|
int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
|
||||||
int btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
|
loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out, u64 len,
|
struct file *file_out, loff_t pos_out,
|
||||||
unsigned int remap_flags);
|
loff_t len, unsigned int remap_flags);
|
||||||
|
|
||||||
/* tree-defrag.c */
|
/* tree-defrag.c */
|
||||||
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||||
|
@ -4328,10 +4328,12 @@ out_unlock:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_remap_file_range(struct file *src_file, loff_t off,
|
loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
|
||||||
struct file *dst_file, loff_t destoff, u64 len,
|
struct file *dst_file, loff_t destoff, loff_t len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -4349,10 +4351,11 @@ int btrfs_remap_file_range(struct file *src_file, loff_t off,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return btrfs_extent_same(src, off, len, dst, destoff);
|
ret = btrfs_extent_same(src, off, len, dst, destoff);
|
||||||
|
} else {
|
||||||
|
ret = btrfs_clone_files(dst_file, src_file, off, len, destoff);
|
||||||
}
|
}
|
||||||
|
return ret < 0 ? ret : len;
|
||||||
return btrfs_clone_files(dst_file, src_file, off, len, destoff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
|
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
|
||||||
|
@ -975,8 +975,8 @@ const struct inode_operations cifs_symlink_inode_ops = {
|
|||||||
.listxattr = cifs_listxattr,
|
.listxattr = cifs_listxattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cifs_remap_file_range(struct file *src_file, loff_t off,
|
static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
|
||||||
struct file *dst_file, loff_t destoff, u64 len,
|
struct file *dst_file, loff_t destoff, loff_t len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *src_inode = file_inode(src_file);
|
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,
|
|||||||
unlock_two_nondirectories(src_inode, target_inode);
|
unlock_two_nondirectories(src_inode, target_inode);
|
||||||
out:
|
out:
|
||||||
free_xid(xid);
|
free_xid(xid);
|
||||||
return rc;
|
return rc < 0 ? rc : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t cifs_file_copychunk_range(unsigned int xid,
|
ssize_t cifs_file_copychunk_range(unsigned int xid,
|
||||||
|
10
fs/ioctl.c
10
fs/ioctl.c
@ -223,6 +223,7 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
|
|||||||
u64 off, u64 olen, u64 destoff)
|
u64 off, u64 olen, u64 destoff)
|
||||||
{
|
{
|
||||||
struct fd src_file = fdget(srcfd);
|
struct fd src_file = fdget(srcfd);
|
||||||
|
loff_t cloned;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!src_file.file)
|
if (!src_file.file)
|
||||||
@ -230,7 +231,14 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
|
|||||||
ret = -EXDEV;
|
ret = -EXDEV;
|
||||||
if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
|
if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
|
||||||
goto fdput;
|
goto fdput;
|
||||||
ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen);
|
cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff,
|
||||||
|
olen);
|
||||||
|
if (cloned < 0)
|
||||||
|
ret = cloned;
|
||||||
|
else if (olen && cloned != olen)
|
||||||
|
ret = -EINVAL;
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
fdput:
|
fdput:
|
||||||
fdput(src_file);
|
fdput(src_file);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -180,8 +180,8 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t
|
|||||||
return nfs42_proc_allocate(filep, offset, len);
|
return nfs42_proc_allocate(filep, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
||||||
struct file *dst_file, loff_t dst_off, u64 count,
|
struct file *dst_file, loff_t dst_off, loff_t count,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *dst_inode = file_inode(dst_file);
|
struct inode *dst_inode = file_inode(dst_file);
|
||||||
@ -244,7 +244,7 @@ out_unlock:
|
|||||||
inode_unlock(src_inode);
|
inode_unlock(src_inode);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret < 0 ? ret : count;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NFS_V4_2 */
|
#endif /* CONFIG_NFS_V4_2 */
|
||||||
|
|
||||||
|
@ -541,8 +541,12 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
__be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
|
__be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
|
||||||
u64 dst_pos, u64 count)
|
u64 dst_pos, u64 count)
|
||||||
{
|
{
|
||||||
return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos,
|
loff_t cloned;
|
||||||
count));
|
|
||||||
|
cloned = vfs_clone_file_range(src, src_pos, dst, dst_pos, count);
|
||||||
|
if (count && cloned != count)
|
||||||
|
cloned = -EINVAL;
|
||||||
|
return nfserrno(cloned < 0 ? cloned : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
|
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
|
||||||
|
@ -2527,18 +2527,18 @@ out:
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ocfs2_remap_file_range(struct file *file_in,
|
static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||||
loff_t pos_in,
|
struct file *file_out, loff_t pos_out,
|
||||||
struct file *file_out,
|
loff_t len, unsigned int remap_flags)
|
||||||
loff_t pos_out,
|
|
||||||
u64 len,
|
|
||||||
unsigned int remap_flags)
|
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
ret = ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
||||||
len, remap_flags);
|
len, remap_flags);
|
||||||
|
return ret < 0 ? ret : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct inode_operations ocfs2_file_iops = {
|
const struct inode_operations ocfs2_file_iops = {
|
||||||
|
@ -4824,7 +4824,7 @@ int ocfs2_reflink_remap_range(struct file *file_in,
|
|||||||
loff_t pos_in,
|
loff_t pos_in,
|
||||||
struct file *file_out,
|
struct file *file_out,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 len,
|
loff_t len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
|
@ -119,7 +119,7 @@ int ocfs2_reflink_remap_range(struct file *file_in,
|
|||||||
loff_t pos_in,
|
loff_t pos_in,
|
||||||
struct file *file_out,
|
struct file *file_out,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 len,
|
loff_t len,
|
||||||
unsigned int remap_flags);
|
unsigned int remap_flags);
|
||||||
|
|
||||||
#endif /* OCFS2_REFCOUNTTREE_H */
|
#endif /* OCFS2_REFCOUNTTREE_H */
|
||||||
|
@ -125,6 +125,7 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
|
|||||||
struct file *new_file;
|
struct file *new_file;
|
||||||
loff_t old_pos = 0;
|
loff_t old_pos = 0;
|
||||||
loff_t new_pos = 0;
|
loff_t new_pos = 0;
|
||||||
|
loff_t cloned;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
@ -141,11 +142,10 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Try to use clone_file_range to clone up within the same fs */
|
/* Try to use clone_file_range to clone up within the same fs */
|
||||||
error = do_clone_file_range(old_file, 0, new_file, 0, len);
|
cloned = do_clone_file_range(old_file, 0, new_file, 0, len);
|
||||||
if (!error)
|
if (cloned == len)
|
||||||
goto out;
|
goto out;
|
||||||
/* Couldn't clone, so now we try to copy the data */
|
/* Couldn't clone, so now we try to copy the data */
|
||||||
error = 0;
|
|
||||||
|
|
||||||
/* FIXME: copy up sparse files efficiently */
|
/* FIXME: copy up sparse files efficiently */
|
||||||
while (len) {
|
while (len) {
|
||||||
|
@ -434,14 +434,14 @@ enum ovl_copyop {
|
|||||||
OVL_DEDUPE,
|
OVL_DEDUPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in,
|
static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 len, unsigned int flags, enum ovl_copyop op)
|
loff_t len, unsigned int flags, enum ovl_copyop op)
|
||||||
{
|
{
|
||||||
struct inode *inode_out = file_inode(file_out);
|
struct inode *inode_out = file_inode(file_out);
|
||||||
struct fd real_in, real_out;
|
struct fd real_in, real_out;
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
ssize_t ret;
|
loff_t ret;
|
||||||
|
|
||||||
ret = ovl_real_fdget(file_out, &real_out);
|
ret = ovl_real_fdget(file_out, &real_out);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -489,9 +489,9 @@ static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||||||
OVL_COPY);
|
OVL_COPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ovl_remap_file_range(struct file *file_in, loff_t pos_in,
|
static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 len, unsigned int remap_flags)
|
loff_t len, unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
enum ovl_copyop op;
|
enum ovl_copyop op;
|
||||||
|
|
||||||
|
@ -1589,10 +1589,13 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||||||
* more efficient if both clone and copy are supported (e.g. NFS).
|
* more efficient if both clone and copy are supported (e.g. NFS).
|
||||||
*/
|
*/
|
||||||
if (file_in->f_op->remap_file_range) {
|
if (file_in->f_op->remap_file_range) {
|
||||||
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
loff_t cloned;
|
||||||
file_out, pos_out, len, 0);
|
|
||||||
if (ret == 0) {
|
cloned = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||||
ret = len;
|
file_out, pos_out,
|
||||||
|
min_t(loff_t, MAX_RW_COUNT, len), 0);
|
||||||
|
if (cloned > 0) {
|
||||||
|
ret = cloned;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1686,11 +1689,12 @@ out2:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int remap_verify_area(struct file *file, loff_t pos, u64 len, bool write)
|
static int remap_verify_area(struct file *file, loff_t pos, loff_t len,
|
||||||
|
bool write)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
|
|
||||||
if (unlikely(pos < 0))
|
if (unlikely(pos < 0 || len < 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (unlikely((loff_t) (pos + len) < 0))
|
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)
|
|||||||
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,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 *len,
|
loff_t *len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
u64 blkmask = i_blocksize(inode_in) - 1;
|
u64 blkmask = i_blocksize(inode_in) - 1;
|
||||||
@ -1747,7 +1751,7 @@ static int generic_remap_check_len(struct inode *inode_in,
|
|||||||
*/
|
*/
|
||||||
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 *len, unsigned int remap_flags)
|
loff_t *len, unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
struct inode *inode_out = file_inode(file_out);
|
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,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(generic_remap_file_range_prep);
|
EXPORT_SYMBOL(generic_remap_file_range_prep);
|
||||||
|
|
||||||
int do_clone_file_range(struct file *file_in, loff_t pos_in,
|
loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out, u64 len)
|
struct file *file_out, loff_t pos_out, loff_t len)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
struct inode *inode_out = file_inode(file_out);
|
struct inode *inode_out = file_inode(file_out);
|
||||||
int ret;
|
loff_t ret;
|
||||||
|
|
||||||
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
|
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
|
||||||
return -EISDIR;
|
return -EISDIR;
|
||||||
@ -1881,19 +1885,19 @@ int do_clone_file_range(struct file *file_in, loff_t pos_in,
|
|||||||
|
|
||||||
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||||
file_out, pos_out, len, 0);
|
file_out, pos_out, len, 0);
|
||||||
if (!ret) {
|
if (ret < 0)
|
||||||
fsnotify_access(file_in);
|
return ret;
|
||||||
fsnotify_modify(file_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fsnotify_access(file_in);
|
||||||
|
fsnotify_modify(file_out);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(do_clone_file_range);
|
EXPORT_SYMBOL(do_clone_file_range);
|
||||||
|
|
||||||
int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
|
loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out, u64 len)
|
struct file *file_out, loff_t pos_out, loff_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
loff_t ret;
|
||||||
|
|
||||||
file_start_write(file_out);
|
file_start_write(file_out);
|
||||||
ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len);
|
ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len);
|
||||||
@ -1999,10 +2003,11 @@ out_error:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
|
EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
|
||||||
|
|
||||||
int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
||||||
struct file *dst_file, loff_t dst_pos, u64 len)
|
struct file *dst_file, loff_t dst_pos,
|
||||||
|
loff_t len)
|
||||||
{
|
{
|
||||||
s64 ret;
|
loff_t ret;
|
||||||
|
|
||||||
ret = mnt_want_write_file(dst_file);
|
ret = mnt_want_write_file(dst_file);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -2051,7 +2056,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
|||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
u16 count = same->dest_count;
|
u16 count = same->dest_count;
|
||||||
int deduped;
|
loff_t deduped;
|
||||||
|
|
||||||
if (!(file->f_mode & FMODE_READ))
|
if (!(file->f_mode & FMODE_READ))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -919,20 +919,23 @@ out_unlock:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC loff_t
|
||||||
xfs_file_remap_range(
|
xfs_file_remap_range(
|
||||||
struct file *file_in,
|
struct file *file_in,
|
||||||
loff_t pos_in,
|
loff_t pos_in,
|
||||||
struct file *file_out,
|
struct file *file_out,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 len,
|
loff_t len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
ret = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
||||||
len, remap_flags);
|
len, remap_flags);
|
||||||
|
return ret < 0 ? ret : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
|
@ -1296,7 +1296,7 @@ xfs_reflink_remap_prep(
|
|||||||
loff_t pos_in,
|
loff_t pos_in,
|
||||||
struct file *file_out,
|
struct file *file_out,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 *len,
|
loff_t *len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
@ -1387,7 +1387,7 @@ xfs_reflink_remap_range(
|
|||||||
loff_t pos_in,
|
loff_t pos_in,
|
||||||
struct file *file_out,
|
struct file *file_out,
|
||||||
loff_t pos_out,
|
loff_t pos_out,
|
||||||
u64 len,
|
loff_t len,
|
||||||
unsigned int remap_flags)
|
unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
|
@ -28,7 +28,7 @@ extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset,
|
|||||||
xfs_off_t count);
|
xfs_off_t count);
|
||||||
extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
|
extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
|
||||||
extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in,
|
extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out, u64 len,
|
struct file *file_out, loff_t pos_out, loff_t len,
|
||||||
unsigned int remap_flags);
|
unsigned int remap_flags);
|
||||||
extern int xfs_reflink_inode_has_shared_extents(struct xfs_trans *tp,
|
extern int xfs_reflink_inode_has_shared_extents(struct xfs_trans *tp,
|
||||||
struct xfs_inode *ip, bool *has_shared);
|
struct xfs_inode *ip, bool *has_shared);
|
||||||
|
@ -1777,9 +1777,9 @@ struct file_operations {
|
|||||||
#endif
|
#endif
|
||||||
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
|
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
|
||||||
loff_t, size_t, unsigned int);
|
loff_t, size_t, unsigned int);
|
||||||
int (*remap_file_range)(struct file *file_in, loff_t pos_in,
|
loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 len, unsigned int remap_flags);
|
loff_t len, unsigned int remap_flags);
|
||||||
int (*fadvise)(struct file *, loff_t, loff_t, int);
|
int (*fadvise)(struct file *, loff_t, loff_t, int);
|
||||||
} __randomize_layout;
|
} __randomize_layout;
|
||||||
|
|
||||||
@ -1844,19 +1844,22 @@ extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
|
|||||||
loff_t, size_t, unsigned int);
|
loff_t, size_t, unsigned int);
|
||||||
extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
u64 *count, unsigned int remap_flags);
|
loff_t *count,
|
||||||
extern int do_clone_file_range(struct file *file_in, loff_t pos_in,
|
unsigned int remap_flags);
|
||||||
struct file *file_out, loff_t pos_out, u64 len);
|
extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||||
extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
|
struct file *file_out, loff_t pos_out,
|
||||||
struct file *file_out, loff_t pos_out, u64 len);
|
loff_t len);
|
||||||
|
extern loff_t vfs_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||||
|
struct file *file_out, loff_t pos_out,
|
||||||
|
loff_t len);
|
||||||
extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
|
extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
|
||||||
struct inode *dest, loff_t destoff,
|
struct inode *dest, loff_t destoff,
|
||||||
loff_t len, bool *is_same);
|
loff_t len, bool *is_same);
|
||||||
extern int vfs_dedupe_file_range(struct file *file,
|
extern int vfs_dedupe_file_range(struct file *file,
|
||||||
struct file_dedupe_range *same);
|
struct file_dedupe_range *same);
|
||||||
extern int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
||||||
struct file *dst_file, loff_t dst_pos,
|
struct file *dst_file, loff_t dst_pos,
|
||||||
u64 len);
|
loff_t len);
|
||||||
|
|
||||||
|
|
||||||
struct super_operations {
|
struct super_operations {
|
||||||
@ -2986,7 +2989,7 @@ extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
|
|||||||
extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *);
|
extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *);
|
||||||
extern int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
extern int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
uint64_t *count, unsigned int remap_flags);
|
loff_t *count, unsigned int remap_flags);
|
||||||
extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
|
extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
|
||||||
extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
||||||
extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
|
||||||
|
@ -2994,7 +2994,7 @@ EXPORT_SYMBOL(generic_write_checks);
|
|||||||
*/
|
*/
|
||||||
int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
int generic_remap_checks(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
uint64_t *req_count, unsigned int remap_flags)
|
loff_t *req_count, unsigned int remap_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode_in = file_in->f_mapping->host;
|
struct inode *inode_in = file_in->f_mapping->host;
|
||||||
struct inode *inode_out = file_out->f_mapping->host;
|
struct inode *inode_out = file_out->f_mapping->host;
|
||||||
|
Loading…
Reference in New Issue
Block a user