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

Commit 637b58c2 authored by Al Viro's avatar Al Viro
Browse files

switch pipe_read() to copy_page_to_iter()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 74027f4a
Loading
Loading
Loading
Loading
+8 −71
Original line number Diff line number Diff line
@@ -142,55 +142,6 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len,
	return 0;
}

static int
pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len,
		      int atomic)
{
	unsigned long copy;

	while (len > 0) {
		while (!iov->iov_len)
			iov++;
		copy = min_t(unsigned long, len, iov->iov_len);

		if (atomic) {
			if (__copy_to_user_inatomic(iov->iov_base, from, copy))
				return -EFAULT;
		} else {
			if (copy_to_user(iov->iov_base, from, copy))
				return -EFAULT;
		}
		from += copy;
		len -= copy;
		iov->iov_base += copy;
		iov->iov_len -= copy;
	}
	return 0;
}

/*
 * Attempt to pre-fault in the user memory, so we can use atomic copies.
 * Returns the number of bytes not faulted in.
 */
static int iov_fault_in_pages_write(struct iovec *iov, unsigned long len)
{
	while (!iov->iov_len)
		iov++;

	while (len > 0) {
		unsigned long this_len;

		this_len = min_t(unsigned long, len, iov->iov_len);
		if (fault_in_pages_writeable(iov->iov_base, this_len))
			break;

		len -= this_len;
		iov++;
	}

	return len;
}

/*
 * Pre-fault in the user memory, so we can use atomic copies.
 */
@@ -329,12 +280,15 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
	ssize_t ret;
	struct iovec *iov = (struct iovec *)_iov;
	size_t total_len;
	struct iov_iter iter;

	total_len = iov_length(iov, nr_segs);
	/* Null read succeeds. */
	if (unlikely(total_len == 0))
		return 0;

	iov_iter_init(&iter, iov, nr_segs, total_len, 0);

	do_wakeup = 0;
	ret = 0;
	__pipe_lock(pipe);
@@ -344,9 +298,9 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
			int curbuf = pipe->curbuf;
			struct pipe_buffer *buf = pipe->bufs + curbuf;
			const struct pipe_buf_operations *ops = buf->ops;
			void *addr;
			size_t chars = buf->len;
			int error, atomic;
			size_t written;
			int error;

			if (chars > total_len)
				chars = total_len;
@@ -358,27 +312,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
				break;
			}

			atomic = !iov_fault_in_pages_write(iov, chars);
redo:
			if (atomic)
				addr = kmap_atomic(buf->page);
			else
				addr = kmap(buf->page);
			error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic);
			if (atomic)
				kunmap_atomic(addr);
			else
				kunmap(buf->page);
			if (unlikely(error)) {
				/*
				 * Just retry with the slow path if we failed.
				 */
				if (atomic) {
					atomic = 0;
					goto redo;
				}
			written = copy_page_to_iter(buf->page, buf->offset, chars, &iter);
			if (unlikely(written < chars)) {
				if (!ret)
					ret = error;
					ret = -EFAULT;
				break;
			}
			ret += chars;