add_nr_deferred() is often called with next_deferred equal to 0. For instance, it's happening under low memory pressure for any shrinkers with a low number of cached objects. A corresponding trace looks like: <...>-619914 [005] .... 467456.345160: mm_shrink_slab_end: \ super_cache_scan+0x0/0x1a0 0000000087027f06: nid: 1 \ unused scan count 0 new scan count 0 total_scan 0 \ last shrinker return val 0 <...>-619914 [005] .... 467456.345371: mm_shrink_slab_end: \ super_cache_scan+0x0/0x1a0 0000000087027f06: nid: 1 \ unused scan count 0 new scan count 0 total_scan 0 \ last shrinker return val 0 <...>-619914 [005] .... 467456.345380: mm_shrink_slab_end: \ super_cache_scan+0x0/0x1a0 0000000087027f06: nid: 1 unused \ scan count 0 new scan count 0 total_scan 0 \ last shrinker return val 0 This lead to unnecessary checks and atomic operations, which can be avoided by checking next_deferred for not being zero before calling add_nr_deferred(). In this case the mm_shrink_slab_end trace point will get a potentially slightly outdated "new scan count" value, but it's totally fine. Signed-off-by: Roman Gushchin <roman.gushchin@xxxxxxxxx> --- mm/vmscan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index d4a7d2bd276d..19d3d4fa1aad 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -808,7 +808,10 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, * move the unused scan count back into the shrinker in a * manner that handles concurrent updates. */ - new_nr = add_nr_deferred(next_deferred, shrinker, shrinkctl); + if (next_deferred) + new_nr = add_nr_deferred(next_deferred, shrinker, shrinkctl); + else + new_nr = nr; trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan); return freed; -- 2.35.1