Commit 234931ab authored by Andrew Morton's avatar Andrew Morton Committed by Jaroslav Kysela

[PATCH] limit pinned memory due to readahead

readahead allocates all the pages before starting I/O.  Potentially bad
if someone is performing huge reads with madvise or sys_readahead().

So the patch just busts that up into two-megabyte units.
parent 67de87c5
...@@ -53,11 +53,8 @@ static inline unsigned long get_min_readahead(struct file_ra_state *ra) ...@@ -53,11 +53,8 @@ static inline unsigned long get_min_readahead(struct file_ra_state *ra)
* *
* Hides the details of the LRU cache etc from the filesystems. * Hides the details of the LRU cache etc from the filesystems.
*/ */
int int read_cache_pages(struct address_space *mapping, struct list_head *pages,
read_cache_pages(struct address_space *mapping, int (*filler)(void *, struct page *), void *data)
struct list_head *pages,
int (*filler)(void *, struct page *),
void *data)
{ {
struct page *page; struct page *page;
struct pagevec lru_pvec; struct pagevec lru_pvec;
...@@ -82,8 +79,7 @@ read_cache_pages(struct address_space *mapping, ...@@ -82,8 +79,7 @@ read_cache_pages(struct address_space *mapping,
return ret; return ret;
} }
static int static int read_pages(struct address_space *mapping, struct file *filp,
read_pages(struct address_space *mapping, struct file *filp,
struct list_head *pages, unsigned nr_pages) struct list_head *pages, unsigned nr_pages)
{ {
unsigned page_idx; unsigned page_idx;
...@@ -184,10 +180,9 @@ read_pages(struct address_space *mapping, struct file *filp, ...@@ -184,10 +180,9 @@ read_pages(struct address_space *mapping, struct file *filp,
* *
* Returns the number of pages which actually had IO started against them. * Returns the number of pages which actually had IO started against them.
*/ */
int do_page_cache_readahead(struct address_space *mapping, static inline int
struct file *filp, __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
unsigned long offset, unsigned long offset, unsigned long nr_to_read)
unsigned long nr_to_read)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct page *page; struct page *page;
...@@ -240,6 +235,30 @@ int do_page_cache_readahead(struct address_space *mapping, ...@@ -240,6 +235,30 @@ int do_page_cache_readahead(struct address_space *mapping,
return ret; return ret;
} }
/*
* Chunk the readahead into 2 megabyte units, so that we don't pin too much
* memory at once.
*/
int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
unsigned long offset, unsigned long nr_to_read)
{
int ret = 0;
while (nr_to_read) {
unsigned long this_chunk = (2 * 1024 * 1024) / PAGE_CACHE_SIZE;
if (this_chunk > nr_to_read)
this_chunk = nr_to_read;
ret = __do_page_cache_readahead(mapping, filp,
offset, this_chunk);
if (ret < 0)
break;
offset += this_chunk;
nr_to_read -= this_chunk;
}
return ret;
}
/* /*
* Check how effective readahead is being. If the amount of started IO is * Check how effective readahead is being. If the amount of started IO is
* less than expected then the file is partly or fully in pagecache and * less than expected then the file is partly or fully in pagecache and
...@@ -267,8 +286,9 @@ check_ra_success(struct file_ra_state *ra, pgoff_t attempt, ...@@ -267,8 +286,9 @@ check_ra_success(struct file_ra_state *ra, pgoff_t attempt,
* page_cache_readahead is the main function. If performs the adaptive * page_cache_readahead is the main function. If performs the adaptive
* readahead window size management and submits the readahead I/O. * readahead window size management and submits the readahead I/O.
*/ */
void page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, void
struct file *filp, unsigned long offset) page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
struct file *filp, unsigned long offset)
{ {
unsigned max; unsigned max;
unsigned min; unsigned min;
...@@ -394,8 +414,9 @@ void page_cache_readahead(struct address_space *mapping, struct file_ra_state *r ...@@ -394,8 +414,9 @@ void page_cache_readahead(struct address_space *mapping, struct file_ra_state *r
* but somewhat ascending. So readaround favours pages beyond the target one. * but somewhat ascending. So readaround favours pages beyond the target one.
* We also boost the window size, as it can easily shrink due to misses. * We also boost the window size, as it can easily shrink due to misses.
*/ */
void page_cache_readaround(struct address_space *mapping, struct file_ra_state *ra, void
struct file *filp, unsigned long offset) page_cache_readaround(struct address_space *mapping, struct file_ra_state *ra,
struct file *filp, unsigned long offset)
{ {
if (ra->next_size != -1UL) { if (ra->next_size != -1UL) {
const unsigned long min = get_min_readahead(ra) * 2; const unsigned long min = get_min_readahead(ra) * 2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment