]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
slab: fix memory leak when refill_sheaf() fails
authorQing Wang <wangqing7171@gmail.com>
Wed, 11 Mar 2026 09:36:17 +0000 (17:36 +0800)
committerVlastimil Babka (SUSE) <vbabka@kernel.org>
Wed, 11 Mar 2026 16:55:26 +0000 (17:55 +0100)
When refill_sheaf() partially fills one sheaf (e.g., fills 5 objects
but need to fill 10), it will update sheaf->size and return -ENOMEM.
However, the callers (alloc_full_sheaf() and __pcs_replace_empty_main())
directly call free_empty_sheaf() on failure, which only does kfree(sheaf),
causing the partially allocated objects memory in sheaf->objects[] leaked.

Fix this by calling sheaf_flush_unused() before free_empty_sheaf() to
free objects of sheaf->objects[]. And also add a WARN_ON() in
free_empty_sheaf() to catch any future cases where a non-empty sheaf is
being freed.

Fixes: ed30c4adfc2b ("slab: add optimized sheaf refill from partial list")
Signed-off-by: Qing Wang <wangqing7171@gmail.com>
Link: https://patch.msgid.link/20260311093617.4155965-1-wangqing7171@gmail.com
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Reviewed-by: Hao Li <hao.li@linux.dev>
Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
mm/slub.c

index 6371838d2352715ec28fd1e9c89171b66c8b780f..2b2d33cc735cb6a0ad7eacb75fffc0816908a096 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2790,6 +2790,7 @@ static void free_empty_sheaf(struct kmem_cache *s, struct slab_sheaf *sheaf)
        if (s->flags & SLAB_KMALLOC)
                mark_obj_codetag_empty(sheaf);
 
+       VM_WARN_ON_ONCE(sheaf->size > 0);
        kfree(sheaf);
 
        stat(s, SHEAF_FREE);
@@ -2821,6 +2822,7 @@ static int refill_sheaf(struct kmem_cache *s, struct slab_sheaf *sheaf,
        return 0;
 }
 
+static void sheaf_flush_unused(struct kmem_cache *s, struct slab_sheaf *sheaf);
 
 static struct slab_sheaf *alloc_full_sheaf(struct kmem_cache *s, gfp_t gfp)
 {
@@ -2830,6 +2832,7 @@ static struct slab_sheaf *alloc_full_sheaf(struct kmem_cache *s, gfp_t gfp)
                return NULL;
 
        if (refill_sheaf(s, sheaf, gfp | __GFP_NOMEMALLOC | __GFP_NOWARN)) {
+               sheaf_flush_unused(s, sheaf);
                free_empty_sheaf(s, sheaf);
                return NULL;
        }
@@ -4616,6 +4619,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
                         * we must be very low on memory so don't bother
                         * with the barn
                         */
+                       sheaf_flush_unused(s, empty);
                        free_empty_sheaf(s, empty);
                }
        } else {