diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-03-15 04:05:57 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-05-06 17:32:50 -0400 |
commit | 7b2c99d15559e285384c742db52316802e24b0bd (patch) | |
tree | 0f5260039ca25431decd1affc281aea5a5da27da /mm | |
parent | 3320c60b3a26d05666285c55ab08ee043c017ba3 (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')
-rw-r--r-- | mm/iov_iter.c | 27 |
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, | |||
235 | i->count = count; | 235 | i->count = count; |
236 | } | 236 | } |
237 | EXPORT_SYMBOL(iov_iter_init); | 237 | EXPORT_SYMBOL(iov_iter_init); |
238 | |||
239 | ssize_t iov_iter_get_pages(struct iov_iter *i, | ||
240 | struct page **pages, size_t maxsize, | ||
241 | size_t *start) | ||
242 | { | ||
243 | size_t offset = i->iov_offset; | ||
244 | const struct iovec *iov = i->iov; | ||
245 | size_t len; | ||
246 | unsigned long addr; | ||
247 | int n; | ||
248 | int res; | ||
249 | |||
250 | len = iov->iov_len - offset; | ||
251 | if (len > i->count) | ||
252 | len = i->count; | ||
253 | if (len > maxsize) | ||
254 | len = maxsize; | ||
255 | addr = (unsigned long)iov->iov_base + offset; | ||
256 | len += *start = addr & (PAGE_SIZE - 1); | ||
257 | addr &= ~(PAGE_SIZE - 1); | ||
258 | n = (len + PAGE_SIZE - 1) / PAGE_SIZE; | ||
259 | res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages); | ||
260 | if (unlikely(res < 0)) | ||
261 | return res; | ||
262 | return (res == n ? len : res * PAGE_SIZE) - *start; | ||
263 | } | ||
264 | EXPORT_SYMBOL(iov_iter_get_pages); | ||