hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9324 ---------------------------------------- When destroying kmem_cache A races with creating and destroying kmem_cache B which is mergeable with kmem_cache A, kmem_cache A may be destroyed twice, leading to NULL-ptr dereference. The race is as follows. CPU1 CPU2 destroy kmem_cache A create kmem_cache B refcount 1->0 __kmem_cache_alias A refcount 0->1 destroy kmem_cache B refcount 1->0 shutdown_cache shutdown_cache To fix it, check if s->memcg_params.dying is set when dropping refcount to zero, and only destroy the kmem_cache when s->memcg_params.dying isn't set. Fixes: d0ffe36fdd12 ("mm: slab: fix kmem_cache_create failed when sysfs node not destroyed") Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- mm/slab_common.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mm/slab_common.c b/mm/slab_common.c index 89c2bb08a099..ad5b3a2cf2bb 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -837,11 +837,17 @@ static int shutdown_memcg_caches(struct kmem_cache *s) return 0; } -static void memcg_set_kmem_cache_dying(struct kmem_cache *s) +static int memcg_test_and_set_kmem_cache_dying(struct kmem_cache *s) { + int ret; + spin_lock_irq(&memcg_kmem_wq_lock); - s->memcg_params.dying = true; + ret = s->memcg_params.dying; + if (!ret) + s->memcg_params.dying = true; spin_unlock_irq(&memcg_kmem_wq_lock); + + return ret; } static void flush_memcg_workqueue(struct kmem_cache *s) @@ -890,7 +896,9 @@ void kmem_cache_destroy(struct kmem_cache *s) goto out_unlock; #ifdef CONFIG_MEMCG_KMEM - memcg_set_kmem_cache_dying(s); + err = memcg_test_and_set_kmem_cache_dying(s); + if (err) + goto out_unlock; mutex_unlock(&slab_mutex); -- 2.43.0