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/pipe.c | |
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/pipe.c')
-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; |