mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-20 22:15:59 +00:00
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:
parent
f981c5950f
commit
18022c5d86
4 changed files with 61 additions and 0 deletions
|
@ -160,6 +160,7 @@ enum rq_flag_bits {
|
||||||
__REQ_FLUSH_SEQ, /* request for flush sequence */
|
__REQ_FLUSH_SEQ, /* request for flush sequence */
|
||||||
__REQ_IO_STAT, /* account I/O stat */
|
__REQ_IO_STAT, /* account I/O stat */
|
||||||
__REQ_MIXED_MERGE, /* merge of different types, fail separately */
|
__REQ_MIXED_MERGE, /* merge of different types, fail separately */
|
||||||
|
__REQ_KERNEL, /* direct IO to kernel pages */
|
||||||
__REQ_NR_BITS, /* stops here */
|
__REQ_NR_BITS, /* stops here */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,5 +202,6 @@ enum rq_flag_bits {
|
||||||
#define REQ_IO_STAT (1 << __REQ_IO_STAT)
|
#define REQ_IO_STAT (1 << __REQ_IO_STAT)
|
||||||
#define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE)
|
#define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE)
|
||||||
#define REQ_SECURE (1 << __REQ_SECURE)
|
#define REQ_SECURE (1 << __REQ_SECURE)
|
||||||
|
#define REQ_KERNEL (1 << __REQ_KERNEL)
|
||||||
|
|
||||||
#endif /* __LINUX_BLK_TYPES_H */
|
#endif /* __LINUX_BLK_TYPES_H */
|
||||||
|
|
|
@ -165,6 +165,8 @@ struct inodes_stat_t {
|
||||||
#define READ 0
|
#define READ 0
|
||||||
#define WRITE RW_MASK
|
#define WRITE RW_MASK
|
||||||
#define READA RWA_MASK
|
#define READA RWA_MASK
|
||||||
|
#define KERNEL_READ (READ|REQ_KERNEL)
|
||||||
|
#define KERNEL_WRITE (WRITE|REQ_KERNEL)
|
||||||
|
|
||||||
#define READ_SYNC (READ | REQ_SYNC)
|
#define READ_SYNC (READ | REQ_SYNC)
|
||||||
#define WRITE_SYNC (WRITE | REQ_SYNC | REQ_NOIDLE)
|
#define WRITE_SYNC (WRITE | REQ_SYNC | REQ_NOIDLE)
|
||||||
|
|
|
@ -1019,6 +1019,10 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
|
||||||
struct page **pages, struct vm_area_struct **vmas);
|
struct page **pages, struct vm_area_struct **vmas);
|
||||||
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
|
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
|
||||||
struct page **pages);
|
struct page **pages);
|
||||||
|
struct kvec;
|
||||||
|
int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
|
||||||
|
struct page **pages);
|
||||||
|
int get_kernel_page(unsigned long start, int write, struct page **pages);
|
||||||
struct page *get_dump_page(unsigned long addr);
|
struct page *get_dump_page(unsigned long addr);
|
||||||
|
|
||||||
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
|
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
|
||||||
|
|
53
mm/swap.c
53
mm/swap.c
|
@ -236,6 +236,59 @@ void put_pages_list(struct list_head *pages)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(put_pages_list);
|
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,
|
static void pagevec_lru_move_fn(struct pagevec *pvec,
|
||||||
void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
|
void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
|
||||||
void *arg)
|
void *arg)
|
||||||
|
|
Loading…
Add table
Reference in a new issue