mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
switch pipe_read() to copy_page_to_iter()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
74027f4a18
commit
637b58c288
1 changed files with 8 additions and 71 deletions
79
fs/pipe.c
79
fs/pipe.c
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue