diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2014-02-03 19:11:42 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-01 23:19:22 -0400 |
| commit | 637b58c2887e5e57850865839cc75f59184b23d1 (patch) | |
| tree | 96ea83eabcdc3e37c866eda374d079b40b2d4379 /fs | |
| parent | 74027f4a181754e917853bd1d2e21449f008ab39 (diff) | |
switch pipe_read() to copy_page_to_iter()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/pipe.c | 79 |
1 files changed, 8 insertions, 71 deletions
| @@ -142,55 +142,6 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, | |||
| 142 | return 0; | 142 | return 0; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static int | ||
| 146 | pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len, | ||
| 147 | int atomic) | ||
| 148 | { | ||
| 149 | unsigned long copy; | ||
| 150 | |||
| 151 | while (len > 0) { | ||
| 152 | while (!iov->iov_len) | ||
| 153 | iov++; | ||
| 154 | copy = min_t(unsigned long, len, iov->iov_len); | ||
| 155 | |||
| 156 | if (atomic) { | ||
| 157 | if (__copy_to_user_inatomic(iov->iov_base, from, copy)) | ||
| 158 | return -EFAULT; | ||
| 159 | } else { | ||
| 160 | if (copy_to_user(iov->iov_base, from, copy)) | ||
| 161 | return -EFAULT; | ||
| 162 | } | ||
| 163 | from += copy; | ||
| 164 | len -= copy; | ||
| 165 | iov->iov_base += copy; | ||
| 166 | iov->iov_len -= copy; | ||
| 167 | } | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Attempt to pre-fault in the user memory, so we can use atomic copies. | ||
| 173 | * Returns the number of bytes not faulted in. | ||
| 174 | */ | ||
| 175 | static int iov_fault_in_pages_write(struct iovec *iov, unsigned long len) | ||
| 176 | { | ||
| 177 | while (!iov->iov_len) | ||
| 178 | iov++; | ||
| 179 | |||
| 180 | while (len > 0) { | ||
| 181 | unsigned long this_len; | ||
| 182 | |||
| 183 | this_len = min_t(unsigned long, len, iov->iov_len); | ||
| 184 | if (fault_in_pages_writeable(iov->iov_base, this_len)) | ||
| 185 | break; | ||
| 186 | |||
| 187 | len -= this_len; | ||
| 188 | iov++; | ||
| 189 | } | ||
| 190 | |||
| 191 | return len; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* | 145 | /* |
| 195 | * Pre-fault in the user memory, so we can use atomic copies. | 146 | * Pre-fault in the user memory, so we can use atomic copies. |
| 196 | */ | 147 | */ |
| @@ -329,12 +280,15 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, | |||
| 329 | ssize_t ret; | 280 | ssize_t ret; |
| 330 | struct iovec *iov = (struct iovec *)_iov; | 281 | struct iovec *iov = (struct iovec *)_iov; |
| 331 | size_t total_len; | 282 | size_t total_len; |
| 283 | struct iov_iter iter; | ||
| 332 | 284 | ||
| 333 | total_len = iov_length(iov, nr_segs); | 285 | total_len = iov_length(iov, nr_segs); |
| 334 | /* Null read succeeds. */ | 286 | /* Null read succeeds. */ |
| 335 | if (unlikely(total_len == 0)) | 287 | if (unlikely(total_len == 0)) |
| 336 | return 0; | 288 | return 0; |
| 337 | 289 | ||
| 290 | iov_iter_init(&iter, iov, nr_segs, total_len, 0); | ||
| 291 | |||
| 338 | do_wakeup = 0; | 292 | do_wakeup = 0; |
| 339 | ret = 0; | 293 | ret = 0; |
| 340 | __pipe_lock(pipe); | 294 | __pipe_lock(pipe); |
| @@ -344,9 +298,9 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, | |||
| 344 | int curbuf = pipe->curbuf; | 298 | int curbuf = pipe->curbuf; |
| 345 | struct pipe_buffer *buf = pipe->bufs + curbuf; | 299 | struct pipe_buffer *buf = pipe->bufs + curbuf; |
| 346 | const struct pipe_buf_operations *ops = buf->ops; | 300 | const struct pipe_buf_operations *ops = buf->ops; |
| 347 | void *addr; | ||
| 348 | size_t chars = buf->len; | 301 | size_t chars = buf->len; |
| 349 | int error, atomic; | 302 | size_t written; |
| 303 | int error; | ||
| 350 | 304 | ||
| 351 | if (chars > total_len) | 305 | if (chars > total_len) |
| 352 | chars = total_len; | 306 | chars = total_len; |
| @@ -358,27 +312,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, | |||
| 358 | break; | 312 | break; |
| 359 | } | 313 | } |
| 360 | 314 | ||
| 361 | atomic = !iov_fault_in_pages_write(iov, chars); | 315 | written = copy_page_to_iter(buf->page, buf->offset, chars, &iter); |
| 362 | redo: | 316 | if (unlikely(written < chars)) { |
| 363 | if (atomic) | ||
| 364 | addr = kmap_atomic(buf->page); | ||
| 365 | else | ||
| 366 | addr = kmap(buf->page); | ||
| 367 | error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); | ||
| 368 | if (atomic) | ||
| 369 | kunmap_atomic(addr); | ||
| 370 | else | ||
| 371 | kunmap(buf->page); | ||
| 372 | if (unlikely(error)) { | ||
| 373 | /* | ||
| 374 | * Just retry with the slow path if we failed. | ||
| 375 | */ | ||
| 376 | if (atomic) { | ||
| 377 | atomic = 0; | ||
| 378 | goto redo; | ||
| 379 | } | ||
| 380 | if (!ret) | 317 | if (!ret) |
| 381 | ret = error; | 318 | ret = -EFAULT; |
| 382 | break; | 319 | break; |
| 383 | } | 320 | } |
| 384 | ret += chars; | 321 | ret += chars; |
