]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/vmscan.c
Merge branch 'x86-build-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / mm / vmscan.c
index 2f7c6ae8fae07c23c0e539ef97f756448943920e..febbc044e792c427264c908dfe1303ca87ea9c0b 100644 (file)
@@ -253,6 +253,8 @@ unsigned long shrink_slab(struct shrink_control *shrink,
                int shrink_ret = 0;
                long nr;
                long new_nr;
+               long batch_size = shrinker->batch ? shrinker->batch
+                                                 : SHRINK_BATCH;
 
                /*
                 * copy the current shrinker scan count into a local variable
@@ -276,6 +278,21 @@ unsigned long shrink_slab(struct shrink_control *shrink,
                        total_scan = max_pass;
                }
 
+               /*
+                * We need to avoid excessive windup on filesystem shrinkers
+                * due to large numbers of GFP_NOFS allocations causing the
+                * shrinkers to return -1 all the time. This results in a large
+                * nr being built up so when a shrink that can do some work
+                * comes along it empties the entire cache due to nr >>>
+                * max_pass.  This is bad for sustaining a working set in
+                * memory.
+                *
+                * Hence only allow the shrinker to scan the entire cache when
+                * a large delta change is calculated directly.
+                */
+               if (delta < max_pass / 4)
+                       total_scan = min(total_scan, max_pass / 2);
+
                /*
                 * Avoid risking looping forever due to too large nr value:
                 * never try to free more than twice the estimate number of
@@ -288,19 +305,18 @@ unsigned long shrink_slab(struct shrink_control *shrink,
                                        nr_pages_scanned, lru_pages,
                                        max_pass, delta, total_scan);
 
-               while (total_scan >= SHRINK_BATCH) {
-                       long this_scan = SHRINK_BATCH;
+               while (total_scan >= batch_size) {
                        int nr_before;
 
                        nr_before = do_shrinker_shrink(shrinker, shrink, 0);
                        shrink_ret = do_shrinker_shrink(shrinker, shrink,
-                                                       this_scan);
+                                                       batch_size);
                        if (shrink_ret == -1)
                                break;
                        if (shrink_ret < nr_before)
                                ret += nr_before - shrink_ret;
-                       count_vm_events(SLABS_SCANNED, this_scan);
-                       total_scan -= this_scan;
+                       count_vm_events(SLABS_SCANNED, batch_size);
+                       total_scan -= batch_size;
 
                        cond_resched();
                }