Commit 6f5bd3c5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Fix dcache and icache bloat with deep directories

This fixes the recently-reported "fsstress memory leak" problem.  It has been
there since November 2002.

shrink_dcache() has a heuristic to prevent the dcache (and hence icache) from
getting shrunk too far: it refuses to allow the dcache to shrink below
2*nr_used.

Problem is, _all_ non-leaf dentries (directories) count as used.  So when you
have really deep directory hierarchies (fsstress creates these), nr_used is
really high, and there is no upper bound to the amount of pinned dcache.

The patch just rips out the heuristic.  This means that dcache (and hence
icache (and hence pagecache)) will be shrunk more aggressively.  This could
be a problem, and tons of testing is needed - a new heuristic may be needed.

However I am not able to reproduce the problem which cause me to add this
heuristic in the first place:

   Simple testcase: run a huge `dd' while running a concurrent `watch -n1
   cat /proc/meminfo'.  The program text for `cat' gets loaded from disk once
   per second.
parent a61f9729
...@@ -639,24 +639,9 @@ void shrink_dcache_anon(struct hlist_head *head) ...@@ -639,24 +639,9 @@ void shrink_dcache_anon(struct hlist_head *head)
/* /*
* This is called from kswapd when we think we need some more memory. * This is called from kswapd when we think we need some more memory.
*
* We don't want the VM to steal _all_ unused dcache. Because that leads to
* the VM stealing all unused inodes, which shoots down recently-used
* pagecache. So what we do is to tell fibs to the VM about how many reapable
* objects there are in this cache. If the number of unused dentries is
* less than half of the total dentry count then return zero. The net effect
* is that the number of unused dentries will be, at a minimum, equal to the
* number of used ones.
*
* If unused_ratio is set to 5, the number of unused dentries will not fall
* below 5* the number of used ones.
*/ */
static int shrink_dcache_memory(int nr, unsigned int gfp_mask) static int shrink_dcache_memory(int nr, unsigned int gfp_mask)
{ {
int nr_used;
int nr_unused;
const int unused_ratio = 1;
if (nr) { if (nr) {
/* /*
* Nasty deadlock avoidance. * Nasty deadlock avoidance.
...@@ -672,11 +657,7 @@ static int shrink_dcache_memory(int nr, unsigned int gfp_mask) ...@@ -672,11 +657,7 @@ static int shrink_dcache_memory(int nr, unsigned int gfp_mask)
if (gfp_mask & __GFP_FS) if (gfp_mask & __GFP_FS)
prune_dcache(nr); prune_dcache(nr);
} }
nr_unused = dentry_stat.nr_unused; return dentry_stat.nr_unused;
nr_used = dentry_stat.nr_dentry - nr_unused;
if (nr_unused < nr_used * unused_ratio)
return 0;
return nr_unused - nr_used * unused_ratio;
} }
#define NAME_ALLOC_LEN(len) ((len+16) & ~15) #define NAME_ALLOC_LEN(len) ((len+16) & ~15)
......
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