Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51e6ce82 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

Merge branch 'dedupe-cleanup' into overlayfs-next

Following series for stacking overlay files depends on this mini series.
parents 9951934d 1b4f42a1
Loading
Loading
Loading
Loading
+3 −2
Original line number Original line Diff line number Diff line
@@ -3247,8 +3247,9 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
				struct btrfs_ioctl_space_info *space);
				struct btrfs_ioctl_space_info *space);
void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
			       struct btrfs_ioctl_balance_args *bargs);
			       struct btrfs_ioctl_balance_args *bargs);
ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
			   struct file *dst_file, u64 dst_loff);
			    struct file *dst_file, loff_t dst_loff,
			    u64 olen);


/* file.c */
/* file.c */
int __init btrfs_auto_defrag_init(void);
int __init btrfs_auto_defrag_init(void);
+4 −7
Original line number Original line Diff line number Diff line
@@ -3600,13 +3600,13 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
	return ret;
	return ret;
}
}


ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
				struct file *dst_file, u64 dst_loff)
			    struct file *dst_file, loff_t dst_loff,
			    u64 olen)
{
{
	struct inode *src = file_inode(src_file);
	struct inode *src = file_inode(src_file);
	struct inode *dst = file_inode(dst_file);
	struct inode *dst = file_inode(dst_file);
	u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
	u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
	ssize_t res;


	if (WARN_ON_ONCE(bs < PAGE_SIZE)) {
	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;
		return -EINVAL;
	}
	}


	res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
	return btrfs_extent_same(src, src_loff, olen, dst, dst_loff);
	if (res)
		return res;
	return olen;
}
}


static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
+6 −11
Original line number Original line Diff line number Diff line
@@ -2537,19 +2537,14 @@ static int ocfs2_file_clone_range(struct file *file_in,
					 len, false);
					 len, false);
}
}


static ssize_t ocfs2_file_dedupe_range(struct file *src_file,
static int ocfs2_file_dedupe_range(struct file *file_in,
				       u64 loff,
				   loff_t pos_in,
				       u64 len,
				   struct file *file_out,
				       struct file *dst_file,
				   loff_t pos_out,
				       u64 dst_loff)
				   u64 len)
{
{
	int error;
	return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out,

	error = ocfs2_reflink_remap_range(src_file, loff, dst_file, dst_loff,
					  len, true);
					  len, true);
	if (error)
		return error;
	return len;
}
}


const struct inode_operations ocfs2_file_iops = {
const struct inode_operations ocfs2_file_iops = {
+53 −41
Original line number Original line Diff line number Diff line
@@ -1964,6 +1964,44 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
}
}
EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
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)
int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
{
{
	struct file_dedupe_range_info *info;
	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;
	u64 len;
	int i;
	int i;
	int ret;
	int ret;
	bool is_admin = capable(CAP_SYS_ADMIN);
	u16 count = same->dest_count;
	u16 count = same->dest_count;
	struct file *dst_file;
	int deduped;
	loff_t dst_off;
	ssize_t deduped;


	if (!(file->f_mode & FMODE_READ))
	if (!(file->f_mode & FMODE_READ))
		return -EINVAL;
		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))
	if (off + len > i_size_read(src))
		return -EINVAL;
		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 */
	/* pre-format output fields to sane values */
	for (i = 0; i < count; i++) {
	for (i = 0; i < count; i++) {
		same->info[i].bytes_deduped = 0ULL;
		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++) {
	for (i = 0, info = same->info; i < count; i++, info++) {
		struct inode *dst;
		struct fd dst_fd = fdget(info->dest_fd);
		struct fd dst_fd = fdget(info->dest_fd);
		struct file *dst_file = dst_fd.file;


		dst_file = dst_fd.file;
		if (!dst_file) {
		if (!dst_file) {
			info->status = -EBADF;
			info->status = -EBADF;
			goto next_loop;
			goto next_loop;
		}
		}
		dst = file_inode(dst_file);


		ret = mnt_want_write_file(dst_file);
		if (info->reserved) {
		if (ret) {
			info->status = -EINVAL;
			info->status = ret;
			goto next_fdput;
			goto next_fdput;
		}
		}


		dst_off = info->dest_offset;
		deduped = vfs_dedupe_file_range_one(file, off, dst_file,
		ret = clone_verify_area(dst_file, dst_off, len, true);
						    info->dest_offset, len);
		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)
		if (deduped == -EBADE)
			info->status = FILE_DEDUPE_RANGE_DIFFERS;
			info->status = FILE_DEDUPE_RANGE_DIFFERS;
		else if (deduped < 0)
		else if (deduped < 0)
			info->status = deduped;
			info->status = deduped;
		else
		else
				info->bytes_deduped += deduped;
			info->bytes_deduped = len;
		}


next_file:
		mnt_drop_write_file(dst_file);
next_fdput:
next_fdput:
		fdput(dst_fd);
		fdput(dst_fd);
next_loop:
next_loop:
+7 −22
Original line number Original line Diff line number Diff line
@@ -933,31 +933,16 @@ xfs_file_clone_range(
				     len, false);
				     len, false);
}
}


STATIC ssize_t
STATIC int
xfs_file_dedupe_range(
xfs_file_dedupe_range(
	struct file	*src_file,
	struct file	*file_in,
	u64		loff,
	loff_t		pos_in,
	u64		len,
	struct file	*file_out,
	struct file	*dst_file,
	loff_t		pos_out,
	u64		dst_loff)
	u64		len)
{
{
	struct inode	*srci = file_inode(src_file);
	return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
	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,
				     len, true);
				     len, true);
	if (error)
		return error;
	return len;
}
}


STATIC int
STATIC int
Loading