From: Marcelo Tosatti <mtosatti@redhat.com>
To: linux-kernel@vger.kernel.org, linux-mm@kvack.org
Cc: Johannes Weiner <hannes@cmpxchg.org>,
Michal Hocko <mhocko@kernel.org>,
Roman Gushchin <roman.gushchin@linux.dev>,
Shakeel Butt <shakeel.butt@linux.dev>,
Muchun Song <muchun.song@linux.dev>,
Andrew Morton <akpm@linux-foundation.org>,
Christoph Lameter <cl@linux.com>,
Pekka Enberg <penberg@kernel.org>,
David Rientjes <rientjes@google.com>,
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
Vlastimil Babka <vbabka@suse.cz>,
Hyeonggon Yoo <42.hyeyoo@gmail.com>,
Leonardo Bras <leobras.c@gmail.com>,
Thomas Gleixner <tglx@linutronix.de>,
Waiman Long <longman@redhat.com>,
Boqun Feun <boqun.feng@gmail.com>,
Frederic Weisbecker <frederic@kernel.org>,
Marcelo Tosatti <mtosatti@redhat.com>
Subject: [PATCH v2 5/5] slub: apply new queue_percpu_work_on() interface
Date: Mon, 02 Mar 2026 12:49:50 -0300 [thread overview]
Message-ID: <20260302155105.306721019@redhat.com> (raw)
In-Reply-To: 20260302154945.143996316@redhat.com
Make use of the new qpw_{un,}lock*() and queue_percpu_work_on()
interface to improve performance & latency.
For functions that may be scheduled in a different cpu, replace
local_{un,}lock*() by qpw_{un,}lock*(), and replace schedule_work_on() by
queue_percpu_work_on(). The same happens for flush_work() and
flush_percpu_work().
This change requires allocation of qpw_structs instead of a work_structs,
and changing parameters of a few functions to include the cpu parameter.
This should bring no relevant performance impact on non-QPW kernels:
For functions that may be scheduled in a different cpu, the local_*lock's
this_cpu_ptr() becomes a per_cpu_ptr(smp_processor_id()).
Signed-off-by: Leonardo Bras <leobras.c@gmail.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
mm/slub.c | 146 +++++++++++++++++++++++++++++++-------------------------------
1 file changed, 74 insertions(+), 72 deletions(-)
Index: linux/mm/slub.c
===================================================================
--- linux.orig/mm/slub.c
+++ linux/mm/slub.c
@@ -50,6 +50,7 @@
#include <linux/irq_work.h>
#include <linux/kprobes.h>
#include <linux/debugfs.h>
+#include <linux/qpw.h>
#include <trace/events/kmem.h>
#include "internal.h"
@@ -129,7 +130,7 @@
* For debug caches, all allocations are forced to go through a list_lock
* protected region to serialize against concurrent validation.
*
- * cpu_sheaves->lock (local_trylock)
+ * cpu_sheaves->lock (qpw_trylock)
*
* This lock protects fastpath operations on the percpu sheaves. On !RT it
* only disables preemption and does no atomic operations. As long as the main
@@ -157,7 +158,7 @@
* Interrupts are disabled as part of list_lock or barn lock operations, or
* around the slab_lock operation, in order to make the slab allocator safe
* to use in the context of an irq.
- * Preemption is disabled as part of local_trylock operations.
+ * Preemption is disabled as part of qpw_trylock operations.
* kmalloc_nolock() and kfree_nolock() are safe in NMI context but see
* their limitations.
*
@@ -418,7 +419,7 @@ struct slab_sheaf {
};
struct slub_percpu_sheaves {
- local_trylock_t lock;
+ qpw_trylock_t lock;
struct slab_sheaf *main; /* never NULL when unlocked */
struct slab_sheaf *spare; /* empty or full, may be NULL */
struct slab_sheaf *rcu_free; /* for batching kfree_rcu() */
@@ -480,7 +481,7 @@ static nodemask_t slab_nodes;
static struct workqueue_struct *flushwq;
struct slub_flush_work {
- struct work_struct work;
+ struct qpw_struct qpw;
struct kmem_cache *s;
bool skip;
};
@@ -2849,16 +2850,14 @@ static void __kmem_cache_free_bulk(struc
*
* Returns how many objects are remaining to be flushed
*/
-static unsigned int __sheaf_flush_main_batch(struct kmem_cache *s)
+static unsigned int __sheaf_flush_main_batch(struct kmem_cache *s, int cpu)
{
struct slub_percpu_sheaves *pcs;
unsigned int batch, remaining;
void *objects[PCS_BATCH_MAX];
struct slab_sheaf *sheaf;
- lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
-
- pcs = this_cpu_ptr(s->cpu_sheaves);
+ pcs = per_cpu_ptr(s->cpu_sheaves, cpu);
sheaf = pcs->main;
batch = min(PCS_BATCH_MAX, sheaf->size);
@@ -2868,7 +2867,7 @@ static unsigned int __sheaf_flush_main_b
remaining = sheaf->size;
- local_unlock(&s->cpu_sheaves->lock);
+ qpw_unlock(&s->cpu_sheaves->lock, cpu);
__kmem_cache_free_bulk(s, batch, &objects[0]);
@@ -2877,14 +2876,14 @@ static unsigned int __sheaf_flush_main_b
return remaining;
}
-static void sheaf_flush_main(struct kmem_cache *s)
+static void sheaf_flush_main(struct kmem_cache *s, int cpu)
{
unsigned int remaining;
do {
- local_lock(&s->cpu_sheaves->lock);
+ qpw_lock(&s->cpu_sheaves->lock, cpu);
- remaining = __sheaf_flush_main_batch(s);
+ remaining = __sheaf_flush_main_batch(s, cpu);
} while (remaining);
}
@@ -2898,11 +2897,13 @@ static bool sheaf_try_flush_main(struct
bool ret = false;
do {
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
return ret;
ret = true;
- remaining = __sheaf_flush_main_batch(s);
+
+ lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
+ remaining = __sheaf_flush_main_batch(s, smp_processor_id());
} while (remaining);
@@ -2979,13 +2980,13 @@ static void rcu_free_sheaf_nobarn(struct
* flushing operations are rare so let's keep it simple and flush to slabs
* directly, skipping the barn
*/
-static void pcs_flush_all(struct kmem_cache *s)
+static void pcs_flush_all(struct kmem_cache *s, int cpu)
{
struct slub_percpu_sheaves *pcs;
struct slab_sheaf *spare, *rcu_free;
- local_lock(&s->cpu_sheaves->lock);
- pcs = this_cpu_ptr(s->cpu_sheaves);
+ qpw_lock(&s->cpu_sheaves->lock, cpu);
+ pcs = per_cpu_ptr(s->cpu_sheaves, cpu);
spare = pcs->spare;
pcs->spare = NULL;
@@ -2993,7 +2994,7 @@ static void pcs_flush_all(struct kmem_ca
rcu_free = pcs->rcu_free;
pcs->rcu_free = NULL;
- local_unlock(&s->cpu_sheaves->lock);
+ qpw_unlock(&s->cpu_sheaves->lock, cpu);
if (spare) {
sheaf_flush_unused(s, spare);
@@ -3003,7 +3004,7 @@ static void pcs_flush_all(struct kmem_ca
if (rcu_free)
call_rcu(&rcu_free->rcu_head, rcu_free_sheaf_nobarn);
- sheaf_flush_main(s);
+ sheaf_flush_main(s, cpu);
}
static void __pcs_flush_all_cpu(struct kmem_cache *s, unsigned int cpu)
@@ -3953,13 +3954,13 @@ static void flush_cpu_sheaves(struct wor
{
struct kmem_cache *s;
struct slub_flush_work *sfw;
+ int cpu = qpw_get_cpu(w);
- sfw = container_of(w, struct slub_flush_work, work);
-
+ sfw = &per_cpu(slub_flush, cpu);
s = sfw->s;
if (cache_has_sheaves(s))
- pcs_flush_all(s);
+ pcs_flush_all(s, cpu);
}
static void flush_all_cpus_locked(struct kmem_cache *s)
@@ -3976,17 +3977,17 @@ static void flush_all_cpus_locked(struct
sfw->skip = true;
continue;
}
- INIT_WORK(&sfw->work, flush_cpu_sheaves);
+ INIT_QPW(&sfw->qpw, flush_cpu_sheaves, cpu);
sfw->skip = false;
sfw->s = s;
- queue_work_on(cpu, flushwq, &sfw->work);
+ queue_percpu_work_on(cpu, flushwq, &sfw->qpw);
}
for_each_online_cpu(cpu) {
sfw = &per_cpu(slub_flush, cpu);
if (sfw->skip)
continue;
- flush_work(&sfw->work);
+ flush_percpu_work(&sfw->qpw);
}
mutex_unlock(&flush_lock);
@@ -4005,17 +4006,18 @@ static void flush_rcu_sheaf(struct work_
struct slab_sheaf *rcu_free;
struct slub_flush_work *sfw;
struct kmem_cache *s;
+ int cpu = qpw_get_cpu(w);
- sfw = container_of(w, struct slub_flush_work, work);
+ sfw = &per_cpu(slub_flush, cpu);
s = sfw->s;
- local_lock(&s->cpu_sheaves->lock);
- pcs = this_cpu_ptr(s->cpu_sheaves);
+ qpw_lock(&s->cpu_sheaves->lock, cpu);
+ pcs = per_cpu_ptr(s->cpu_sheaves, cpu);
rcu_free = pcs->rcu_free;
pcs->rcu_free = NULL;
- local_unlock(&s->cpu_sheaves->lock);
+ qpw_unlock(&s->cpu_sheaves->lock, cpu);
if (rcu_free)
call_rcu(&rcu_free->rcu_head, rcu_free_sheaf_nobarn);
@@ -4040,14 +4042,14 @@ void flush_rcu_sheaves_on_cache(struct k
* sure the __kfree_rcu_sheaf() finished its call_rcu()
*/
- INIT_WORK(&sfw->work, flush_rcu_sheaf);
+ INIT_QPW(&sfw->qpw, flush_rcu_sheaf, cpu);
sfw->s = s;
- queue_work_on(cpu, flushwq, &sfw->work);
+ queue_percpu_work_on(cpu, flushwq, &sfw->qpw);
}
for_each_online_cpu(cpu) {
sfw = &per_cpu(slub_flush, cpu);
- flush_work(&sfw->work);
+ flush_percpu_work(&sfw->qpw);
}
mutex_unlock(&flush_lock);
@@ -4555,11 +4557,11 @@ __pcs_replace_empty_main(struct kmem_cac
struct node_barn *barn;
bool can_alloc;
- lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
+ qpw_lockdep_assert_held(&s->cpu_sheaves->lock);
/* Bootstrap or debug cache, back off */
if (unlikely(!cache_has_sheaves(s))) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return NULL;
}
@@ -4570,7 +4572,7 @@ __pcs_replace_empty_main(struct kmem_cac
barn = get_barn(s);
if (!barn) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return NULL;
}
@@ -4596,7 +4598,7 @@ __pcs_replace_empty_main(struct kmem_cac
}
}
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
if (!can_alloc)
return NULL;
@@ -4622,7 +4624,7 @@ __pcs_replace_empty_main(struct kmem_cac
* we can reach here only when gfpflags_allow_blocking
* so this must not be an irq
*/
- local_lock(&s->cpu_sheaves->lock);
+ local_qpw_lock(&s->cpu_sheaves->lock);
pcs = this_cpu_ptr(s->cpu_sheaves);
/*
@@ -4699,7 +4701,7 @@ void *alloc_from_pcs(struct kmem_cache *
return NULL;
}
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
return NULL;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -4719,7 +4721,7 @@ void *alloc_from_pcs(struct kmem_cache *
* the current allocation or previous freeing process.
*/
if (page_to_nid(virt_to_page(object)) != node) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat(s, ALLOC_NODE_MISMATCH);
return NULL;
}
@@ -4727,7 +4729,7 @@ void *alloc_from_pcs(struct kmem_cache *
pcs->main->size--;
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat(s, ALLOC_FASTPATH);
@@ -4744,7 +4746,7 @@ unsigned int alloc_from_pcs_bulk(struct
unsigned int batch;
next_batch:
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
return allocated;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -4755,7 +4757,7 @@ next_batch:
struct node_barn *barn;
if (unlikely(!cache_has_sheaves(s))) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return allocated;
}
@@ -4766,7 +4768,7 @@ next_batch:
barn = get_barn(s);
if (!barn) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return allocated;
}
@@ -4781,7 +4783,7 @@ next_batch:
stat(s, BARN_GET_FAIL);
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
/*
* Once full sheaves in barn are depleted, let the bulk
@@ -4799,7 +4801,7 @@ do_alloc:
main->size -= batch;
memcpy(p, main->objects + main->size, batch * sizeof(void *));
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat_add(s, ALLOC_FASTPATH, batch);
@@ -4978,7 +4980,7 @@ kmem_cache_prefill_sheaf(struct kmem_cac
return sheaf;
}
- local_lock(&s->cpu_sheaves->lock);
+ local_qpw_lock(&s->cpu_sheaves->lock);
pcs = this_cpu_ptr(s->cpu_sheaves);
if (pcs->spare) {
@@ -4997,7 +4999,7 @@ kmem_cache_prefill_sheaf(struct kmem_cac
stat(s, BARN_GET_FAIL);
}
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
if (!sheaf)
@@ -5041,7 +5043,7 @@ void kmem_cache_return_sheaf(struct kmem
return;
}
- local_lock(&s->cpu_sheaves->lock);
+ local_qpw_lock(&s->cpu_sheaves->lock);
pcs = this_cpu_ptr(s->cpu_sheaves);
barn = get_barn(s);
@@ -5051,7 +5053,7 @@ void kmem_cache_return_sheaf(struct kmem
stat(s, SHEAF_RETURN_FAST);
}
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
if (!sheaf)
return;
@@ -5581,7 +5583,7 @@ static void __pcs_install_empty_sheaf(st
struct slub_percpu_sheaves *pcs, struct slab_sheaf *empty,
struct node_barn *barn)
{
- lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
+ qpw_lockdep_assert_held(&s->cpu_sheaves->lock);
/* This is what we expect to find if nobody interrupted us. */
if (likely(!pcs->spare)) {
@@ -5618,9 +5620,9 @@ static void __pcs_install_empty_sheaf(st
/*
* Replace the full main sheaf with a (at least partially) empty sheaf.
*
- * Must be called with the cpu_sheaves local lock locked. If successful, returns
- * the pcs pointer and the local lock locked (possibly on a different cpu than
- * initially called). If not successful, returns NULL and the local lock
+ * Must be called with the cpu_sheaves qpw lock locked. If successful, returns
+ * the pcs pointer and the qpw lock locked (possibly on a different cpu than
+ * initially called). If not successful, returns NULL and the qpw lock
* unlocked.
*/
static struct slub_percpu_sheaves *
@@ -5632,17 +5634,17 @@ __pcs_replace_full_main(struct kmem_cach
bool put_fail;
restart:
- lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
+ qpw_lockdep_assert_held(&s->cpu_sheaves->lock);
/* Bootstrap or debug cache, back off */
if (unlikely(!cache_has_sheaves(s))) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return NULL;
}
barn = get_barn(s);
if (!barn) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
return NULL;
}
@@ -5679,7 +5681,7 @@ restart:
stat(s, BARN_PUT_FAIL);
pcs->spare = NULL;
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
sheaf_flush_unused(s, to_flush);
empty = to_flush;
@@ -5695,7 +5697,7 @@ restart:
put_fail = true;
alloc_empty:
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
/*
* alloc_empty_sheaf() doesn't support !allow_spin and it's
@@ -5715,7 +5717,7 @@ alloc_empty:
if (!sheaf_try_flush_main(s))
return NULL;
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
return NULL;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -5731,7 +5733,7 @@ alloc_empty:
return pcs;
got_empty:
- if (!local_trylock(&s->cpu_sheaves->lock)) {
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock)) {
barn_put_empty_sheaf(barn, empty);
return NULL;
}
@@ -5751,7 +5753,7 @@ bool free_to_pcs(struct kmem_cache *s, v
{
struct slub_percpu_sheaves *pcs;
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
return false;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -5765,7 +5767,7 @@ bool free_to_pcs(struct kmem_cache *s, v
pcs->main->objects[pcs->main->size++] = object;
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat(s, FREE_FASTPATH);
@@ -5855,7 +5857,7 @@ bool __kfree_rcu_sheaf(struct kmem_cache
lock_map_acquire_try(&kfree_rcu_sheaf_map);
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
goto fail;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -5867,7 +5869,7 @@ bool __kfree_rcu_sheaf(struct kmem_cache
/* Bootstrap or debug cache, fall back */
if (unlikely(!cache_has_sheaves(s))) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
goto fail;
}
@@ -5879,7 +5881,7 @@ bool __kfree_rcu_sheaf(struct kmem_cache
barn = get_barn(s);
if (!barn) {
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
goto fail;
}
@@ -5890,14 +5892,14 @@ bool __kfree_rcu_sheaf(struct kmem_cache
goto do_free;
}
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
empty = alloc_empty_sheaf(s, GFP_NOWAIT);
if (!empty)
goto fail;
- if (!local_trylock(&s->cpu_sheaves->lock)) {
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock)) {
barn_put_empty_sheaf(barn, empty);
goto fail;
}
@@ -5934,7 +5936,7 @@ do_free:
if (rcu_sheaf)
call_rcu(&rcu_sheaf->rcu_head, rcu_free_sheaf);
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat(s, FREE_RCU_SHEAF);
lock_map_release(&kfree_rcu_sheaf_map);
@@ -5990,7 +5992,7 @@ next_remote_batch:
goto flush_remote;
next_batch:
- if (!local_trylock(&s->cpu_sheaves->lock))
+ if (!local_qpw_trylock(&s->cpu_sheaves->lock))
goto fallback;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -6033,7 +6035,7 @@ do_free:
memcpy(main->objects + main->size, p, batch * sizeof(void *));
main->size += batch;
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
stat_add(s, FREE_FASTPATH, batch);
@@ -6049,7 +6051,7 @@ do_free:
return;
no_empty:
- local_unlock(&s->cpu_sheaves->lock);
+ local_qpw_unlock(&s->cpu_sheaves->lock);
/*
* if we depleted all empty sheaves in the barn or there are too
@@ -7454,7 +7456,7 @@ static int init_percpu_sheaves(struct km
pcs = per_cpu_ptr(s->cpu_sheaves, cpu);
- local_trylock_init(&pcs->lock);
+ qpw_trylock_init(&pcs->lock);
/*
* Bootstrap sheaf has zero size so fast-path allocation fails.
next prev parent reply other threads:[~2026-03-02 15:53 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-02 15:49 [PATCH v2 0/5] Introduce QPW for per-cpu operations (v2) Marcelo Tosatti
2026-03-02 15:49 ` [PATCH v2 1/5] slab: distinguish lock and trylock for sheaf_flush_main() Marcelo Tosatti
2026-03-02 15:49 ` [PATCH v2 2/5] Introducing qpw_lock() and per-cpu queue & flush work Marcelo Tosatti
2026-03-03 12:03 ` Vlastimil Babka (SUSE)
2026-03-03 16:02 ` Marcelo Tosatti
2026-03-08 18:00 ` Leonardo Bras
2026-03-09 10:14 ` Vlastimil Babka (SUSE)
2026-03-11 0:16 ` Leonardo Bras
2026-03-11 7:58 ` Vlastimil Babka (SUSE)
2026-03-15 17:37 ` Leonardo Bras
2026-03-16 10:55 ` Vlastimil Babka (SUSE)
2026-03-23 0:51 ` Leonardo Bras
2026-03-13 21:55 ` Frederic Weisbecker
2026-03-15 18:10 ` Leonardo Bras
2026-03-17 13:33 ` Frederic Weisbecker
2026-03-23 1:38 ` Leonardo Bras
2026-03-24 11:54 ` Frederic Weisbecker
2026-03-24 22:06 ` Leonardo Bras
2026-03-23 14:36 ` Marcelo Tosatti
2026-03-02 15:49 ` [PATCH v2 3/5] mm/swap: move bh draining into a separate workqueue Marcelo Tosatti
2026-03-02 15:49 ` [PATCH v2 4/5] swap: apply new queue_percpu_work_on() interface Marcelo Tosatti
2026-03-02 15:49 ` Marcelo Tosatti [this message]
2026-03-03 11:15 ` [PATCH v2 0/5] Introduce QPW for per-cpu operations (v2) Frederic Weisbecker
2026-03-08 18:02 ` Leonardo Bras
2026-03-03 12:07 ` Vlastimil Babka (SUSE)
2026-03-05 16:55 ` Frederic Weisbecker
2026-03-06 1:47 ` Marcelo Tosatti
2026-03-10 21:34 ` Frederic Weisbecker
2026-03-10 17:12 ` Marcelo Tosatti
2026-03-10 22:14 ` Frederic Weisbecker
2026-03-11 1:18 ` Hillf Danton
2026-03-11 7:54 ` Vlastimil Babka
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=20260302155105.306721019@redhat.com \
--to=mtosatti@redhat.com \
--cc=42.hyeyoo@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=boqun.feng@gmail.com \
--cc=cl@linux.com \
--cc=frederic@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=iamjoonsoo.kim@lge.com \
--cc=leobras.c@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=longman@redhat.com \
--cc=mhocko@kernel.org \
--cc=muchun.song@linux.dev \
--cc=penberg@kernel.org \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=tglx@linutronix.de \
--cc=vbabka@suse.cz \
/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.