Re: [1/4] vmsplice: lift import_iovec() into do_vmsplice()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jun 06, 2018 at 03:57:51PM -0700, Andrei Vagin wrote:
> On Mon, May 28, 2018 at 11:20:10PM +0100, Al Viro wrote:
> > From: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> > 
> > Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
> > ---
> >  fs/splice.c | 69 ++++++++++++++++++++++++++-----------------------------------
> >  1 file changed, 29 insertions(+), 40 deletions(-)
> > 
> > diff --git a/fs/splice.c b/fs/splice.c
> > index 005d09cf3fa8..920ff0b20e53 100644
> > --- a/fs/splice.c
> > +++ b/fs/splice.c
> > @@ -1242,38 +1242,26 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
> >   * For lack of a better implementation, implement vmsplice() to userspace
> >   * as a simple copy of the pipes pages to the user iov.
> >   */
> > -static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
> > -			     unsigned long nr_segs, unsigned int flags)
> > +static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
> > +			     unsigned int flags)
> >  {
> > -	struct pipe_inode_info *pipe;
> > -	struct splice_desc sd;
> > -	long ret;
> > -	struct iovec iovstack[UIO_FASTIOV];
> > -	struct iovec *iov = iovstack;
> > -	struct iov_iter iter;
> > +	struct pipe_inode_info *pipe = get_pipe_info(file);
> > +	struct splice_desc sd = {
> > +		.total_len = iov_iter_count(iter),
> > +		.flags = flags,
> > +		.u.data = iter
> > +	};
> > +	long ret = 0;
> >  
> > -	pipe = get_pipe_info(file);
> >  	if (!pipe)
> >  		return -EBADF;
> >  
> > -	ret = import_iovec(READ, uiov, nr_segs,
> > -			   ARRAY_SIZE(iovstack), &iov, &iter);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	sd.total_len = iov_iter_count(&iter);
> > -	sd.len = 0;
> > -	sd.flags = flags;
> > -	sd.u.data = &iter;
> > -	sd.pos = 0;
> > -
> >  	if (sd.total_len) {
> >  		pipe_lock(pipe);
> >  		ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
> >  		pipe_unlock(pipe);
> >  	}
> >  
> > -	kfree(iov);
> >  	return ret;
> >  }
> >  
> > @@ -1282,14 +1270,11 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
> >   * as splice-from-memory, where the regular splice is splice-from-file (or
> >   * to file). In both cases the output is a pipe, naturally.
> >   */
> > -static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
> > -			     unsigned long nr_segs, unsigned int flags)
> > +static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
> > +			     unsigned int flags)
> >  {
> >  	struct pipe_inode_info *pipe;
> > -	struct iovec iovstack[UIO_FASTIOV];
> > -	struct iovec *iov = iovstack;
> > -	struct iov_iter from;
> > -	long ret;
> > +	long ret = 0;
> >  	unsigned buf_flag = 0;
> >  
> >  	if (flags & SPLICE_F_GIFT)
> > @@ -1299,19 +1284,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
> >  	if (!pipe)
> >  		return -EBADF;
> >  
> > -	ret = import_iovec(WRITE, uiov, nr_segs,
> > -			   ARRAY_SIZE(iovstack), &iov, &from);
> > -	if (ret < 0)
> > -		return ret;
> > -
> >  	pipe_lock(pipe);
> >  	ret = wait_for_space(pipe, flags);
> >  	if (!ret)
> > -		ret = iter_to_pipe(&from, pipe, buf_flag);
> > +		ret = iter_to_pipe(iter, pipe, buf_flag);
> >  	pipe_unlock(pipe);
> >  	if (ret > 0)
> >  		wakeup_pipe_readers(pipe);
> > -	kfree(iov);
> >  	return ret;
> >  }
> >  
> > @@ -1331,29 +1310,39 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
> >   * Currently we punt and implement it as a normal copy, see pipe_to_user().
> >   *
> >   */
> > -static long do_vmsplice(int fd, const struct iovec __user *iov,
> > +static long do_vmsplice(int fd, const struct iovec __user *uiov,
> >  			unsigned long nr_segs, unsigned int flags)
> >  {
> > +	struct iovec iovstack[UIO_FASTIOV];
> > +	struct iovec *iov = iovstack;
> > +	struct iov_iter iter;
> >  	struct fd f;
> >  	long error;
> >  
> >  	if (unlikely(flags & ~SPLICE_F_ALL))
> >  		return -EINVAL;
> > -	if (unlikely(nr_segs > UIO_MAXIOV))
> > -		return -EINVAL;
> > -	else if (unlikely(!nr_segs))
> > +
> > +	error = import_iovec(READ, uiov, nr_segs,
> > +			   ARRAY_SIZE(iovstack), &iov, &iter);
> 
> import_iovec should be called with WRITE, if we are going to call
> vmsplice_to_pipe().

We caught this issue, when we run CRIU tests for
https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git/log/?h=for-next

CRIU fails with errors like this:

pie: 38: Error (criu/pie/parasite.c:89): Can't splice pages to pipe (-14/2/0)

Thanks,
Andrei

> 
> > +	if (error < 0)
> > +		return error;
> > +
> > +	if (!iov_iter_count(&iter)) {
> > +		kfree(iov);
> >  		return 0;
> > +	}
> >  
> >  	error = -EBADF;
> >  	f = fdget(fd);
> >  	if (f.file) {
> >  		if (f.file->f_mode & FMODE_WRITE)
> > -			error = vmsplice_to_pipe(f.file, iov, nr_segs, flags);
> > +			error = vmsplice_to_pipe(f.file, &iter, flags);
> >  		else if (f.file->f_mode & FMODE_READ)
> > -			error = vmsplice_to_user(f.file, iov, nr_segs, flags);
> > +			error = vmsplice_to_user(f.file, &iter, flags);
> >  
> >  		fdput(f);
> >  	}
> > +	kfree(iov);
> >  
> >  	return error;
> >  }



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux