Merge branch 'dedupe-cleanup' into overlayfs-next
Following series for stacking overlay files depends on this mini series.
This commit is contained in:
commit
51e6ce820b
|
@ -3247,8 +3247,9 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
|
|||
struct btrfs_ioctl_space_info *space);
|
||||
void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_balance_args *bargs);
|
||||
ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
|
||||
struct file *dst_file, u64 dst_loff);
|
||||
int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
|
||||
struct file *dst_file, loff_t dst_loff,
|
||||
u64 olen);
|
||||
|
||||
/* file.c */
|
||||
int __init btrfs_auto_defrag_init(void);
|
||||
|
|
|
@ -3600,13 +3600,13 @@ out_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
|
||||
struct file *dst_file, u64 dst_loff)
|
||||
int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
|
||||
struct file *dst_file, loff_t dst_loff,
|
||||
u64 olen)
|
||||
{
|
||||
struct inode *src = file_inode(src_file);
|
||||
struct inode *dst = file_inode(dst_file);
|
||||
u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
|
||||
ssize_t res;
|
||||
|
||||
if (WARN_ON_ONCE(bs < PAGE_SIZE)) {
|
||||
/*
|
||||
|
@ -3617,10 +3617,7 @@ ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
|
||||
if (res)
|
||||
return res;
|
||||
return olen;
|
||||
return btrfs_extent_same(src, src_loff, olen, dst, dst_loff);
|
||||
}
|
||||
|
||||
static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
|
||||
|
|
|
@ -2537,19 +2537,14 @@ static int ocfs2_file_clone_range(struct file *file_in,
|
|||
len, false);
|
||||
}
|
||||
|
||||
static ssize_t ocfs2_file_dedupe_range(struct file *src_file,
|
||||
u64 loff,
|
||||
u64 len,
|
||||
struct file *dst_file,
|
||||
u64 dst_loff)
|
||||
static int ocfs2_file_dedupe_range(struct file *file_in,
|
||||
loff_t pos_in,
|
||||
struct file *file_out,
|
||||
loff_t pos_out,
|
||||
u64 len)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ocfs2_reflink_remap_range(src_file, loff, dst_file, dst_loff,
|
||||
return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
||||
len, true);
|
||||
if (error)
|
||||
return error;
|
||||
return len;
|
||||
}
|
||||
|
||||
const struct inode_operations ocfs2_file_iops = {
|
||||
|
|
|
@ -1964,6 +1964,44 @@ out_error:
|
|||
}
|
||||
EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
|
||||
|
||||
static int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
||||
struct file *dst_file, loff_t dst_pos,
|
||||
u64 len)
|
||||
{
|
||||
s64 ret;
|
||||
|
||||
ret = mnt_want_write_file(dst_file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clone_verify_area(dst_file, dst_pos, len, true);
|
||||
if (ret < 0)
|
||||
goto out_drop_write;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE)))
|
||||
goto out_drop_write;
|
||||
|
||||
ret = -EXDEV;
|
||||
if (src_file->f_path.mnt != dst_file->f_path.mnt)
|
||||
goto out_drop_write;
|
||||
|
||||
ret = -EISDIR;
|
||||
if (S_ISDIR(file_inode(dst_file)->i_mode))
|
||||
goto out_drop_write;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (!dst_file->f_op->dedupe_file_range)
|
||||
goto out_drop_write;
|
||||
|
||||
ret = dst_file->f_op->dedupe_file_range(src_file, src_pos,
|
||||
dst_file, dst_pos, len);
|
||||
out_drop_write:
|
||||
mnt_drop_write_file(dst_file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
||||
{
|
||||
struct file_dedupe_range_info *info;
|
||||
|
@ -1972,11 +2010,8 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
|||
u64 len;
|
||||
int i;
|
||||
int ret;
|
||||
bool is_admin = capable(CAP_SYS_ADMIN);
|
||||
u16 count = same->dest_count;
|
||||
struct file *dst_file;
|
||||
loff_t dst_off;
|
||||
ssize_t deduped;
|
||||
int deduped;
|
||||
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return -EINVAL;
|
||||
|
@ -2003,6 +2038,9 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
|||
if (off + len > i_size_read(src))
|
||||
return -EINVAL;
|
||||
|
||||
/* Arbitrary 1G limit on a single dedupe request, can be raised. */
|
||||
len = min_t(u64, len, 1 << 30);
|
||||
|
||||
/* pre-format output fields to sane values */
|
||||
for (i = 0; i < count; i++) {
|
||||
same->info[i].bytes_deduped = 0ULL;
|
||||
|
@ -2010,54 +2048,28 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
|
|||
}
|
||||
|
||||
for (i = 0, info = same->info; i < count; i++, info++) {
|
||||
struct inode *dst;
|
||||
struct fd dst_fd = fdget(info->dest_fd);
|
||||
struct file *dst_file = dst_fd.file;
|
||||
|
||||
dst_file = dst_fd.file;
|
||||
if (!dst_file) {
|
||||
info->status = -EBADF;
|
||||
goto next_loop;
|
||||
}
|
||||
dst = file_inode(dst_file);
|
||||
|
||||
ret = mnt_want_write_file(dst_file);
|
||||
if (ret) {
|
||||
info->status = ret;
|
||||
goto next_fdput;
|
||||
}
|
||||
|
||||
dst_off = info->dest_offset;
|
||||
ret = clone_verify_area(dst_file, dst_off, len, true);
|
||||
if (ret < 0) {
|
||||
info->status = ret;
|
||||
goto next_file;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
if (info->reserved) {
|
||||
info->status = -EINVAL;
|
||||
} else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
|
||||
info->status = -EINVAL;
|
||||
} else if (file->f_path.mnt != dst_file->f_path.mnt) {
|
||||
info->status = -EXDEV;
|
||||
} else if (S_ISDIR(dst->i_mode)) {
|
||||
info->status = -EISDIR;
|
||||
} else if (dst_file->f_op->dedupe_file_range == NULL) {
|
||||
info->status = -EINVAL;
|
||||
} else {
|
||||
deduped = dst_file->f_op->dedupe_file_range(file, off,
|
||||
len, dst_file,
|
||||
info->dest_offset);
|
||||
if (deduped == -EBADE)
|
||||
info->status = FILE_DEDUPE_RANGE_DIFFERS;
|
||||
else if (deduped < 0)
|
||||
info->status = deduped;
|
||||
else
|
||||
info->bytes_deduped += deduped;
|
||||
goto next_fdput;
|
||||
}
|
||||
|
||||
next_file:
|
||||
mnt_drop_write_file(dst_file);
|
||||
deduped = vfs_dedupe_file_range_one(file, off, dst_file,
|
||||
info->dest_offset, len);
|
||||
if (deduped == -EBADE)
|
||||
info->status = FILE_DEDUPE_RANGE_DIFFERS;
|
||||
else if (deduped < 0)
|
||||
info->status = deduped;
|
||||
else
|
||||
info->bytes_deduped = len;
|
||||
|
||||
next_fdput:
|
||||
fdput(dst_fd);
|
||||
next_loop:
|
||||
|
|
|
@ -933,31 +933,16 @@ xfs_file_clone_range(
|
|||
len, false);
|
||||
}
|
||||
|
||||
STATIC ssize_t
|
||||
STATIC int
|
||||
xfs_file_dedupe_range(
|
||||
struct file *src_file,
|
||||
u64 loff,
|
||||
u64 len,
|
||||
struct file *dst_file,
|
||||
u64 dst_loff)
|
||||
struct file *file_in,
|
||||
loff_t pos_in,
|
||||
struct file *file_out,
|
||||
loff_t pos_out,
|
||||
u64 len)
|
||||
{
|
||||
struct inode *srci = file_inode(src_file);
|
||||
u64 max_dedupe;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Since we have to read all these pages in to compare them, cut
|
||||
* it off at MAX_RW_COUNT/2 rounded down to the nearest block.
|
||||
* That means we won't do more than MAX_RW_COUNT IO per request.
|
||||
*/
|
||||
max_dedupe = (MAX_RW_COUNT >> 1) & ~(i_blocksize(srci) - 1);
|
||||
if (len > max_dedupe)
|
||||
len = max_dedupe;
|
||||
error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff,
|
||||
return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
|
||||
len, true);
|
||||
if (error)
|
||||
return error;
|
||||
return len;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
|
|
|
@ -1751,7 +1751,7 @@ struct file_operations {
|
|||
loff_t, size_t, unsigned int);
|
||||
int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
|
||||
u64);
|
||||
ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
|
||||
int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t,
|
||||
u64);
|
||||
} __randomize_layout;
|
||||
|
||||
|
|
Loading…
Reference in New Issue