aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorShaohua Li <shli@fb.com>2016-12-12 19:41:50 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-06 04:40:15 -0500
commit04597beae7c23ccefd4502c0b9296d68292b807f (patch)
tree7fa485ea6f8b767ed25efbcec43595b099dabedb /mm
parentfe3d462821b02df53e5c99b2c9b059824adbac0a (diff)
mm/vmscan.c: set correct defer count for shrinker
commit 5f33a0803bbd781de916f5c7448cbbbbc763d911 upstream. Our system uses significantly more slab memory with memcg enabled with the latest kernel. With 3.10 kernel, slab uses 2G memory, while with 4.6 kernel, 6G memory is used. The shrinker has problem. Let's see we have two memcg for one shrinker. In do_shrink_slab: 1. Check cg1. nr_deferred = 0, assume total_scan = 700. batch size is 1024, then no memory is freed. nr_deferred = 700 2. Check cg2. nr_deferred = 700. Assume freeable = 20, then total_scan = 10 or 40. Let's assume it's 10. No memory is freed. nr_deferred = 10. The deferred share of cg1 is lost in this case. kswapd will free no memory even run above steps again and again. The fix makes sure one memcg's deferred share isn't lost. Link: http://lkml.kernel.org/r/2414be961b5d25892060315fbb56bb19d81d0c07.1476227351.git.shli@fb.com Signed-off-by: Shaohua Li <shli@fb.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: Vladimir Davydov <vdavydov@parallels.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/vmscan.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d75cdf360730..c4abf08861d2 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -291,6 +291,7 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
291 int nid = shrinkctl->nid; 291 int nid = shrinkctl->nid;
292 long batch_size = shrinker->batch ? shrinker->batch 292 long batch_size = shrinker->batch ? shrinker->batch
293 : SHRINK_BATCH; 293 : SHRINK_BATCH;
294 long scanned = 0, next_deferred;
294 295
295 freeable = shrinker->count_objects(shrinker, shrinkctl); 296 freeable = shrinker->count_objects(shrinker, shrinkctl);
296 if (freeable == 0) 297 if (freeable == 0)
@@ -312,7 +313,9 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
312 pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n", 313 pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n",
313 shrinker->scan_objects, total_scan); 314 shrinker->scan_objects, total_scan);
314 total_scan = freeable; 315 total_scan = freeable;
315 } 316 next_deferred = nr;
317 } else
318 next_deferred = total_scan;
316 319
317 /* 320 /*
318 * We need to avoid excessive windup on filesystem shrinkers 321 * We need to avoid excessive windup on filesystem shrinkers
@@ -369,17 +372,22 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
369 372
370 count_vm_events(SLABS_SCANNED, nr_to_scan); 373 count_vm_events(SLABS_SCANNED, nr_to_scan);
371 total_scan -= nr_to_scan; 374 total_scan -= nr_to_scan;
375 scanned += nr_to_scan;
372 376
373 cond_resched(); 377 cond_resched();
374 } 378 }
375 379
380 if (next_deferred >= scanned)
381 next_deferred -= scanned;
382 else
383 next_deferred = 0;
376 /* 384 /*
377 * move the unused scan count back into the shrinker in a 385 * move the unused scan count back into the shrinker in a
378 * manner that handles concurrent updates. If we exhausted the 386 * manner that handles concurrent updates. If we exhausted the
379 * scan, there is no need to do an update. 387 * scan, there is no need to do an update.
380 */ 388 */
381 if (total_scan > 0) 389 if (next_deferred > 0)
382 new_nr = atomic_long_add_return(total_scan, 390 new_nr = atomic_long_add_return(next_deferred,
383 &shrinker->nr_deferred[nid]); 391 &shrinker->nr_deferred[nid]);
384 else 392 else
385 new_nr = atomic_long_read(&shrinker->nr_deferred[nid]); 393 new_nr = atomic_long_read(&shrinker->nr_deferred[nid]);