aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pipe.c')
-rw-r--r--fs/pipe.c189
1 files changed, 151 insertions, 38 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index e984beb93a0e..5acd8954aaa0 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -55,7 +55,8 @@ void pipe_wait(struct pipe_inode_info *pipe)
55} 55}
56 56
57static int 57static int
58pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len) 58pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len,
59 int atomic)
59{ 60{
60 unsigned long copy; 61 unsigned long copy;
61 62
@@ -64,8 +65,13 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len)
64 iov++; 65 iov++;
65 copy = min_t(unsigned long, len, iov->iov_len); 66 copy = min_t(unsigned long, len, iov->iov_len);
66 67
67 if (copy_from_user(to, iov->iov_base, copy)) 68 if (atomic) {
68 return -EFAULT; 69 if (__copy_from_user_inatomic(to, iov->iov_base, copy))
70 return -EFAULT;
71 } else {
72 if (copy_from_user(to, iov->iov_base, copy))
73 return -EFAULT;
74 }
69 to += copy; 75 to += copy;
70 len -= copy; 76 len -= copy;
71 iov->iov_base += copy; 77 iov->iov_base += copy;
@@ -75,7 +81,8 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len)
75} 81}
76 82
77static int 83static int
78pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len) 84pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len,
85 int atomic)
79{ 86{
80 unsigned long copy; 87 unsigned long copy;
81 88
@@ -84,8 +91,13 @@ pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len)
84 iov++; 91 iov++;
85 copy = min_t(unsigned long, len, iov->iov_len); 92 copy = min_t(unsigned long, len, iov->iov_len);
86 93
87 if (copy_to_user(iov->iov_base, from, copy)) 94 if (atomic) {
88 return -EFAULT; 95 if (__copy_to_user_inatomic(iov->iov_base, from, copy))
96 return -EFAULT;
97 } else {
98 if (copy_to_user(iov->iov_base, from, copy))
99 return -EFAULT;
100 }
89 from += copy; 101 from += copy;
90 len -= copy; 102 len -= copy;
91 iov->iov_base += copy; 103 iov->iov_base += copy;
@@ -94,13 +106,52 @@ pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len)
94 return 0; 106 return 0;
95} 107}
96 108
109/*
110 * Attempt to pre-fault in the user memory, so we can use atomic copies.
111 * Returns the number of bytes not faulted in.
112 */
113static int iov_fault_in_pages_write(struct iovec *iov, unsigned long len)
114{
115 while (!iov->iov_len)
116 iov++;
117
118 while (len > 0) {
119 unsigned long this_len;
120
121 this_len = min_t(unsigned long, len, iov->iov_len);
122 if (fault_in_pages_writeable(iov->iov_base, this_len))
123 break;
124
125 len -= this_len;
126 iov++;
127 }
128
129 return len;
130}
131
132/*
133 * Pre-fault in the user memory, so we can use atomic copies.
134 */
135static void iov_fault_in_pages_read(struct iovec *iov, unsigned long len)
136{
137 while (!iov->iov_len)
138 iov++;
139
140 while (len > 0) {
141 unsigned long this_len;
142
143 this_len = min_t(unsigned long, len, iov->iov_len);
144 fault_in_pages_readable(iov->iov_base, this_len);
145 len -= this_len;
146 iov++;
147 }
148}
149
97static void anon_pipe_buf_release(struct pipe_inode_info *pipe, 150static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
98 struct pipe_buffer *buf) 151 struct pipe_buffer *buf)
99{ 152{
100 struct page *page = buf->page; 153 struct page *page = buf->page;
101 154
102 buf->flags &= ~PIPE_BUF_FLAG_STOLEN;
103
104 /* 155 /*
105 * If nobody else uses this page, and we don't already have a 156 * If nobody else uses this page, and we don't already have a
106 * temporary page, let's keep track of it as a one-deep 157 * temporary page, let's keep track of it as a one-deep
@@ -112,31 +163,58 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
112 page_cache_release(page); 163 page_cache_release(page);
113} 164}
114 165
115static void * anon_pipe_buf_map(struct file *file, struct pipe_inode_info *pipe, 166void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
116 struct pipe_buffer *buf) 167 struct pipe_buffer *buf, int atomic)
117{ 168{
169 if (atomic) {
170 buf->flags |= PIPE_BUF_FLAG_ATOMIC;
171 return kmap_atomic(buf->page, KM_USER0);
172 }
173
118 return kmap(buf->page); 174 return kmap(buf->page);
119} 175}
120 176
121static void anon_pipe_buf_unmap(struct pipe_inode_info *pipe, 177void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
122 struct pipe_buffer *buf) 178 struct pipe_buffer *buf, void *map_data)
179{
180 if (buf->flags & PIPE_BUF_FLAG_ATOMIC) {
181 buf->flags &= ~PIPE_BUF_FLAG_ATOMIC;
182 kunmap_atomic(map_data, KM_USER0);
183 } else
184 kunmap(buf->page);
185}
186
187int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
188 struct pipe_buffer *buf)
189{
190 struct page *page = buf->page;
191
192 if (page_count(page) == 1) {
193 lock_page(page);
194 return 0;
195 }
196
197 return 1;
198}
199
200void generic_pipe_buf_get(struct pipe_inode_info *info, struct pipe_buffer *buf)
123{ 201{
124 kunmap(buf->page); 202 page_cache_get(buf->page);
125} 203}
126 204
127static int anon_pipe_buf_steal(struct pipe_inode_info *pipe, 205int generic_pipe_buf_pin(struct pipe_inode_info *info, struct pipe_buffer *buf)
128 struct pipe_buffer *buf)
129{ 206{
130 buf->flags |= PIPE_BUF_FLAG_STOLEN;
131 return 0; 207 return 0;
132} 208}
133 209
134static struct pipe_buf_operations anon_pipe_buf_ops = { 210static struct pipe_buf_operations anon_pipe_buf_ops = {
135 .can_merge = 1, 211 .can_merge = 1,
136 .map = anon_pipe_buf_map, 212 .map = generic_pipe_buf_map,
137 .unmap = anon_pipe_buf_unmap, 213 .unmap = generic_pipe_buf_unmap,
214 .pin = generic_pipe_buf_pin,
138 .release = anon_pipe_buf_release, 215 .release = anon_pipe_buf_release,
139 .steal = anon_pipe_buf_steal, 216 .steal = generic_pipe_buf_steal,
217 .get = generic_pipe_buf_get,
140}; 218};
141 219
142static ssize_t 220static ssize_t
@@ -167,22 +245,33 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
167 struct pipe_buf_operations *ops = buf->ops; 245 struct pipe_buf_operations *ops = buf->ops;
168 void *addr; 246 void *addr;
169 size_t chars = buf->len; 247 size_t chars = buf->len;
170 int error; 248 int error, atomic;
171 249
172 if (chars > total_len) 250 if (chars > total_len)
173 chars = total_len; 251 chars = total_len;
174 252
175 addr = ops->map(filp, pipe, buf); 253 error = ops->pin(pipe, buf);
176 if (IS_ERR(addr)) { 254 if (error) {
177 if (!ret) 255 if (!ret)
178 ret = PTR_ERR(addr); 256 error = ret;
179 break; 257 break;
180 } 258 }
181 error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); 259
182 ops->unmap(pipe, buf); 260 atomic = !iov_fault_in_pages_write(iov, chars);
261redo:
262 addr = ops->map(pipe, buf, atomic);
263 error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic);
264 ops->unmap(pipe, buf, addr);
183 if (unlikely(error)) { 265 if (unlikely(error)) {
266 /*
267 * Just retry with the slow path if we failed.
268 */
269 if (atomic) {
270 atomic = 0;
271 goto redo;
272 }
184 if (!ret) 273 if (!ret)
185 ret = -EFAULT; 274 ret = error;
186 break; 275 break;
187 } 276 }
188 ret += chars; 277 ret += chars;
@@ -286,21 +375,28 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
286 int offset = buf->offset + buf->len; 375 int offset = buf->offset + buf->len;
287 376
288 if (ops->can_merge && offset + chars <= PAGE_SIZE) { 377 if (ops->can_merge && offset + chars <= PAGE_SIZE) {
378 int error, atomic = 1;
289 void *addr; 379 void *addr;
290 int error;
291 380
292 addr = ops->map(filp, pipe, buf); 381 error = ops->pin(pipe, buf);
293 if (IS_ERR(addr)) { 382 if (error)
294 error = PTR_ERR(addr);
295 goto out; 383 goto out;
296 } 384
385 iov_fault_in_pages_read(iov, chars);
386redo1:
387 addr = ops->map(pipe, buf, atomic);
297 error = pipe_iov_copy_from_user(offset + addr, iov, 388 error = pipe_iov_copy_from_user(offset + addr, iov,
298 chars); 389 chars, atomic);
299 ops->unmap(pipe, buf); 390 ops->unmap(pipe, buf, addr);
300 ret = error; 391 ret = error;
301 do_wakeup = 1; 392 do_wakeup = 1;
302 if (error) 393 if (error) {
394 if (atomic) {
395 atomic = 0;
396 goto redo1;
397 }
303 goto out; 398 goto out;
399 }
304 buf->len += chars; 400 buf->len += chars;
305 total_len -= chars; 401 total_len -= chars;
306 ret = chars; 402 ret = chars;
@@ -323,7 +419,8 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
323 int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS-1); 419 int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS-1);
324 struct pipe_buffer *buf = pipe->bufs + newbuf; 420 struct pipe_buffer *buf = pipe->bufs + newbuf;
325 struct page *page = pipe->tmp_page; 421 struct page *page = pipe->tmp_page;
326 int error; 422 char *src;
423 int error, atomic = 1;
327 424
328 if (!page) { 425 if (!page) {
329 page = alloc_page(GFP_HIGHUSER); 426 page = alloc_page(GFP_HIGHUSER);
@@ -343,11 +440,27 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
343 if (chars > total_len) 440 if (chars > total_len)
344 chars = total_len; 441 chars = total_len;
345 442
346 error = pipe_iov_copy_from_user(kmap(page), iov, chars); 443 iov_fault_in_pages_read(iov, chars);
347 kunmap(page); 444redo2:
445 if (atomic)
446 src = kmap_atomic(page, KM_USER0);
447 else
448 src = kmap(page);
449
450 error = pipe_iov_copy_from_user(src, iov, chars,
451 atomic);
452 if (atomic)
453 kunmap_atomic(src, KM_USER0);
454 else
455 kunmap(page);
456
348 if (unlikely(error)) { 457 if (unlikely(error)) {
458 if (atomic) {
459 atomic = 0;
460 goto redo2;
461 }
349 if (!ret) 462 if (!ret)
350 ret = -EFAULT; 463 ret = error;
351 break; 464 break;
352 } 465 }
353 ret += chars; 466 ret += chars;