aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-03-21 04:58:33 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-05-06 17:32:53 -0400
commit91f79c43d1b54d7154b118860d81b39bad07dfff (patch)
treea5b142ba57fdabf835476b6dbca24288a78f0c53 /mm
parentf67da30c1d5fc9e341bc8121708874bfd7b31e45 (diff)
new helper: iov_iter_get_pages_alloc()
same as iov_iter_get_pages(), except that pages array is allocated (kmalloc if possible, vmalloc if that fails) and left for caller to free. Lustre and NFS ->direct_IO() switched to it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm')
-rw-r--r--mm/iov_iter.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index 0b677f8f9bad..a5c691c1a283 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -1,6 +1,8 @@
1#include <linux/export.h> 1#include <linux/export.h>
2#include <linux/uio.h> 2#include <linux/uio.h>
3#include <linux/pagemap.h> 3#include <linux/pagemap.h>
4#include <linux/slab.h>
5#include <linux/vmalloc.h>
4 6
5size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, 7size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
6 struct iov_iter *i) 8 struct iov_iter *i)
@@ -263,6 +265,44 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
263} 265}
264EXPORT_SYMBOL(iov_iter_get_pages); 266EXPORT_SYMBOL(iov_iter_get_pages);
265 267
268ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
269 struct page ***pages, size_t maxsize,
270 size_t *start)
271{
272 size_t offset = i->iov_offset;
273 const struct iovec *iov = i->iov;
274 size_t len;
275 unsigned long addr;
276 void *p;
277 int n;
278 int res;
279
280 len = iov->iov_len - offset;
281 if (len > i->count)
282 len = i->count;
283 if (len > maxsize)
284 len = maxsize;
285 addr = (unsigned long)iov->iov_base + offset;
286 len += *start = addr & (PAGE_SIZE - 1);
287 addr &= ~(PAGE_SIZE - 1);
288 n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
289
290 p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
291 if (!p)
292 p = vmalloc(n * sizeof(struct page *));
293 if (!p)
294 return -ENOMEM;
295
296 res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
297 if (unlikely(res < 0)) {
298 kvfree(p);
299 return res;
300 }
301 *pages = p;
302 return (res == n ? len : res * PAGE_SIZE) - *start;
303}
304EXPORT_SYMBOL(iov_iter_get_pages_alloc);
305
266int iov_iter_npages(const struct iov_iter *i, int maxpages) 306int iov_iter_npages(const struct iov_iter *i, int maxpages)
267{ 307{
268 size_t offset = i->iov_offset; 308 size_t offset = i->iov_offset;