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

Commit 79fddc4e authored by Al Viro's avatar Al Viro
Browse files

new helper: add_to_pipe()



single-buffer analogue of splice_to_pipe(); vmsplice_to_pipe() switched
to that, leaving splice_to_pipe() only for ->splice_read() instances
(and that only until they are converted as well).

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 8924feff
Loading
Loading
Loading
Loading
+62 −44
Original line number Original line Diff line number Diff line
@@ -203,8 +203,6 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
		buf->len = spd->partial[page_nr].len;
		buf->len = spd->partial[page_nr].len;
		buf->private = spd->partial[page_nr].private;
		buf->private = spd->partial[page_nr].private;
		buf->ops = spd->ops;
		buf->ops = spd->ops;
		if (spd->flags & SPLICE_F_GIFT)
			buf->flags |= PIPE_BUF_FLAG_GIFT;


		pipe->nrbufs++;
		pipe->nrbufs++;
		page_nr++;
		page_nr++;
@@ -225,6 +223,27 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
}
}
EXPORT_SYMBOL_GPL(splice_to_pipe);
EXPORT_SYMBOL_GPL(splice_to_pipe);


ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
{
	int ret;

	if (unlikely(!pipe->readers)) {
		send_sig(SIGPIPE, current, 0);
		ret = -EPIPE;
	} else if (pipe->nrbufs == pipe->buffers) {
		ret = -EAGAIN;
	} else {
		int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
		pipe->bufs[newbuf] = *buf;
		pipe->nrbufs++;
		return buf->len;
	}
	buf->ops->release(pipe, buf);
	buf->ops = NULL;
	return ret;
}
EXPORT_SYMBOL(add_to_pipe);

void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
{
{
	put_page(spd->pages[i]);
	put_page(spd->pages[i]);
@@ -1415,32 +1434,50 @@ static long do_splice(struct file *in, loff_t __user *off_in,
	return -EINVAL;
	return -EINVAL;
}
}


static int get_iovec_page_array(struct iov_iter *from,
static int iter_to_pipe(struct iov_iter *from,
				struct page **pages,
			struct pipe_inode_info *pipe,
				struct partial_page *partial,
			unsigned flags)
				unsigned int pipe_buffers)
{
{
	int buffers = 0;
	struct pipe_buffer buf = {
	while (iov_iter_count(from)) {
		.ops = &user_page_pipe_buf_ops,
		.flags = flags
	};
	size_t total = 0;
	int ret = 0;
	bool failed = false;

	while (iov_iter_count(from) && !failed) {
		struct page *pages[16];
		ssize_t copied;
		ssize_t copied;
		size_t start;
		size_t start;
		int n;


		copied = iov_iter_get_pages(from, pages + buffers, ~0UL,
		copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start);
					pipe_buffers - buffers, &start);
		if (copied <= 0) {
		if (copied <= 0)
			ret = copied;
			return buffers ? buffers : copied;
			break;
		}


		iov_iter_advance(from, copied);
		for (n = 0; copied; n++, start = 0) {
		while (copied) {
			int size = min_t(int, copied, PAGE_SIZE - start);
			int size = min_t(int, copied, PAGE_SIZE - start);
			partial[buffers].offset = start;
			if (!failed) {
			partial[buffers].len = size;
				buf.page = pages[n];
				buf.offset = start;
				buf.len = size;
				ret = add_to_pipe(pipe, &buf);
				if (unlikely(ret < 0)) {
					failed = true;
				} else {
					iov_iter_advance(from, ret);
					total += ret;
				}
			} else {
				put_page(pages[n]);
			}
			copied -= size;
			copied -= size;
			start = 0;
			buffers++;
		}
		}
	}
	}
	return buffers;
	return total ? total : ret;
}
}


static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
@@ -1501,17 +1538,11 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec *iov = iovstack;
	struct iovec *iov = iovstack;
	struct iov_iter from;
	struct iov_iter from;
	struct page *pages[PIPE_DEF_BUFFERS];
	struct partial_page partial[PIPE_DEF_BUFFERS];
	struct splice_pipe_desc spd = {
		.pages = pages,
		.partial = partial,
		.nr_pages_max = PIPE_DEF_BUFFERS,
		.flags = flags,
		.ops = &user_page_pipe_buf_ops,
		.spd_release = spd_release_page,
	};
	long ret;
	long ret;
	unsigned buf_flag = 0;

	if (flags & SPLICE_F_GIFT)
		buf_flag = PIPE_BUF_FLAG_GIFT;


	pipe = get_pipe_info(file);
	pipe = get_pipe_info(file);
	if (!pipe)
	if (!pipe)
@@ -1522,26 +1553,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	if (splice_grow_spd(pipe, &spd)) {
		kfree(iov);
		return -ENOMEM;
	}

	pipe_lock(pipe);
	pipe_lock(pipe);
	ret = wait_for_space(pipe, flags);
	ret = wait_for_space(pipe, flags);
	if (!ret) {
	if (!ret)
		spd.nr_pages = get_iovec_page_array(&from, spd.pages,
		ret = iter_to_pipe(&from, pipe, buf_flag);
						    spd.partial,
						    spd.nr_pages_max);
		if (spd.nr_pages <= 0)
			ret = spd.nr_pages;
		else
			ret = splice_to_pipe(pipe, &spd);
	}
	pipe_unlock(pipe);
	pipe_unlock(pipe);
	if (ret > 0)
	if (ret > 0)
		wakeup_pipe_readers(pipe);
		wakeup_pipe_readers(pipe);
	splice_shrink_spd(&spd);
	kfree(iov);
	kfree(iov);
	return ret;
	return ret;
}
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -72,6 +72,8 @@ extern ssize_t __splice_from_pipe(struct pipe_inode_info *,
				  struct splice_desc *, splice_actor *);
				  struct splice_desc *, splice_actor *);
extern ssize_t splice_to_pipe(struct pipe_inode_info *,
extern ssize_t splice_to_pipe(struct pipe_inode_info *,
			      struct splice_pipe_desc *);
			      struct splice_pipe_desc *);
extern ssize_t add_to_pipe(struct pipe_inode_info *,
			      struct pipe_buffer *);
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
				      splice_direct_actor *);
				      splice_direct_actor *);