aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2017-02-22 18:41:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 19:41:27 -0500
commit290b6a58b78be709e734d7fbeb1aa0416d9d41bc (patch)
treecbddb86cb214bc93f6f2c338d284d789a3910172
parentaf3b5f8764a270165195d8b9520d913a268c0062 (diff)
Revert "slub: move synchronize_sched out of slab_mutex on shrink"
Patch series "slab: make memcg slab destruction scalable", v3. With kmem cgroup support enabled, kmem_caches can be created and destroyed frequently and a great number of near empty kmem_caches can accumulate if there are a lot of transient cgroups and the system is not under memory pressure. When memory reclaim starts under such conditions, it can lead to consecutive deactivation and destruction of many kmem_caches, easily hundreds of thousands on moderately large systems, exposing scalability issues in the current slab management code. I've seen machines which end up with hundred thousands of caches and many millions of kernfs_nodes. The current code is O(N^2) on the total number of caches and has synchronous rcu_barrier() and synchronize_sched() in cgroup offline / release path which is executed while holding cgroup_mutex. Combined, this leads to very expensive and slow cache destruction operations which can easily keep running for half a day. This also messes up /proc/slabinfo along with other cache iterating operations. seq_file operates on 4k chunks and on each 4k boundary tries to seek to the last position in the list. With a huge number of caches on the list, this becomes very slow and very prone to the list content changing underneath it leading to a lot of missing and/or duplicate entries. This patchset addresses the scalability problem. * Add root and per-memcg lists. Update each user to use the appropriate list. * Make rcu_barrier() for SLAB_DESTROY_BY_RCU caches globally batched and asynchronous. * For dying empty slub caches, remove the sysfs files after deactivation so that we don't end up with millions of sysfs files without any useful information on them. This patchset contains the following nine patches. 0001-Revert-slub-move-synchronize_sched-out-of-slab_mutex.patch 0002-slub-separate-out-sysfs_slab_release-from-sysfs_slab.patch 0003-slab-remove-synchronous-rcu_barrier-call-in-memcg-ca.patch 0004-slab-reorganize-memcg_cache_params.patch 0005-slab-link-memcg-kmem_caches-on-their-associated-memo.patch 0006-slab-implement-slab_root_caches-list.patch 0007-slab-introduce-__kmemcg_cache_deactivate.patch 0008-slab-remove-synchronous-synchronize_sched-from-memcg.patch 0009-slab-remove-slub-sysfs-interface-files-early-for-emp.patch 0010-slab-use-memcg_kmem_cache_wq-for-slab-destruction-op.patch 0001 reverts an existing optimization to prepare for the following changes. 0002 is a prep patch. 0003 makes rcu_barrier() in release path batched and asynchronous. 0004-0006 separate out the lists. 0007-0008 replace synchronize_sched() in slub destruction path with call_rcu_sched(). 0009 removes sysfs files early for empty dying caches. 0010 makes destruction work items use a workqueue with limited concurrency. This patch (of 10): Revert 89e364db71fb5e ("slub: move synchronize_sched out of slab_mutex on shrink"). With kmem cgroup support enabled, kmem_caches can be created and destroyed frequently and a great number of near empty kmem_caches can accumulate if there are a lot of transient cgroups and the system is not under memory pressure. When memory reclaim starts under such conditions, it can lead to consecutive deactivation and destruction of many kmem_caches, easily hundreds of thousands on moderately large systems, exposing scalability issues in the current slab management code. This is one of the patches to address the issue. Moving synchronize_sched() out of slab_mutex isn't enough as it's still inside cgroup_mutex. The whole deactivation / release path will be updated to avoid all synchronous RCU operations. Revert this insufficient optimization in preparation to ease future changes. Link: http://lkml.kernel.org/r/20170117235411.9408-2-tj@kernel.org Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Jay Vana <jsvana@fb.com> Cc: Vladimir Davydov <vdavydov.dev@gmail.com> Cc: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/slab.c4
-rw-r--r--mm/slab.h2
-rw-r--r--mm/slab_common.c27
-rw-r--r--mm/slob.c2
-rw-r--r--mm/slub.c19
5 files changed, 23 insertions, 31 deletions
diff --git a/mm/slab.c b/mm/slab.c
index be977ef6e718..8a0e3392f181 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2315,7 +2315,7 @@ out:
2315 return nr_freed; 2315 return nr_freed;
2316} 2316}
2317 2317
2318int __kmem_cache_shrink(struct kmem_cache *cachep) 2318int __kmem_cache_shrink(struct kmem_cache *cachep, bool deactivate)
2319{ 2319{
2320 int ret = 0; 2320 int ret = 0;
2321 int node; 2321 int node;
@@ -2335,7 +2335,7 @@ int __kmem_cache_shrink(struct kmem_cache *cachep)
2335 2335
2336int __kmem_cache_shutdown(struct kmem_cache *cachep) 2336int __kmem_cache_shutdown(struct kmem_cache *cachep)
2337{ 2337{
2338 return __kmem_cache_shrink(cachep); 2338 return __kmem_cache_shrink(cachep, false);
2339} 2339}
2340 2340
2341void __kmem_cache_release(struct kmem_cache *cachep) 2341void __kmem_cache_release(struct kmem_cache *cachep)
diff --git a/mm/slab.h b/mm/slab.h
index 2fa824335a50..d07563f37f33 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -167,7 +167,7 @@ static inline unsigned long kmem_cache_flags(unsigned long object_size,
167 167
168int __kmem_cache_shutdown(struct kmem_cache *); 168int __kmem_cache_shutdown(struct kmem_cache *);
169void __kmem_cache_release(struct kmem_cache *); 169void __kmem_cache_release(struct kmem_cache *);
170int __kmem_cache_shrink(struct kmem_cache *); 170int __kmem_cache_shrink(struct kmem_cache *, bool);
171void slab_kmem_cache_release(struct kmem_cache *); 171void slab_kmem_cache_release(struct kmem_cache *);
172 172
173struct seq_file; 173struct seq_file;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index f266b0de1e92..4a999d749d2b 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -582,29 +582,6 @@ void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg)
582 get_online_cpus(); 582 get_online_cpus();
583 get_online_mems(); 583 get_online_mems();
584 584
585#ifdef CONFIG_SLUB
586 /*
587 * In case of SLUB, we need to disable empty slab caching to
588 * avoid pinning the offline memory cgroup by freeable kmem
589 * pages charged to it. SLAB doesn't need this, as it
590 * periodically purges unused slabs.
591 */
592 mutex_lock(&slab_mutex);
593 list_for_each_entry(s, &slab_caches, list) {
594 c = is_root_cache(s) ? cache_from_memcg_idx(s, idx) : NULL;
595 if (c) {
596 c->cpu_partial = 0;
597 c->min_partial = 0;
598 }
599 }
600 mutex_unlock(&slab_mutex);
601 /*
602 * kmem_cache->cpu_partial is checked locklessly (see
603 * put_cpu_partial()). Make sure the change is visible.
604 */
605 synchronize_sched();
606#endif
607
608 mutex_lock(&slab_mutex); 585 mutex_lock(&slab_mutex);
609 list_for_each_entry(s, &slab_caches, list) { 586 list_for_each_entry(s, &slab_caches, list) {
610 if (!is_root_cache(s)) 587 if (!is_root_cache(s))
@@ -616,7 +593,7 @@ void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg)
616 if (!c) 593 if (!c)
617 continue; 594 continue;
618 595
619 __kmem_cache_shrink(c); 596 __kmem_cache_shrink(c, true);
620 arr->entries[idx] = NULL; 597 arr->entries[idx] = NULL;
621 } 598 }
622 mutex_unlock(&slab_mutex); 599 mutex_unlock(&slab_mutex);
@@ -787,7 +764,7 @@ int kmem_cache_shrink(struct kmem_cache *cachep)
787 get_online_cpus(); 764 get_online_cpus();
788 get_online_mems(); 765 get_online_mems();
789 kasan_cache_shrink(cachep); 766 kasan_cache_shrink(cachep);
790 ret = __kmem_cache_shrink(cachep); 767 ret = __kmem_cache_shrink(cachep, false);
791 put_online_mems(); 768 put_online_mems();
792 put_online_cpus(); 769 put_online_cpus();
793 return ret; 770 return ret;
diff --git a/mm/slob.c b/mm/slob.c
index eac04d4357ec..5ec158054ffe 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -634,7 +634,7 @@ void __kmem_cache_release(struct kmem_cache *c)
634{ 634{
635} 635}
636 636
637int __kmem_cache_shrink(struct kmem_cache *d) 637int __kmem_cache_shrink(struct kmem_cache *d, bool deactivate)
638{ 638{
639 return 0; 639 return 0;
640} 640}
diff --git a/mm/slub.c b/mm/slub.c
index 1e5ef312f146..6de08005d9cd 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3891,7 +3891,7 @@ EXPORT_SYMBOL(kfree);
3891 * being allocated from last increasing the chance that the last objects 3891 * being allocated from last increasing the chance that the last objects
3892 * are freed in them. 3892 * are freed in them.
3893 */ 3893 */
3894int __kmem_cache_shrink(struct kmem_cache *s) 3894int __kmem_cache_shrink(struct kmem_cache *s, bool deactivate)
3895{ 3895{
3896 int node; 3896 int node;
3897 int i; 3897 int i;
@@ -3903,6 +3903,21 @@ int __kmem_cache_shrink(struct kmem_cache *s)
3903 unsigned long flags; 3903 unsigned long flags;
3904 int ret = 0; 3904 int ret = 0;
3905 3905
3906 if (deactivate) {
3907 /*
3908 * Disable empty slabs caching. Used to avoid pinning offline
3909 * memory cgroups by kmem pages that can be freed.
3910 */
3911 s->cpu_partial = 0;
3912 s->min_partial = 0;
3913
3914 /*
3915 * s->cpu_partial is checked locklessly (see put_cpu_partial),
3916 * so we have to make sure the change is visible.
3917 */
3918 synchronize_sched();
3919 }
3920
3906 flush_all(s); 3921 flush_all(s);
3907 for_each_kmem_cache_node(s, node, n) { 3922 for_each_kmem_cache_node(s, node, n) {
3908 INIT_LIST_HEAD(&discard); 3923 INIT_LIST_HEAD(&discard);
@@ -3959,7 +3974,7 @@ static int slab_mem_going_offline_callback(void *arg)
3959 3974
3960 mutex_lock(&slab_mutex); 3975 mutex_lock(&slab_mutex);
3961 list_for_each_entry(s, &slab_caches, list) 3976 list_for_each_entry(s, &slab_caches, list)
3962 __kmem_cache_shrink(s); 3977 __kmem_cache_shrink(s, false);
3963 mutex_unlock(&slab_mutex); 3978 mutex_unlock(&slab_mutex);
3964 3979
3965 return 0; 3980 return 0;