Shrinking a huge number of dentries or inodes can hold dcache_lock or
inode_lock for a long time. Not only does this hold off preemption -
holding those locks basically shuts down the whole VFS.
A neat fix for all such caches is to chunk the work up at the
shrink_slab() level.
I made the chunksize pretty small, for scalability reasons - avoid
holding the lock for too long so another CPU can come in, acquire it
and go off to do some work.
do_div(delta, pages + 1);
shrinker->nr += delta;
if (shrinker->nr > SHRINK_BATCH) {
- long nr = shrinker->nr;
+ long nr_to_scan = shrinker->nr;
shrinker->nr = 0;
- (*shrinker->shrinker)(nr, gfp_mask);
+ while (nr_to_scan) {
+ long this_scan = nr_to_scan;
+
+ if (this_scan > 128)
+ this_scan = 128;
+ (*shrinker->shrinker)(this_scan, gfp_mask);
+ nr_to_scan -= this_scan;
+ cond_resched();
+ }
}
}
up(&shrinker_sem);