mm/slub.c | 9 +++++++++ 1 file changed, 9 insertions(+)
From: Shengming Hu <hu.shengming@zte.com.cn>
The deferred-freelist path allocates the first object from a fresh slab
before building the freelist for the remaining objects. Unlike the old
path, the selected object is no longer the head of a pre-built freelist,
so its freepointer remains uninitialized.
alloc_debug_processing() still checks its freepointer. As a result,
boot can report:
BUG kmem_cache (Tainted: G B W T ): Freepointer corrupt
Restore the old invariant by storing a valid freepointer in the selected
object before alloc_debug_processing() runs. The pointer is the head of
the leftover freelist, matching what the old pre-built freelist path
would have left in the allocated object.
Fixes: 895272864130 ("mm/slub: defer freelist construction until after bulk allocation from a new slab")
Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
---
mm/slub.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mm/slub.c b/mm/slub.c
index f96bac36229c..af942753d495 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3690,6 +3690,15 @@ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,
needs_add_partial = (slab->objects > 1);
build_slab_freelist(s, slab, &iter);
+ /*
+ * alloc_debug_processing() still checks @object as a free object
+ * before returning it to the caller. Since @object was emitted
+ * directly from a fresh slab and skipped by build_slab_freelist(), give
+ * it the same next pointer it would have had in the old prebuilt
+ * freelist path.
+ */
+ set_freepointer(s, object, slab->freelist);
+
if (!alloc_debug_processing(s, slab, object, orig_size)) {
/*
* It's not really expected that this would fail on a
--
2.25.1
On Thu, Apr 30, 2026 at 04:35:04PM +0800, hu.shengming@zte.com.cn wrote:
> From: Shengming Hu <hu.shengming@zte.com.cn>
>
> The deferred-freelist path allocates the first object from a fresh slab
> before building the freelist for the remaining objects. Unlike the old
> path, the selected object is no longer the head of a pre-built freelist,
> so its freepointer remains uninitialized.
>
> alloc_debug_processing() still checks its freepointer. As a result,
> boot can report:
>
> BUG kmem_cache (Tainted: G B W T ): Freepointer corrupt
>
> Restore the old invariant by storing a valid freepointer in the selected
> object before alloc_debug_processing() runs. The pointer is the head of
> the leftover freelist, matching what the old pre-built freelist path
> would have left in the allocated object.
>
> Fixes: 895272864130 ("mm/slub: defer freelist construction until after bulk allocation from a new slab")
> Reported-by: kernel test robot <oliver.sang@intel.com>
> Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
> Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> ---
When the patch did not land the mainline yet (torvalds/linux), we don't
create a separate fix patch because commiting a broken patch and then
adding a fix for that creates unnecessary history. We can avoid that
as it did not land yet.
Could you please send a v8 of the original patch?
In that case no need for Reported-by: Fixes: Closes: tag.
(But a Link: to the thread would be still nice to add)
> mm/slub.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index f96bac36229c..af942753d495 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -3690,6 +3690,15 @@ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,
> needs_add_partial = (slab->objects > 1);
> build_slab_freelist(s, slab, &iter);
>
> + /*
> + * alloc_debug_processing() still checks @object as a free object
> + * before returning it to the caller. Since @object was emitted
> + * directly from a fresh slab and skipped by build_slab_freelist(), give
> + * it the same next pointer it would have had in the old prebuilt
> + * freelist path.
> + */
This is probably too long ;)
I think one line (something like e.g.,
"/* alloc_debug_processing() always expects a valid free pointer */")
should be enough (and some detail can be included in the changelog
instead)
I was thinking the FP would be NULL but either way looks fine to me.
Thanks for addressing it!
> + set_freepointer(s, object, slab->freelist);
> +
> if (!alloc_debug_processing(s, slab, object, orig_size)) {
> /*
> * It's not really expected that this would fail on a
> --
> 2.25.1
--
Cheers,
Harry / Hyeonggon
Harry wrote:
> On Thu, Apr 30, 2026 at 04:35:04PM +0800, hu.shengming@zte.com.cn wrote:
> > From: Shengming Hu <hu.shengming@zte.com.cn>
> >
> > The deferred-freelist path allocates the first object from a fresh slab
> > before building the freelist for the remaining objects. Unlike the old
> > path, the selected object is no longer the head of a pre-built freelist,
> > so its freepointer remains uninitialized.
> >
> > alloc_debug_processing() still checks its freepointer. As a result,
> > boot can report:
> >
> > BUG kmem_cache (Tainted: G B W T ): Freepointer corrupt
> >
> > Restore the old invariant by storing a valid freepointer in the selected
> > object before alloc_debug_processing() runs. The pointer is the head of
> > the leftover freelist, matching what the old pre-built freelist path
> > would have left in the allocated object.
> >
> > Fixes: 895272864130 ("mm/slub: defer freelist construction until after bulk allocation from a new slab")
> > Reported-by: kernel test robot <oliver.sang@intel.com>
> > Closes: https://lore.kernel.org/oe-lkp/202604301428.e2b8d3dd-lkp@intel.com
> > Signed-off-by: Shengming Hu <hu.shengming@zte.com.cn>
> > ---
>
> When the patch did not land the mainline yet (torvalds/linux), we don't
> create a separate fix patch because commiting a broken patch and then
> adding a fix for that creates unnecessary history. We can avoid that
> as it did not land yet.
>
> Could you please send a v8 of the original patch?
>
> In that case no need for Reported-by: Fixes: Closes: tag.
> (But a Link: to the thread would be still nice to add)
>
OK, I will proceed with sending v8 of the original patch and
include a Link: to the discussion thread.
> > mm/slub.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/mm/slub.c b/mm/slub.c
> > index f96bac36229c..af942753d495 100644
> > --- a/mm/slub.c
> > +++ b/mm/slub.c
> > @@ -3690,6 +3690,15 @@ static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,
> > needs_add_partial = (slab->objects > 1);
> > build_slab_freelist(s, slab, &iter);
> >
> > + /*
> > + * alloc_debug_processing() still checks @object as a free object
> > + * before returning it to the caller. Since @object was emitted
> > + * directly from a fresh slab and skipped by build_slab_freelist(), give
> > + * it the same next pointer it would have had in the old prebuilt
> > + * freelist path.
> > + */
>
> This is probably too long ;)
>
> I think one line (something like e.g.,
> "/* alloc_debug_processing() always expects a valid free pointer */")
> should be enough (and some detail can be included in the changelog
> instead)
>
> I was thinking the FP would be NULL but either way looks fine to me.
>
> Thanks for addressing it!
>
I agree with your suggestion to simplify it. ;-)
Thanks again for the helpful feedback!
> > + set_freepointer(s, object, slab->freelist);
> > +
> > if (!alloc_debug_processing(s, slab, object, orig_size)) {
> > /*
> > * It's not really expected that this would fail on a
> > --
> > 2.25.1
>
> --
> Cheers,
> Harry / Hyeonggon
--
With Best Regards,
Shengming
© 2016 - 2026 Red Hat, Inc.