aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/vmscan.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 078cf920208a..b0cd81c32de6 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -201,13 +201,25 @@ static int shrink_slab(unsigned long scanned, gfp_t gfp_mask,
201 list_for_each_entry(shrinker, &shrinker_list, list) { 201 list_for_each_entry(shrinker, &shrinker_list, list) {
202 unsigned long long delta; 202 unsigned long long delta;
203 unsigned long total_scan; 203 unsigned long total_scan;
204 unsigned long max_pass = (*shrinker->shrinker)(0, gfp_mask);
204 205
205 delta = (4 * scanned) / shrinker->seeks; 206 delta = (4 * scanned) / shrinker->seeks;
206 delta *= (*shrinker->shrinker)(0, gfp_mask); 207 delta *= max_pass;
207 do_div(delta, lru_pages + 1); 208 do_div(delta, lru_pages + 1);
208 shrinker->nr += delta; 209 shrinker->nr += delta;
209 if (shrinker->nr < 0) 210 if (shrinker->nr < 0) {
210 shrinker->nr = LONG_MAX; /* It wrapped! */ 211 printk(KERN_ERR "%s: nr=%ld\n",
212 __FUNCTION__, shrinker->nr);
213 shrinker->nr = max_pass;
214 }
215
216 /*
217 * Avoid risking looping forever due to too large nr value:
218 * never try to free more than twice the estimate number of
219 * freeable entries.
220 */
221 if (shrinker->nr > max_pass * 2)
222 shrinker->nr = max_pass * 2;
211 223
212 total_scan = shrinker->nr; 224 total_scan = shrinker->nr;
213 shrinker->nr = 0; 225 shrinker->nr = 0;