From: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>
To: Hao Li <hao.li@linux.dev>, Pedro Falcato <pfalcato@suse.de>
Cc: harry@kernel.org, akpm@linux-foundation.org, cl@gentwo.org,
rientjes@google.com, roman.gushchin@linux.dev,
linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 2/2] mm/slub: introduce slab parking to reduce list_lock contention
Date: Wed, 16 Sep 2026 10:01:00 +0200 [thread overview]
Message-ID: <23b15032-01c3-43fa-866f-296138228b5a@kernel.org> (raw)
In-Reply-To: <aqPlMzUIw-4g2iOX@fedora>
On 9/11/26 15:06, Hao Li wrote:
> --- >8 ---
> mm/slub: refill prefilled sheaves from the barn
>
> For evaluation.
>
> ---
> mm/slub.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 112 insertions(+), 6 deletions(-)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 27a78d63f537..7d337dbe26a5 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -427,6 +427,8 @@ struct node_barn {
> spinlock_t lock;
> struct list_head sheaves_full;
> struct list_head sheaves_empty;
> + /* leftovers of prefill or refill, protected by barn->lock */
All the fields are protected by the lock so I don't think it's worth
pointing out specifically.
"prefill or refill" sounds like it may include also internal sheaf refill,
which is not the case (but maybe something worth exploring later)
> + struct slab_sheaf *sheaf_partial;
> unsigned int nr_full;
> unsigned int nr_empty;
> };
> @@ -3183,6 +3185,69 @@ static struct slab_sheaf *barn_get_empty_sheaf(struct node_barn *barn,
> return empty;
> }
>
> +/*
> + * Exchange @sheaf, which holds fewer objects than requested, for a full sheaf
> + * from the barn. The objects of @sheaf stay in the barn: it becomes the barn's
> + * partial sheaf, or its objects are merged into the existing one, which becomes
> + * a full sheaf when it reaches capacity. That way the leftovers neither occupy
> + * a full-sheaf count nor have to be flushed.
> + *
> + * Returns NULL if the barn has no full sheaf.
> + */
> +static struct slab_sheaf *barn_replace_partial_sheaf(struct kmem_cache *s,
> + struct node_barn *barn,
> + struct slab_sheaf *sheaf)
> +{
> + struct slab_sheaf *full, *partial;
> + unsigned int to_move;
> + unsigned long flags;
> +
> + if (!data_race(barn->nr_full))
> + return NULL;
> +
> + spin_lock_irqsave(&barn->lock, flags);
> +
> + if (unlikely(!barn->nr_full)) {
> + spin_unlock_irqrestore(&barn->lock, flags);
> + return NULL;
Hmm what if there's no full, but there's sheaf_partial with enough objects
to make a full sheaf together with @sheaf?
> + }
> +
> + full = list_first_entry(&barn->sheaves_full, struct slab_sheaf,
> + barn_list);
> + list_del(&full->barn_list);
> + barn->nr_full--;
> +
> + partial = barn->sheaf_partial;
> + if (partial) {
> + to_move = min(sheaf->size, s->sheaf_capacity - partial->size);
> + sheaf->size -= to_move;
> + memcpy(&partial->objects[partial->size],
> + &sheaf->objects[sheaf->size], to_move * sizeof(void *));
> + partial->size += to_move;
> +
> + if (partial->size == s->sheaf_capacity) {
> + list_add(&partial->barn_list, &barn->sheaves_full);
> + barn->nr_full++;
> + barn->sheaf_partial = NULL;
> + }
> + }
> +
> + if (sheaf->size) {
> + /* no partial sheaf, or it just became full */
> + barn->sheaf_partial = sheaf;
> + } else {
> + list_add(&sheaf->barn_list, &barn->sheaves_empty);
> + barn->nr_empty++;
> + }
> +
> + spin_unlock_irqrestore(&barn->lock, flags);
> +
> + full->capacity = s->sheaf_capacity;
> + full->pfmemalloc = false;
I think this belongs more to the caller which deals with the prefilled
sheaves specifically, and this helper is more low level.
Otherwise LGTM!
> +
> + return full;
> +}
> +
> /*
> * The following two functions are used mainly in cases where we have to undo an
> * intended action due to a race or cpu migration. Thus they do not check the
> @@ -3317,6 +3382,7 @@ static void barn_init(struct node_barn *barn)
> spin_lock_init(&barn->lock);
> INIT_LIST_HEAD(&barn->sheaves_full);
> INIT_LIST_HEAD(&barn->sheaves_empty);
> + barn->sheaf_partial = NULL;
> barn->nr_full = 0;
> barn->nr_empty = 0;
> }
> @@ -3334,6 +3400,10 @@ static void barn_shrink(struct kmem_cache *s, struct node_barn *barn)
> barn->nr_full = 0;
> list_splice_init(&barn->sheaves_empty, &empty_list);
> barn->nr_empty = 0;
> + if (barn->sheaf_partial) {
> + list_add(&barn->sheaf_partial->barn_list, &full_list);
> + barn->sheaf_partial = NULL;
> + }
>
> spin_unlock_irqrestore(&barn->lock, flags);
>
> @@ -5233,12 +5303,49 @@ void *kmem_cache_alloc_node_noprof(struct kmem_cache *s, gfp_t gfpflags, int nod
> }
> EXPORT_SYMBOL(kmem_cache_alloc_node_noprof);
>
> +/*
> + * Refill by swapping *@sheafp for a full sheaf from the barn. The old sheaf and
> + * its objects stay in the barn. Returns true when the new sheaf is full.
> + */
> +static bool refill_sheaf_from_barn(struct kmem_cache *s,
> + struct slab_sheaf **sheafp)
> +{
> + struct node_barn *barn = get_barn(s);
> + struct slab_sheaf *sheaf = *sheafp;
> + struct slab_sheaf *full;
> +
> + /* objects from pfmemalloc slabs must not enter the barn */
> + if (!barn || sheaf->pfmemalloc)
> + return false;
> +
> + full = barn_replace_partial_sheaf(s, barn, sheaf);
> + if (!full)
> + return false;
> +
> + stat(s, BARN_GET);
> + *sheafp = full;
> +
> + /*
> + * The sheaf may hold fewer than capacity objects: rcu_free_sheaf()
> + * puts it in the barn as full even when slab_free_hook() has taken
> + * some out (KFENCE, KASAN). __prefill_sheaf_pfmemalloc() then
> + * continues to refill it.
> + */
> + return full->size == s->sheaf_capacity;
> +}
> +
> static int __prefill_sheaf_pfmemalloc(struct kmem_cache *s,
> - struct slab_sheaf *sheaf, gfp_t gfp)
> + struct slab_sheaf **sheafp, gfp_t gfp)
> {
> + struct slab_sheaf *sheaf;
> gfp_t gfp_nomemalloc;
> int ret;
>
> + if (refill_sheaf_from_barn(s, sheafp))
> + return 0;
> +
> + sheaf = *sheafp;
> +
> gfp_nomemalloc = gfp | __GFP_NOMEMALLOC;
> if (gfp_pfmemalloc_allowed(gfp))
> gfp_nomemalloc |= __GFP_NOWARN;
> @@ -5331,7 +5438,7 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
> sheaf->pfmemalloc = false;
>
> if (sheaf->size < size &&
> - __prefill_sheaf_pfmemalloc(s, sheaf, gfp)) {
> + __prefill_sheaf_pfmemalloc(s, &sheaf, gfp)) {
> sheaf_flush_unused(s, sheaf);
> free_empty_sheaf(s, sheaf);
> sheaf = NULL;
> @@ -5401,11 +5508,10 @@ void kmem_cache_return_sheaf(struct kmem_cache *s, gfp_t gfp,
> * the given size.
> *
> * Return: 0 on success. The sheaf will contain at least @size objects.
> - * The sheaf might have been replaced with a new one if more than
> - * sheaf->capacity objects are requested.
> + * The sheaf might have been replaced with a new one.
> *
> * Return: -ENOMEM on failure. Some objects might have been added to the sheaf
> - * but the sheaf will not be replaced.
> + * and the sheaf might have been replaced.
> *
> * In practice we always refill to full sheaf's capacity.
> */
> @@ -5427,7 +5533,7 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
>
> if (likely(sheaf->capacity >= size)) {
> if (likely(sheaf->capacity == s->sheaf_capacity))
> - return __prefill_sheaf_pfmemalloc(s, sheaf, gfp);
> + return __prefill_sheaf_pfmemalloc(s, sheafp, gfp);
>
> if (!__kmem_cache_alloc_bulk(s, gfp, sheaf->capacity - sheaf->size,
> &sheaf->objects[sheaf->size]))
>
next prev parent reply other threads:[~2026-09-16 8:01 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 12:19 [RFC PATCH 0/2] mm/slub: reduce list_lock contention with slab parking Hao Li
2026-08-24 12:25 ` [RFC PATCH 1/2] mm/slub: make the case handling in __slab_free() easier to follow Hao Li
2026-08-24 12:25 ` [RFC PATCH 2/2] mm/slub: introduce slab parking to reduce list_lock contention Hao Li
2026-09-07 13:38 ` Vlastimil Babka (SUSE)
2026-09-07 16:19 ` Pedro Falcato
2026-09-11 13:06 ` Hao Li
2026-09-15 7:43 ` Vlastimil Babka (SUSE)
2026-09-16 3:05 ` Hao Li
2026-09-16 8:01 ` Vlastimil Babka (SUSE) [this message]
2026-09-17 9:13 ` Hao Li
2026-09-16 13:50 ` Harry Yoo
2026-09-17 9:42 ` Hao Li
2026-09-04 16:04 ` [RFC PATCH 1/2] mm/slub: make the case handling in __slab_free() easier to follow Vlastimil Babka (SUSE)
2026-09-07 2:55 ` Hao Li
2026-09-14 13:39 ` Harry Yoo
2026-09-16 14:00 ` Hao Li
2026-08-27 16:24 ` [RFC PATCH 0/2] mm/slub: reduce list_lock contention with slab parking Pedro Falcato
2026-08-30 14:59 ` Hao Li
2026-09-07 13:44 ` Vlastimil Babka (SUSE)
2026-09-11 11:24 ` Hao Li
2026-09-15 7:10 ` Vlastimil Babka (SUSE)
2026-09-16 12:58 ` Hao Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=23b15032-01c3-43fa-866f-296138228b5a@kernel.org \
--to=vbabka@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=cl@gentwo.org \
--cc=hao.li@linux.dev \
--cc=harry@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pfalcato@suse.de \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.