aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2012-07-31 19:44:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-31 21:42:47 -0400
commit18022c5d8627a7a9ba8097a0f238b513fae6f5b8 (patch)
tree57e0d0ec6a5369c56bd00957eb9c0e1220e62917 /mm
parentf981c5950fa85916ba49bea5d9a7a5078f47e569 (diff)
mm: add get_kernel_page[s] for pinning of kernel addresses for I/O
This patch adds two new APIs get_kernel_pages() and get_kernel_page() that may be used to pin a vector of kernel addresses for IO. The initial user is expected to be NFS for allowing pages to be written to swap using aops->direct_IO(). Strictly speaking, swap-over-NFS only needs to pin one page for IO but it makes sense to express the API in terms of a vector and add a helper for pinning single pages. Signed-off-by: Mel Gorman <mgorman@suse.de> Reviewed-by: Rik van Riel <riel@redhat.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: David S. Miller <davem@davemloft.net> Cc: Eric B Munson <emunson@mgebm.net> Cc: Eric Paris <eparis@redhat.com> Cc: James Morris <jmorris@namei.org> Cc: Mel Gorman <mgorman@suse.de> Cc: Mike Christie <michaelc@cs.wisc.edu> Cc: Neil Brown <neilb@suse.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> Cc: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Xiaotian Feng <dfeng@redhat.com> Cc: Mark Salter <msalter@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/swap.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/mm/swap.c b/mm/swap.c
index 4e7e2ec67078..7d7f80c8044a 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -236,6 +236,59 @@ void put_pages_list(struct list_head *pages)
236} 236}
237EXPORT_SYMBOL(put_pages_list); 237EXPORT_SYMBOL(put_pages_list);
238 238
239/*
240 * get_kernel_pages() - pin kernel pages in memory
241 * @kiov: An array of struct kvec structures
242 * @nr_segs: number of segments to pin
243 * @write: pinning for read/write, currently ignored
244 * @pages: array that receives pointers to the pages pinned.
245 * Should be at least nr_segs long.
246 *
247 * Returns number of pages pinned. This may be fewer than the number
248 * requested. If nr_pages is 0 or negative, returns 0. If no pages
249 * were pinned, returns -errno. Each page returned must be released
250 * with a put_page() call when it is finished with.
251 */
252int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
253 struct page **pages)
254{
255 int seg;
256
257 for (seg = 0; seg < nr_segs; seg++) {
258 if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE))
259 return seg;
260
261 /* virt_to_page sanity checks the PFN */
262 pages[seg] = virt_to_page(kiov[seg].iov_base);
263 page_cache_get(pages[seg]);
264 }
265
266 return seg;
267}
268EXPORT_SYMBOL_GPL(get_kernel_pages);
269
270/*
271 * get_kernel_page() - pin a kernel page in memory
272 * @start: starting kernel address
273 * @write: pinning for read/write, currently ignored
274 * @pages: array that receives pointer to the page pinned.
275 * Must be at least nr_segs long.
276 *
277 * Returns 1 if page is pinned. If the page was not pinned, returns
278 * -errno. The page returned must be released with a put_page() call
279 * when it is finished with.
280 */
281int get_kernel_page(unsigned long start, int write, struct page **pages)
282{
283 const struct kvec kiov = {
284 .iov_base = (void *)start,
285 .iov_len = PAGE_SIZE
286 };
287
288 return get_kernel_pages(&kiov, 1, write, pages);
289}
290EXPORT_SYMBOL_GPL(get_kernel_page);
291
239static void pagevec_lru_move_fn(struct pagevec *pvec, 292static void pagevec_lru_move_fn(struct pagevec *pvec,
240 void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg), 293 void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
241 void *arg) 294 void *arg)