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 Original line Diff line number Diff line
@@ -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.
+3 −3
Original line number Original line 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,
		      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,
+8 −5
Original line number Original line Diff line number Diff line
@@ -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)
+3 −3
Original line number Original line Diff line number Diff line
@@ -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,
+9 −1
Original line number Original line 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)
			     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;
Loading