|
@@ -142,55 +142,6 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len,
|
|
return 0;
|
|
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.
|
|
* 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;
|
|
ssize_t ret;
|
|
struct iovec *iov = (struct iovec *)_iov;
|
|
struct iovec *iov = (struct iovec *)_iov;
|
|
size_t total_len;
|
|
size_t total_len;
|
|
|
|
+ struct iov_iter iter;
|
|
|
|
|
|
total_len = iov_length(iov, nr_segs);
|
|
total_len = iov_length(iov, nr_segs);
|
|
/* Null read succeeds. */
|
|
/* Null read succeeds. */
|
|
if (unlikely(total_len == 0))
|
|
if (unlikely(total_len == 0))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ iov_iter_init(&iter, iov, nr_segs, total_len, 0);
|
|
|
|
+
|
|
do_wakeup = 0;
|
|
do_wakeup = 0;
|
|
ret = 0;
|
|
ret = 0;
|
|
__pipe_lock(pipe);
|
|
__pipe_lock(pipe);
|
|
@@ -344,9 +298,9 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
int curbuf = pipe->curbuf;
|
|
int curbuf = pipe->curbuf;
|
|
struct pipe_buffer *buf = pipe->bufs + curbuf;
|
|
struct pipe_buffer *buf = pipe->bufs + curbuf;
|
|
const struct pipe_buf_operations *ops = buf->ops;
|
|
const struct pipe_buf_operations *ops = buf->ops;
|
|
- void *addr;
|
|
|
|
size_t chars = buf->len;
|
|
size_t chars = buf->len;
|
|
- int error, atomic;
|
|
|
|
|
|
+ size_t written;
|
|
|
|
+ int error;
|
|
|
|
|
|
if (chars > total_len)
|
|
if (chars > total_len)
|
|
chars = total_len;
|
|
chars = total_len;
|
|
@@ -358,27 +312,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
break;
|
|
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)
|
|
if (!ret)
|
|
- ret = error;
|
|
|
|
|
|
+ ret = -EFAULT;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
ret += chars;
|
|
ret += chars;
|