summaryrefslogtreecommitdiff
path: root/mm/iov_iter.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-03-15 04:05:57 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-05-06 17:32:50 -0400
commit7b2c99d15559e285384c742db52316802e24b0bd (patch)
tree0f5260039ca25431decd1affc281aea5a5da27da /mm/iov_iter.c
parent3320c60b3a26d05666285c55ab08ee043c017ba3 (diff)
new helper: iov_iter_get_pages()
iov_iter_get_pages(iter, pages, maxsize, &start) grabs references pinning the pages of up to maxsize of (contiguous) data from iter. Returns the amount of memory grabbed or -error. In case of success, the requested area begins at offset start in pages[0] and runs through pages[1], etc. Less than requested amount might be returned - either because the contiguous area in the beginning of iterator is smaller than requested, or because the kernel failed to pin that many pages. direct-io.c switched to using iov_iter_get_pages() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm/iov_iter.c')
-rw-r--r--mm/iov_iter.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index e2c9a2db4350..45204cd5ccd8 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -235,3 +235,30 @@ void iov_iter_init(struct iov_iter *i, int direction,
i->count = count;
}
EXPORT_SYMBOL(iov_iter_init);
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+ struct page **pages, size_t maxsize,
+ size_t *start)
+{
+ size_t offset = i->iov_offset;
+ const struct iovec *iov = i->iov;
+ size_t len;
+ unsigned long addr;
+ int n;
+ int res;
+
+ len = iov->iov_len - offset;
+ if (len > i->count)
+ len = i->count;
+ if (len > maxsize)
+ len = maxsize;
+ addr = (unsigned long)iov->iov_base + offset;
+ len += *start = addr & (PAGE_SIZE - 1);
+ addr &= ~(PAGE_SIZE - 1);
+ n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
+ res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+ if (unlikely(res < 0))
+ return res;
+ return (res == n ? len : res * PAGE_SIZE) - *start;
+}
+EXPORT_SYMBOL(iov_iter_get_pages);