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: 20+ 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-16 13:50 ` Harry Yoo
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®