Commit 654107b9 authored by Andrew Morton's avatar Andrew Morton Committed by Jaroslav Kysela

[PATCH] madvise_willneed() maximum readahead checking

madvise_willneed() currently has a very strange check on how much readahead
it is prepared to do.

  It is based on the user's rss limit.  But this is usually enormous, and
  the user isn't necessarily going to map all that memory at the same time
  anyway.

  And the logic is wrong - it is comparing rss (which is in bytes) with
  `end - start', which is in pages.

  And it returns -EIO on error, which is not mentioned in the Open Group
  spec and doesn't make sense.


This patch takes it all out and applies the same upper limit as is used in
sys_readahead() - half the inactive list.
parent d8259d09
...@@ -516,6 +516,7 @@ void page_cache_readaround(struct address_space *mapping, ...@@ -516,6 +516,7 @@ void page_cache_readaround(struct address_space *mapping,
unsigned long offset); unsigned long offset);
void handle_ra_miss(struct address_space *mapping, void handle_ra_miss(struct address_space *mapping,
struct file_ra_state *ra); struct file_ra_state *ra);
unsigned long max_sane_readahead(unsigned long nr);
/* Do stack extension */ /* Do stack extension */
extern int expand_stack(struct vm_area_struct * vma, unsigned long address); extern int expand_stack(struct vm_area_struct * vma, unsigned long address);
......
...@@ -897,20 +897,10 @@ static ssize_t ...@@ -897,20 +897,10 @@ static ssize_t
do_readahead(struct address_space *mapping, struct file *filp, do_readahead(struct address_space *mapping, struct file *filp,
unsigned long index, unsigned long nr) unsigned long index, unsigned long nr)
{ {
unsigned long max;
unsigned long active;
unsigned long inactive;
if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage)
return -EINVAL; return -EINVAL;
/* Limit it to a sane percentage of the inactive list.. */ do_page_cache_readahead(mapping, filp, index, max_sane_readahead(nr));
get_zone_counts(&active, &inactive);
max = inactive / 2;
if (nr > max)
nr = max;
do_page_cache_readahead(mapping, filp, index, nr);
return 0; return 0;
} }
......
...@@ -51,36 +51,23 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, ...@@ -51,36 +51,23 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
} }
/* /*
* Schedule all required I/O operations, then run the disk queue * Schedule all required I/O operations. Do not wait for completion.
* to make sure they are started. Do not wait for completion.
*/ */
static long madvise_willneed(struct vm_area_struct * vma, static long madvise_willneed(struct vm_area_struct * vma,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ {
long error = -EBADF; struct file *file = vma->vm_file;
struct file * file;
unsigned long size, rlim_rss;
/* Doesn't work if there's no mapped file. */
if (!vma->vm_file) if (!vma->vm_file)
return error; return -EBADF;
file = vma->vm_file;
size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (end > vma->vm_end) if (end > vma->vm_end)
end = vma->vm_end; end = vma->vm_end;
end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
/* Make sure this doesn't exceed the process's max rss. */ do_page_cache_readahead(file->f_dentry->d_inode->i_mapping,
error = -EIO; file, start, max_sane_readahead(end - start));
rlim_rss = current->rlim ? current->rlim[RLIMIT_RSS].rlim_cur :
LONG_MAX; /* default: see resource.h */
if ((vma->vm_mm->rss + (end - start)) > rlim_rss)
return error;
do_page_cache_readahead(file->f_dentry->d_inode->i_mapping, file, start, end - start);
return 0; return 0;
} }
......
...@@ -467,3 +467,16 @@ void handle_ra_miss(struct address_space *mapping, struct file_ra_state *ra) ...@@ -467,3 +467,16 @@ void handle_ra_miss(struct address_space *mapping, struct file_ra_state *ra)
ra->next_size = min; ra->next_size = min;
} }
} }
/*
* Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
* sensible upper limit.
*/
unsigned long max_sane_readahead(unsigned long nr)
{
unsigned long active;
unsigned long inactive;
get_zone_counts(&active, &inactive);
return min(nr, inactive / 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