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>
This commit is contained in:
Mel Gorman
2012-07-31 16:44:51 -07:00
zatwierdzone przez Linus Torvalds
rodzic f981c5950f
commit 18022c5d86
4 zmienionych plików z 61 dodań i 0 usunięć

Wyświetl plik

@@ -236,6 +236,59 @@ void put_pages_list(struct list_head *pages)
}
EXPORT_SYMBOL(put_pages_list);
/*
* get_kernel_pages() - pin kernel pages in memory
* @kiov: An array of struct kvec structures
* @nr_segs: number of segments to pin
* @write: pinning for read/write, currently ignored
* @pages: array that receives pointers to the pages pinned.
* Should be at least nr_segs long.
*
* Returns number of pages pinned. This may be fewer than the number
* requested. If nr_pages is 0 or negative, returns 0. If no pages
* were pinned, returns -errno. Each page returned must be released
* with a put_page() call when it is finished with.
*/
int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
struct page **pages)
{
int seg;
for (seg = 0; seg < nr_segs; seg++) {
if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE))
return seg;
/* virt_to_page sanity checks the PFN */
pages[seg] = virt_to_page(kiov[seg].iov_base);
page_cache_get(pages[seg]);
}
return seg;
}
EXPORT_SYMBOL_GPL(get_kernel_pages);
/*
* get_kernel_page() - pin a kernel page in memory
* @start: starting kernel address
* @write: pinning for read/write, currently ignored
* @pages: array that receives pointer to the page pinned.
* Must be at least nr_segs long.
*
* Returns 1 if page is pinned. If the page was not pinned, returns
* -errno. The page returned must be released with a put_page() call
* when it is finished with.
*/
int get_kernel_page(unsigned long start, int write, struct page **pages)
{
const struct kvec kiov = {
.iov_base = (void *)start,
.iov_len = PAGE_SIZE
};
return get_kernel_pages(&kiov, 1, write, pages);
}
EXPORT_SYMBOL_GPL(get_kernel_page);
static void pagevec_lru_move_fn(struct pagevec *pvec,
void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
void *arg)