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

Commit 42ec3d4c authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Dave Chinner
Browse files

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: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 8dde90bc
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -883,9 +883,9 @@ struct file_operations {
	unsigned (*mmap_capabilities)(struct file *);
#endif
	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,
				u64 len, unsigned int remap_flags);
				   loff_t len, unsigned int remap_flags);
	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
	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
	return value should be zero if all bytes were remapped, or the usual
	negative error code if the remapping did not succeed completely.
	return value should the number of bytes remapped, or the usual
	negative error code if errors occurred before any bytes were remapped.
	The remap_flags parameter accepts REMAP_FILE_* flags.  If
	REMAP_FILE_DEDUP is set then the implementation must only remap if the
	requested file ranges have identical contents.
+3 −3
Original line number Diff line number Diff line
@@ -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,
		      struct extent_state **cached);
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,
			   struct file *file_out, loff_t pos_out, u64 len,
			   unsigned int remap_flags);
loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
			      struct file *file_out, loff_t pos_out,
			      loff_t len, unsigned int remap_flags);

/* tree-defrag.c */
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
+8 −5
Original line number Diff line number Diff line
@@ -4328,10 +4328,12 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
	return ret;
}

int btrfs_remap_file_range(struct file *src_file, loff_t off,
		struct file *dst_file, loff_t destoff, u64 len,
loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
		struct file *dst_file, loff_t destoff, loff_t len,
		unsigned int remap_flags)
{
	int ret;

	if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
		return -EINVAL;

@@ -4349,10 +4351,11 @@ int btrfs_remap_file_range(struct file *src_file, loff_t off,
			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 btrfs_clone_files(dst_file, src_file, off, len, destoff);
	return ret < 0 ? ret : len;
}

static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
+3 −3
Original line number Diff line number Diff line
@@ -975,8 +975,8 @@ const struct inode_operations cifs_symlink_inode_ops = {
	.listxattr = cifs_listxattr,
};

static int cifs_remap_file_range(struct file *src_file, loff_t off,
		struct file *dst_file, loff_t destoff, u64 len,
static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
		struct file *dst_file, loff_t destoff, loff_t len,
		unsigned int remap_flags)
{
	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);
out:
	free_xid(xid);
	return rc;
	return rc < 0 ? rc : len;
}

ssize_t cifs_file_copychunk_range(unsigned int xid,
+9 −1
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
			     u64 off, u64 olen, u64 destoff)
{
	struct fd src_file = fdget(srcfd);
	loff_t cloned;
	int ret;

	if (!src_file.file)
@@ -230,7 +231,14 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
	ret = -EXDEV;
	if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
		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(src_file);
	return ret;
Loading