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

Commit 529565dc authored by Ingo Molnar's avatar Ingo Molnar Committed by Jens Axboe
Browse files

[PATCH] splice: add optional input and output offsets



add optional input and output offsets to sys_splice(), for seekable file
descriptors:

 asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
                            int fd_out, loff_t __user *off_out,
                            size_t len, unsigned int flags);

semantics are straightforward: f_pos will be updated with the offset
provided by user-space, before the splice transfer is about to begin.
Providing a NULL offset pointer means the existing f_pos will be used
(and updated in situ).  Providing an offset for a pipe results in
-ESPIPE. Providing an invalid offset pointer results in -EFAULT.

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarJens Axboe <axboe@suse.de>
parent 3a326a2c
Loading
Loading
Loading
Loading
+41 −13
Original line number Original line Diff line number Diff line
@@ -680,7 +680,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
 * Attempt to initiate a splice from pipe to file.
 * Attempt to initiate a splice from pipe to file.
 */
 */
static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
			   size_t len, unsigned int flags)
			   loff_t __user *off_out, size_t len,
			   unsigned int flags)
{
{
	loff_t pos;
	loff_t pos;
	int ret;
	int ret;
@@ -691,7 +692,11 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
	if (!(out->f_mode & FMODE_WRITE))
	if (!(out->f_mode & FMODE_WRITE))
		return -EBADF;
		return -EBADF;


	if (off_out && copy_from_user(&out->f_pos, off_out, sizeof(loff_t)))
		return -EFAULT;

	pos = out->f_pos;
	pos = out->f_pos;

	ret = rw_verify_area(WRITE, out, &pos, len);
	ret = rw_verify_area(WRITE, out, &pos, len);
	if (unlikely(ret < 0))
	if (unlikely(ret < 0))
		return ret;
		return ret;
@@ -702,8 +707,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
/*
/*
 * Attempt to initiate a splice from a file to a pipe.
 * Attempt to initiate a splice from a file to a pipe.
 */
 */
static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
static long do_splice_to(struct file *in, loff_t __user *off_in,
			 size_t len, unsigned int flags)
			 struct pipe_inode_info *pipe, size_t len,
			 unsigned int flags)
{
{
	loff_t pos, isize, left;
	loff_t pos, isize, left;
	int ret;
	int ret;
@@ -714,7 +720,11 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
	if (!(in->f_mode & FMODE_READ))
	if (!(in->f_mode & FMODE_READ))
		return -EBADF;
		return -EBADF;


	if (off_in && copy_from_user(&in->f_pos, off_in, sizeof(loff_t)))
		return -EFAULT;

	pos = in->f_pos;
	pos = in->f_pos;

	ret = rw_verify_area(READ, in, &pos, len);
	ret = rw_verify_area(READ, in, &pos, len);
	if (unlikely(ret < 0))
	if (unlikely(ret < 0))
		return ret;
		return ret;
@@ -733,23 +743,39 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
/*
/*
 * Determine where to splice to/from.
 * Determine where to splice to/from.
 */
 */
static long do_splice(struct file *in, struct file *out, size_t len,
static long do_splice(struct file *in, loff_t __user *off_in,
		      unsigned int flags)
		      struct file *out, loff_t __user *off_out,
		      size_t len, unsigned int flags)
{
{
	struct pipe_inode_info *pipe;
	struct pipe_inode_info *pipe;


	if (off_out && out->f_op->llseek == no_llseek)
		return -EINVAL;
	if (off_in && in->f_op->llseek == no_llseek)
		return -EINVAL;

	pipe = in->f_dentry->d_inode->i_pipe;
	pipe = in->f_dentry->d_inode->i_pipe;
	if (pipe)
	if (pipe) {
		return do_splice_from(pipe, out, len, flags);
		if (off_in)
			return -ESPIPE;

		return do_splice_from(pipe, out, off_out, len, flags);
	}


	pipe = out->f_dentry->d_inode->i_pipe;
	pipe = out->f_dentry->d_inode->i_pipe;
	if (pipe)
	if (pipe) {
		return do_splice_to(in, pipe, len, flags);
		if (off_out)
			return -ESPIPE;

		return do_splice_to(in, off_in, pipe, len, flags);
	}


	return -EINVAL;
	return -EINVAL;
}
}


asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags)
asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
			   int fd_out, loff_t __user *off_out,
			   size_t len, unsigned int flags)
{
{
	long error;
	long error;
	struct file *in, *out;
	struct file *in, *out;
@@ -759,13 +785,15 @@ asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags)
		return 0;
		return 0;


	error = -EBADF;
	error = -EBADF;
	in = fget_light(fdin, &fput_in);
	in = fget_light(fd_in, &fput_in);
	if (in) {
	if (in) {
		if (in->f_mode & FMODE_READ) {
		if (in->f_mode & FMODE_READ) {
			out = fget_light(fdout, &fput_out);
			out = fget_light(fd_out, &fput_out);
			if (out) {
			if (out) {
				if (out->f_mode & FMODE_WRITE)
				if (out->f_mode & FMODE_WRITE)
					error = do_splice(in, out, len, flags);
					error = do_splice(in, off_in,
							  out, off_out,
							  len, flags);
				fput_light(out, fput_out);
				fput_light(out, fput_out);
			}
			}
		}
		}
+5 −2
Original line number Original line Diff line number Diff line
@@ -569,8 +569,11 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
				   int flags, int mode);
				   int flags, int mode);
asmlinkage long sys_unshare(unsigned long unshare_flags);
asmlinkage long sys_unshare(unsigned long unshare_flags);
asmlinkage long sys_splice(int fdin, int fdout, size_t len,

				unsigned int flags);
asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
			   int fd_out, loff_t __user *off_out,
			   size_t len, unsigned int flags);

asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
					int flags);
					int flags);