Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v2 0/1] fixes for maintainers_include
From: Mauro Carvalho Chehab @ 2026-07-12 19:33 UTC (permalink / raw)
  To: Jonathan Corbet, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-doc, linux-kernel, Shuah Khan,
	Manuel Ebner

Hi Jon,

This v2 replaces v1 series:
	[PATCH 0/2] A couple of fixes for maintainers_include.py

It basically fixes an issue reported by Manuel that entries
are printed duplicated.

In reality, the output maintainer entries are not properly
named per subsystem, so they appear to be duplicated.

Fixing the name output solves the issue and keeps the list
alphabetically sorted, as expected.

Mauro Carvalho Chehab (1):
  docs: maintainers_include: fix entry names

 Documentation/sphinx/maintainers_include.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

-- 
2.55.0


^ permalink raw reply

* [PATCH v2 1/1] docs: maintainers_include: fix entry names
From: Mauro Carvalho Chehab @ 2026-07-12 19:33 UTC (permalink / raw)
  To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, linux-kernel, Shuah Khan, Manuel Ebner
In-Reply-To: <cover.1783884625.git.mchehab+huawei@kernel.org>

Right now, it is printing duplicated values as profile entries, as
it is not properly handling subsystem name.

Fix it.

Reported-by: Manuel Ebner <manuelebner@mailbox.org>
Closes: https://lore.kernel.org/linux-doc/98a558a87a07ab641f47c66c372ee7ed0735f4f5.camel@mailbox.org/
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 Documentation/sphinx/maintainers_include.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index dc9f9e188ffa..7ffe19b5ed58 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -161,7 +161,7 @@ class MaintainersParser:
                     html = KERNELDOC_URL + ename + ".html"
                     entries[entry] = f'`{ename} <{html}>`_'
                 else:
-                    entries[entry] = f':doc:`{ename} </{entry}>`'
+                    entries[entry] = f'/{entry}'
 
         return entries
 
@@ -345,7 +345,10 @@ class MaintainersProfile(Include):
                 output += f"- {name}: {entry}\n"
                 self.warning(f"{profile}: Invalid 'P' tag: {entry}\n")
             else:
-                output += f"- {entry}\n"
+                if not name:
+                    name = entry
+
+                output += f"- :doc:`{name} <{entry}>`\n"
 
         #
         # Create a hidden TOC table with all profiles. That allows adding
-- 
2.55.0


^ permalink raw reply related

* Re: [PATCH v4 0/4] Introduce Per-CPU Work helpers (was QPW)
From: Leonardo Bras @ 2026-07-12 20:32 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Thomas Gleixner, Feng Tang, Dapeng Mi, Kees Cook,
	Marco Elver, Jakub Kicinski, Li RongQing, Eric Biggers,
	Paul E. McKenney, Nathan Chancellor, Miguel Ojeda, Nicolas Schier,
	Thomas Weißschuh, Douglas Anderson, Gary Guo,
	Christian Brauner, Pasha Tatashin, Masahiro Yamada, Coiby Xu,
	Frederic Weisbecker, linux-doc, linux-kernel, linux-mm,
	linux-rt-devel
In-Reply-To: <20260520130903.Ebsd4aUa@linutronix.de>

On Wed, May 20, 2026 at 03:09:03PM +0200, Sebastian Andrzej Siewior wrote:
> On 2026-05-18 22:27:46 [-0300], Leonardo Bras wrote:
> > The problem:
> > Some places in the kernel implement a parallel programming strategy
> > consisting on local_locks() for most of the work, and some rare remote
> > operations are scheduled on target cpu. This keeps cache bouncing low since
> > cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> > kernels, even though the very few remote operations will be expensive due
> > to scheduling overhead.
> > 
> > On the other hand, for RT workloads this can represent a problem: getting
> > an important workload scheduled out to deal with remote requests is
> > sure to introduce unexpected deadline misses.
> > 
> > The idea:
> > Currently with PREEMPT_RT=y, local_locks() become per-cpu spinlocks.

Hi Sebastian, thank you for reviewing!
(Sorry for the delay)

> It does not become a _spin_lock because it does not spin. It sleeps.

Right, it's a per-cpu mutex. 
My point is that it's a full lock, and we could use it instead of doing the 
whole scheduling thing, since we are already paying the 'atomic overhead' 
to get the lock here.

> 
> > In this case, instead of scheduling work on a remote cpu, it should
> > be safe to grab that remote cpu's per-cpu spinlock and run the required
> > work locally. That major cost, which is un/locking in every local function,
> > already happens in PREEMPT_RT.
> 
> We did have this before but only in the RT tree. It was a bit messy from
> the naming because it started with local_ but then it was a remote CPU.

Had the same naming issue here. This idea was initially a expansion to 
local_lock() mechanism, about the same way you were planning in the past.

> The main issue was the different code path which led to a few deadlocks
> back then.
> By the time local_lock_t went upstream, the cross-CPU locking was
> removed. As far as I remember, the cross-CPU user which did schedule
> work on a remote CPU and annoyed NOHZ folks were replaced.

I understand this could be a big issue if used in a generic way.

What I am proposing here a mechanism that standardizes those 
local_lock()+IPI strategies based on how they are done today, so we are 
only explected to get 'remote-cpu' pwlocks in the 'IPI replacement' 
operations.

The idea is pwlock_local* in every local function, and pwlock*(,cpu) in 
operations that can be remote. 

Maybe being used in a more constrained way, it has less chance of being an 
issue. Also, the whole idea is to improve CPU isolation numbers by 
reducing IPIs, so maybe NOHZ people will be happier with that :)

Thanks again!
Leo

^ permalink raw reply

* Re: [PATCH v4 1/4] Introducing pw_lock() and per-cpu queue & flush work
From: Leonardo Bras @ 2026-07-12 20:49 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Feng Tang, Dapeng Mi, Kees Cook, Marco Elver,
	Jakub Kicinski, Li RongQing, Eric Biggers, Paul E. McKenney,
	Nathan Chancellor, Nicolas Schier, Miguel Ojeda,
	Thomas Weißschuh, Thomas Gleixner, Douglas Anderson,
	Gary Guo, Christian Brauner, Pasha Tatashin, Coiby Xu,
	Masahiro Yamada, linux-doc, linux-kernel, linux-mm,
	linux-rt-devel, Marcelo Tosatti
In-Reply-To: <ag2IDR-JWn8k3bUG@localhost.localdomain>

On Wed, May 20, 2026 at 12:08:13PM +0200, Frederic Weisbecker wrote:
> Le Mon, May 18, 2026 at 10:27:47PM -0300, Leonardo Bras a écrit :
> > Some places in the kernel implement a parallel programming strategy
> > consisting on local_locks() for most of the work, and some rare remote
> > operations are scheduled on target cpu. This keeps cache bouncing low since
> > cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> > kernels, even though the very few remote operations will be expensive due
> > to scheduling overhead.
> > 
> > On the other hand, for RT workloads this can represent a problem:
> > scheduling work on remote cpu that are executing low latency tasks
> > is undesired and can introduce unexpected deadline misses.
> > 
> > It's interesting, though, that local_lock()s in RT kernels become
> > spinlock(). We can make use of those to avoid scheduling work on a remote
> > cpu by directly updating another cpu's per_cpu structure, while holding
> > it's spinlock().
> > 
> > In order to do that, it's necessary to introduce a new set of functions to
> > make it possible to get another cpu's per-cpu "local" lock (pw_{un,}lock*)
> > and also do the corresponding queueing (pw_queue_on()) and flushing
> > (pw_flush()) helpers to run the remote work.
> > 
> > Users of non-RT kernels but with low latency requirements can select
> > similar functionality by using the CONFIG_PWLOCKS compile time option.
> > 
> > On CONFIG_PWLOCKS disabled kernels, no changes are expected, as every
> > one of the introduced helpers work the exactly same as the current
> > implementation:
> > pw_{un,}lock*()		->  local_{un,}lock*() (ignores cpu parameter)
> > pw_queue_on()  		->  queue_work_on()
> > pw_flush()		->  flush_work()
> > 
> > For PWLOCKS enabled kernels, though, pw_{un,}lock*() will use the extra
> > cpu parameter to select the correct per-cpu structure to work on,
> > and acquire the spinlock for that cpu.
> > 
> > pw_queue_on() will just call the requested function in the current
> > cpu, which will operate in another cpu's per-cpu object. Since the
> > local_locks() become spinlock()s in PWLOCKS enabled kernels, we are
> > safe doing that.
> > 
> > pw_flush() then becomes a no-op since no work is actually scheduled on a
> > remote cpu.
> > 
> > Some minimal code rework is needed in order to make this mechanism work:
> > The calls for local_{un,}lock*() on the functions that are currently
> > scheduled on remote cpus need to be replaced by either pw_{un,}lock_*(),
> > PWLOCKS enabled kernels they can reference a different cpu. It's also
> > necessary to use a pw_struct instead of a work_struct, but it just
> > contains a work struct and, in CONFIG_PWLOCKS, the target cpu.
> > 
> > This should have almost no impact on non-CONFIG_PWLOCKS kernels: few
> > this_cpu_ptr() will become per_cpu_ptr(,smp_processor_id()) on non-hotpath
> > functions.
> > 
> > On CONFIG_PWLOCKS kernels, this should avoid deadlines misses by
> > removing scheduling noise.
> > 
> > Signed-off-by: Leonardo Bras <leobras.c@gmail.com>
> > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> 
> I like it! Just a few observations:
>

Hi Frederic, thanks for reviewing!
 
> > +#ifndef CONFIG_PWLOCKS
> > +
> > +typedef local_lock_t pw_lock_t;
> > +typedef local_trylock_t pw_trylock_t;
> > +
> > +struct pw_struct {
> > +	struct work_struct work;
> > +};
> > +
> > +#define pw_lock_init(lock)				\
> > +	local_lock_init(lock)
> > +
> > +#define pw_trylock_init(lock)				\
> > +	local_trylock_init(lock)
> > +
> > +#define pw_lock(lock, cpu)				\
> > +	local_lock(lock)
> 
> For debugging purpose, it would be nice to ensure that in those off-case,
> cpu is indeed the local one. Basically all the non-local functions, those that
> take a cpu, should verify:
> 
> lockdep_assert(cpu == smp_processor_id())

I see the point, should not be an issue, as non-local functions are not
hotpath.

> 
> > +
> > +#define pw_lock_local(lock)				\
> > +	local_lock(lock)
> > +
> > +#define pw_lock_irqsave(lock, flags, cpu)		\
> > +	local_lock_irqsave(lock, flags)
> > +
> > +#define pw_lock_local_irqsave(lock, flags)		\
> > +	local_lock_irqsave(lock, flags)
> > +
> > +#define pw_trylock(lock, cpu)				\
> > +	local_trylock(lock)
> > +
> > +#define pw_trylock_local(lock)				\
> > +	local_trylock(lock)
> > +
> > +#define pw_trylock_irqsave(lock, flags, cpu)		\
> > +	local_trylock_irqsave(lock, flags)
> > +
> > +#define pw_unlock(lock, cpu)				\
> > +	local_unlock(lock)
> > +
> > +#define pw_unlock_local(lock)				\
> > +	local_unlock(lock)
> > +
> > +#define pw_unlock_irqrestore(lock, flags, cpu)		\
> > +	local_unlock_irqrestore(lock, flags)
> > +
> > +#define pw_unlock_local_irqrestore(lock, flags)		\
> > +	local_unlock_irqrestore(lock, flags)
> > +
> > +#define pw_lockdep_assert_held(lock)			\
> > +	lockdep_assert_held(lock)
> > +
> > +#define pw_queue_on(c, wq, pw)				\
> > +	queue_work_on(c, wq, &(pw)->work)
> > +
> > +#define pw_flush(pw)					\
> > +	flush_work(&(pw)->work)
> > +
> > +#define pw_get_cpu(pw)	smp_processor_id()
> > +
> > +#define pw_is_cpu_remote(cpu)		(false)
> > +
> > +#define INIT_PW(pw, func, c)				\
> > +	INIT_WORK(&(pw)->work, (func))
> > +
> > +#else /* CONFIG_PWLOCKS */
> > +
> > +DECLARE_STATIC_KEY_MAYBE(CONFIG_PWLOCKS_DEFAULT, pw_sl);
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_lock_t ll;
> > +} pw_lock_t;
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_trylock_t ll;
> > +} pw_trylock_t;
> > +
> > +struct pw_struct {
> > +	struct work_struct work;
> > +	int cpu;
> > +};
> > +
> > +#ifdef CONFIG_PREEMPT_RT
> > +#define preempt_or_migrate_disable migrate_disable
> > +#define preempt_or_migrate_enable migrate_enable
> > +#else
> > +#define preempt_or_migrate_disable preempt_disable
> > +#define preempt_or_migrate_enable preempt_enable
> 
> This can be no-op in !CONFIG_PREEMPT_RT because non-rt spinlocks
> disable preemption already.
> 

I remember this was useful because we were getting the per-cpu variable 
before we preempt_disable in the lock code, and that could be bad if we get 
preempted after getting the per-cpu variable, and migrated to another core.

This is supposed to cost very little, because it's planned to match 
whatever is inside the lock, which would just be incrementing a nesting 
counter.

> > +#endif
> > +
> > +#define pw_lock_init(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_init(lock.sl);					\
> > +	else									\
> > +		local_lock_init(lock.ll);					\
> > +} while (0)
> 
> It looks like all these macros could be inline functions.
> 

I think the one with irqsave does not :(
So I ended up staying with defines all around.

Do you suggest replacing all except the irqsave ones with inline functions?
(I tried that, and the macro version looked easier to read. I have no issue 
reusing the inline version again) 

> > +
> > +#define pw_trylock_init(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_init(lock.sl);					\
> > +	else									\
> > +		local_trylock_init(lock.ll);					\
> > +} while (0)
> > +
> > +#define pw_lock(lock, cpu)
> > \
> 
> And those could have the same local CPU debug check.
> 

Sure

> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock(per_cpu_ptr(lock.sl, cpu));				\
> > +	else									\
> > +		local_lock(lock.ll);						\
> > +} while (0)
> > +
> > +#define pw_lock_local(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		spin_lock(this_cpu_ptr(lock.sl));				\
> > +	} else {								\
> > +		local_lock(lock.ll);						\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_lock_irqsave(lock, flags, cpu)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_irqsave(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		local_lock_irqsave(lock.ll, flags);				\
> > +} while (0)
> > +
> > +#define pw_lock_local_irqsave(lock, flags)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		spin_lock_irqsave(this_cpu_ptr(lock.sl), flags);		\
> > +	} else {								\
> > +		local_lock_irqsave(lock.ll, flags);				\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_trylock(lock, cpu)							\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		t = spin_trylock(per_cpu_ptr(lock.sl, cpu));			\
> > +	else									\
> > +		t = local_trylock(lock.ll);					\
> > +	t;									\
> > +})
> > +
> > +#define pw_trylock_local(lock)							\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		t = spin_trylock(this_cpu_ptr(lock.sl));			\
> > +		if (!t)								\
> > +			preempt_or_migrate_enable();
> > \
> 
> This is duplicating the RT logic in local_lock_internal.h and it would be
> tempting to propose spin_local_lock_t that both pw and RT local_lock could rely
> upon. But I'm afraid that would create a less readable result:
> 
> - we would need to check the CONFIG_PREEMPT_RT there before doing the
>   migrate_disable/enable
> 
> - RT local lock don't take the lock on IRQ/NMI, which is fine as pw is not
>   expected to be used on the non-threaded parts of IRQs not NMIs. Still that's
>   one more conditional to add there.
> 
> - we'll need to differenciate local/remote operations.
> 
> Well let's stick to what you did for now (Peter might have a different opinion though).
> 

I get your point. I will take a look on that.

> > +	} else {								\
> > +		t = local_trylock(lock.ll);					\
> > +	}									\
> > +	t;									\
> > +})
> > +
> > +#define pw_trylock_irqsave(lock, flags, cpu)					\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		t = spin_trylock_irqsave(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		t = local_trylock_irqsave(lock.ll, flags);			\
> > +	t;									\
> > +})
> > +
> > +#define pw_unlock(lock, cpu)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_unlock(per_cpu_ptr(lock.sl, cpu));			\
> > +	else									\
> > +		local_unlock(lock.ll);					\
> > +} while (0)
> > +
> > +#define pw_unlock_local(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		spin_unlock(this_cpu_ptr(lock.sl));				\
> > +		preempt_or_migrate_enable();					\
> > +	} else {								\
> > +		local_unlock(lock.ll);						\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_unlock_irqrestore(lock, flags, cpu)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_unlock_irqrestore(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		local_unlock_irqrestore(lock.ll, flags);			\
> > +} while (0)
> > +
> > +#define pw_unlock_local_irqrestore(lock, flags)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		spin_unlock_irqrestore(this_cpu_ptr(lock.sl), flags);	\
> > +		preempt_or_migrate_enable();					\
> > +	} else {								\
> > +		local_unlock_irqrestore(lock.ll, flags);			\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_lockdep_assert_held(lock)						\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		lockdep_assert_held(this_cpu_ptr(lock.sl));			\
> > +	else									\
> > +		lockdep_assert_held(this_cpu_ptr(lock.ll));			\
> > +} while (0)
> > +
> > +#define pw_queue_on(c, wq, pw)							\
> > +do {										\
> > +	int __c = c;								\
> > +	struct pw_struct *__pw = (pw);						\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		WARN_ON((__c) != __pw->cpu);					\
> > +		__pw->work.func(&__pw->work);					\
> > +	} else {								\
> > +		queue_work_on(__c, wq, &(__pw)->work);				\
> > +	}									\
> > +} while (0)
> > +
> > +/*
> > + * Does nothing if PWLOCKS is set to use spinlock, as the task is already done at the
> > + * time pw_queue_on() returns.
> > + */
> > +#define pw_flush(pw)								\
> > +do {										\
> > +	struct pw_struct *__pw = (pw);						\
> > +	if (!static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		flush_work(&__pw->work);					\
> > +} while (0)
> > +
> > +#define pw_get_cpu(w)			container_of((w), struct pw_struct, work)->cpu
> > +
> > +#define pw_is_cpu_remote(cpu)		((cpu) != smp_processor_id())
> > +
> > +#define INIT_PW(pw, func, c)							\
> > +do {										\
> > +	struct pw_struct *__pw = (pw);						\
> > +	INIT_WORK(&__pw->work, (func));						\
> > +	__pw->cpu = (c);							\
> > +} while (0)
> > +
> > +#endif /* CONFIG_PWLOCKS */
> > +#endif /* LINUX_PWLOCKS_H */
> > diff --git a/kernel/pwlocks.c b/kernel/pwlocks.c
> > new file mode 100644
> > index 000000000000..1ebf5cb979b9
> > --- /dev/null
> > +++ b/kernel/pwlocks.c
> > @@ -0,0 +1,47 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +#include "linux/export.h"
> > +#include <linux/sched.h>
> > +#include <linux/pwlocks.h>
> > +#include <linux/string.h>
> > +#include <linux/sched/isolation.h>
> > +
> > +DEFINE_STATIC_KEY_MAYBE(CONFIG_PWLOCKS_DEFAULT, pw_sl);
> > +EXPORT_SYMBOL(pw_sl);
> > +
> > +static bool pwlocks_param_specified;
> > +
> > +static int __init pwlocks_setup(char *str)
> > +{
> > +	int opt;
> > +
> > +	if (!get_option(&str, &opt)) {
> > +		pr_warn("PWLOCKS: invalid pwlocks parameter: %s, ignoring.\n", str);
> > +		return 0;
> > +	}
> > +
> > +	if (opt)
> > +		static_branch_enable(&pw_sl);
> > +	else
> > +		static_branch_disable(&pw_sl);
> > +
> > +	pwlocks_param_specified = true;
> > +
> > +	return 1;
> > +}
> > +__setup("pwlocks=", pwlocks_setup);
> > +
> > +/*
> > + * Enable PWLOCKS if CPUs want to avoid kernel noise.
> > + */
> > +static int __init pwlocks_init(void)
> > +{
> > +	if (pwlocks_param_specified)
> > +		return 0;
> > +
> > +	if (housekeeping_enabled(HK_TYPE_KERNEL_NOISE))
> > +		static_branch_enable(&pw_sl);
> > +
> > +	return 0;
> > +}
> > +
> > +late_initcall(pwlocks_init);
> 
> That should be a pre-SMP initcall. Otherwise you risk some asymetric calls.
> 

Noted.
Will take a deeper look on that part for next version

Thanks!
Leo

^ permalink raw reply

* [PATCH v3] docs/ja_JP: translate submitting-patches.rst (sign-off)
From: Akiyoshi Kurita @ 2026-07-12 21:05 UTC (permalink / raw)
  To: linux-doc; +Cc: linux-kernel, corbet, akiyks, weibu

Translate the "Include PATCH in the subject" and "Sign your work -
the Developer's Certificate of Origin" sections into Japanese.

Keep the DCO text in English as the original certificate text, and add
a Japanese note that the sign-off refers to the English DCO text.

Signed-off-by: Akiyoshi Kurita <weibu@redadmin.org>
---
Changes in v3:

  - Keep the DCO 1.1 text in English instead of translating it.
  - Add a Japanese note explaining that Signed-off-by refers to the
    original English DCO text, not to a translated version.
  - Address Akira Yokosawa's concern about possible confusion around
    translating the DCO text.

Changes in v2:

  - Added the Japanese translation of the "Include PATCH in the subject"
    section.
  - Updated the DCO translation to match the current English text and
    structure.
  - Kept the DCO statement in a literal block following commit
    999161066dc5.

 .../ja_JP/process/submitting-patches.rst      | 75 +++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/Documentation/translations/ja_JP/process/submitting-patches.rst b/Documentation/translations/ja_JP/process/submitting-patches.rst
index d31d469909e4..9bf4d1f99196 100644
--- a/Documentation/translations/ja_JP/process/submitting-patches.rst
+++ b/Documentation/translations/ja_JP/process/submitting-patches.rst
@@ -402,3 +402,78 @@ ping したりする前に、少なくとも 1 週間は待ってください。
 パッチまたはパッチシリーズの修正版を投稿する場合は、"RESEND" を
 追加しないでください。"RESEND" は、前回の投稿から一切変更していない
 パッチまたはパッチシリーズを再送する場合にのみ使います。
+
+
+件名に PATCH を含める
+---------------------
+
+Linus と linux-kernel メーリングリストには大量のメールが届くため、
+件名の先頭に ``[PATCH]`` を付けることが一般的な慣例となっています。
+これにより、Linus や他のカーネル開発者は、パッチとその他の議論を
+容易に区別できます。
+
+``git send-email`` は、この指定を自動的に行います。
+
+
+作業への署名 - Developer's Certificate of Origin
+--------------------------------------------------
+
+誰が何を行ったのかを追跡しやすくするため、特にパッチが複数階層の
+メンテナーを経由して最終的にカーネルへ取り込まれる場合に備えて、
+メールでやり取りされるパッチには sign-off の手続きが導入されています。
+
+sign-off は、パッチの説明の末尾に追加する単純な一行です。これは、
+そのパッチを自分で作成したか、オープンソースのパッチとして提出する
+権利を持っていることを証明します。
+
+注意: ``Signed-off-by`` によって同意する対象は、翻訳文ではなく、
+以下に示す英語原文の Developer's Certificate of Origin 1.1 です。
+DCO は法的な性質を持つ文書であるため、本文は翻訳せず、原文のまま
+掲載します。内容を確認する場合は、必ず英語原文を参照してください。
+
+規則は単純で、以下を証明できる場合です::
+
+        Developer's Certificate of Origin 1.1
+
+        By making a contribution to this project, I certify that:
+
+        (a) The contribution was created in whole or in part by me and I
+            have the right to submit it under the open source license
+            indicated in the file; or
+
+        (b) The contribution is based upon previous work that, to the best
+            of my knowledge, is covered under an appropriate open source
+            license and I have the right under that license to submit that
+            work with modifications, whether created in whole or in part
+            by me, under the same open source license (unless I am
+            permitted to submit under a different license), as indicated
+            in the file; or
+
+        (c) The contribution was provided directly to me by some other
+            person who certified (a), (b) or (c) and I have not modified
+            it.
+
+        (d) I understand and agree that this project and the contribution
+            are public and that a record of the contribution (including all
+            personal information I submit with it, including my sign-off) is
+            maintained indefinitely and may be redistributed consistent with
+            this project or the open source license(s) involved.
+
+上記を証明できる場合は、次のような行を追加します::
+
+        Signed-off-by: Random J Developer <random@developer.example.org>
+
+既知の身元を使用してください。匿名での貢献は認められません。
+``git commit -s`` を使用すると、この行を自動的に追加できます。
+
+revert にも ``Signed-off-by:`` を含める必要があります。
+``git revert -s`` を使用すると、自動的に追加できます。
+
+末尾に追加のタグを付ける人もいます。現時点では無視されますが、
+社内手続きを示したり、sign-off に関する特記事項を記録したりするために
+使用できます。
+
+作者の SoB に続く追加の SoB(``Signed-off-by:``)は、パッチの開発には
+関与せず、その取り扱いや転送を行った人によるものです。SoB の連鎖は、
+パッチがメンテナーを経て最終的に Linus へ届いた実際の経路を反映する
+必要があります。最初の SoB は、単独の主要作者であることを示します。
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH v4 1/4] Introducing pw_lock() and per-cpu queue & flush work
From: Leonardo Bras @ 2026-07-12 21:17 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Feng Tang, Dapeng Mi, Kees Cook, Marco Elver,
	Jakub Kicinski, Li RongQing, Eric Biggers, Paul E. McKenney,
	Nathan Chancellor, Nicolas Schier, Miguel Ojeda,
	Thomas Weißschuh, Thomas Gleixner, Douglas Anderson,
	Gary Guo, Christian Brauner, Pasha Tatashin, Coiby Xu,
	Masahiro Yamada, Frederic Weisbecker, linux-doc, linux-kernel,
	linux-mm, linux-rt-devel, Marcelo Tosatti
In-Reply-To: <20260520134832.WS7TrMnu@linutronix.de>

On Wed, May 20, 2026 at 03:48:32PM +0200, Sebastian Andrzej Siewior wrote:
> On 2026-05-18 22:27:47 [-0300], Leonardo Bras wrote:
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index 4d0f545fb3ec..68c8a6f9d227 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -2810,20 +2810,30 @@ Kernel parameters
> >  			  If a queue's affinity mask contains only isolated
> >  			  CPUs then this parameter has no effect on the
> >  			  interrupt routing decision, though interrupts are
> >  			  only delivered when tasks running on those
> >  			  isolated CPUs submit IO. IO submitted on
> >  			  housekeeping CPUs has no influence on those
> >  			  queues.
> >  
> >  			The format of <cpu-list> is described above.
> >  
> > +	pwlocks=	[KNL,SMP] Select a behavior on per-CPU resource sharing
> > +			and remote interference mechanism on a kernel built with
> > +			CONFIG_PWLOCKS.
> > +			Format: { "0" | "1" }
> > +			0 - local_lock() + queue_work_on(remote_cpu)
> > +			1 - spin_lock() for both local and remote operations
> > +
> > +			Selecting 1 may be interesting for systems that want
> > +			to avoid interruption & context switches from IPIs.
> > +
> 
> This documentation is supposed to be for an administrator/ user of the
> system. Exposing him to underlying kernel technique shouldn't happen.
> It does not explain the users/ outcome so it sounds like best hope.

Noted, will try to improve the explanation to target a user/sysadmin 
public.


> 
> >  	iucv=		[HW,NET]
> >  
> >  	ivrs_ioapic	[HW,X86-64]
> >  			Provide an override to the IOAPIC-ID<->DEVICE-ID
> >  			mapping provided in the IVRS ACPI table.
> >  			By default, PCI segment is 0, and can be omitted.
> >  
> >  			For example, to map IOAPIC-ID decimal 10 to
> >  			PCI segment 0x1 and PCI device 00:14.0,
> >  			write the parameter as:
> > diff --git a/Documentation/locking/pwlocks.rst b/Documentation/locking/pwlocks.rst
> > new file mode 100644
> > index 000000000000..09f4a5417bc1
> > --- /dev/null
> > +++ b/Documentation/locking/pwlocks.rst
> > @@ -0,0 +1,76 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +=========
> > +PW (Per-CPU Work) locks
> > +=========
> > +
> > +Some places in the kernel implement a parallel programming strategy
> > +consisting on local_locks() for most of the work, and some rare remote
> > +operations are scheduled on target cpu. This keeps cache bouncing low since
> > +cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> 
> PREEMPT_RT can be spelled out if you mean it so it is not confused with
> other meanings of the two letters.
> 

Will do!


> > +kernels, even though the very few remote operations will be expensive due
> > +to scheduling overhead.
> > +
> > +On the other hand, for RT workloads this can represent a problem:
> > +scheduling work on remote cpu that are executing low latency tasks
> > +is undesired and can introduce unexpected deadline misses.
> > +
> > +PW locks help to convert sites that use local_locks (for cpu local operations)
> > +and queue_work_on (for queueing work remotely, to be executed
> > +locally on the owner cpu of the lock) to a spinlocks.
> 
> not spinlocks.
> 

If CONFIG_RT=n, and PWLOCKS=1, it becomes a spinlock.

IIUC in PREEMPT_RT=1 spinlocks become mutexes. I get that it does not 
actually spins, but it should behave as much as a spinlock could in 
PREEMPT_RT systems, right?

> > +
> > +The lock is declared pw_lock_t type.
> > +The lock is initialized with pw_lock_init.
> > +The lock is locked with pw_lock (takes a lock and cpu as a parameter).
> > +The lock is unlocked with pw_unlock (takes a lock and cpu as a parameter).
> 
> If it is a function, it should end with ()
> 

Right, will correct those.

> > +The pw_lock_irqsave function disables interrupts and saves current interrupt state,
> > +cpu as a parameter.
> 
> CPU.

right

> 
> > +For trylock variant, there is the pw_trylock_t type, initialized with
> > +pw_trylock_init. Then the corresponding pw_trylock and pw_trylock_irqsave.
> > +
> > +work_struct should be replaced by pw_struct, which contains a cpu parameter
> > +(owner cpu of the lock), initialized by INIT_PW.
> > +
> > +The queue work related functions (analogous to queue_work_on and flush_work) are:
> > +pw_queue_on and pw_flush.
> > +
> > +The behaviour of the PW lock functions is as follows:
> > +
> > +* !CONFIG_PWLOCKS (or CONFIG_PWLOCKS and pwlocks=off kernel boot parameter):
> > +        - pw_lock:			local_lock
> > +        - pw_lock_irqsave:		local_lock_irqsave
> > +        - pw_trylock:			local_trylock
> > +        - pw_trylock_irqsave:		local_trylock_irqsave
> > +        - pw_unlock:			local_unlock
> > +        - pw_lock_local:		local_lock
> > +        - pw_trylock_local:		local_trylock
> > +        - pw_unlock_local:		local_unlock
> > +        - pw_queue_on:         		queue_work_on
> > +        - pw_flush:	            	flush_work
> > +
> > +* CONFIG_PWLOCKS (and CONFIG_PWLOCKS_DEFAULT=y or pwlocks=on kernel boot parameter),
> > +        - pw_lock:			spin_lock
> > +        - pw_lock_irqsave:		spin_lock_irqsave
> > +        - pw_trylock:			spin_trylock
> > +        - pw_trylock_irqsave:		spin_trylock_irqsave
> > +        - pw_unlock:			spin_unlock
> > +        - pw_lock_local:		preempt_disable OR migrate_disable + spin_lock
> > +        - pw_trylock_local:		preempt_disable OR migrate_disable + spin_trylock
> > +        - pw_unlock_local:		preempt_enable OR migrate_enable + spin_unlock
> > +        - pw_queue_on:         		executes work function on caller cpu
> > +        - pw_flush:            		empty
> > +
> > +pw_get_cpu(work_struct), to be called from within per-cpu work function,
> > +returns the target cpu.
> > +
> > +On the locking functions above, there are the local locking functions
> > +(pw_lock_local, pw_trylock_local and pw_unlock_local) that must only
> > +be used to access per-CPU data from the CPU that owns that data,
> > +and never remotely. They disable preemption/migration and don't require
> > +a cpu parameter, making them a replacement for local_lock functions that
> > +does not introduce overhead.
> 
> Why do you need to either the one or the other? My only guess is that
> migrate_disable() is sufficient but you prefer preempt_disable() on
> !PREEMPT_RT because it is cheaper.

Correct.
One goal of this change is not introduce overheads in the user code, in 
special on hotpath code. Using preempt_disable in !PREEMPT_RT just nests 
with the one in the lock, and it becomes almost free

> 
> > +These should only be used when accessing per-CPU data of the local CPU.
> > +
> > diff --git a/init/Kconfig b/init/Kconfig
> > index 2937c4d308ae..3fb751dc4530 100644
> > --- a/init/Kconfig
> > +++ b/init/Kconfig
> > @@ -764,20 +764,55 @@ config CPU_ISOLATION
> >  	depends on SMP
> >  	default y
> >  	help
> >  	  Make sure that CPUs running critical tasks are not disturbed by
> >  	  any source of "noise" such as unbound workqueues, timers, kthreads...
> >  	  Unbound jobs get offloaded to housekeeping CPUs. This is driven by
> >  	  the "isolcpus=" boot parameter.
> >  
> >  	  Say Y if unsure.
> >  
> > +config PWLOCKS
> > +	bool "Per-CPU Work locks"
> > +	depends on SMP || COMPILE_TEST
> > +	default n
> > +	help
> > +	  Allow changing the behavior on per-CPU resource sharing with cache,
> > +	  from the regular local_locks() + queue_work_on(remote_cpu) to using
> > +	  per-CPU spinlocks on both local and remote operations.
> > +
> > +	  This is useful to give user the option on reducing IPIs to CPUs, and
> > +	  thus reduce interruptions and context switches. On the other hand, it
> > +	  increases generated code and will use atomic operations if spinlocks
> > +	  are selected.
> 
> I think the goal is to avoid scheduling a task on a remote CPU to get
> something done. 

Correct, it makes an isolated CPU less noisy.

> 
> > +
> > +	  If set, will use the default behavior set in PWLOCKS_DEFAULT unless boot
> > +	  parameter pwlocks is passed with a different behavior.
> > +
> > +	  If unset, will use the local_lock() + queue_work_on() strategy,
> > +	  regardless of the boot parameter or PWLOCKS_DEFAULT.
> 
> This sounds like it affects the greater kernel.
> 

It should affect only code converted to use pwlocks.

> > +	  Say N if unsure.
> > +
> > +config PWLOCKS_DEFAULT
> > +	bool "Use per-CPU spinlocks by default on PWLOCKS"
> > +	depends on PWLOCKS
> > +	default n
> 
> n is default.

You can set PWLOCKS=n, then it compiles out the mechanism.
You can set PWLOCKS=y, and then it will use PWLOCKS_DEFAULT + pwlocks 
command-line argument to decide on using either local_lock+IPI or 
spinlocks (that become mutexes in PREEMPT_RT=y).

PWLOCKS_DEFAULT is just a way of letting whoever builds the kernel to 
decide the default mode, while letting the user decide to disable/enable 
the mechanism on cmdline as desired.

> 
> > +	help
> > +	  If set, will use per-CPU spinlocks as default behavior for per-CPU
> > +	  remote operations.
> > +
> > +	  If unset, will use local_lock() + queue_work_on(cpu) as default
> > +	  behavior for remote operations.
> > +
> > +	  Say N if unsure
> > +
> >  source "kernel/rcu/Kconfig"
> >  
> >  config IKCONFIG
> >  	tristate "Kernel .config support"
> >  	help
> >  	  This option enables the complete Linux kernel ".config" file
> >  	  contents to be saved in the kernel. It provides documentation
> >  	  of which kernel options are used in a running kernel or in an
> >  	  on-disk kernel.  This information can be extracted from the kernel
> >  	  image file with the script scripts/extract-ikconfig and used as
> > diff --git a/include/linux/pwlocks.h b/include/linux/pwlocks.h
> > new file mode 100644
> > index 000000000000..3d79621655f9
> > --- /dev/null
> > +++ b/include/linux/pwlocks.h
> > @@ -0,0 +1,265 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _LINUX_PWLOCKS_H
> > +#define _LINUX_PWLOCKS_H
> > +
> > +#include "linux/spinlock.h"
> > +#include "linux/local_lock.h"
> > +#include "linux/workqueue.h"
> > +
> > +#ifndef CONFIG_PWLOCKS
> > +
> > +typedef local_lock_t pw_lock_t;
> > +typedef local_trylock_t pw_trylock_t;
> > +
> > +struct pw_struct {
> > +	struct work_struct work;
> > +};
> > +
> > +#define pw_lock_init(lock)				\
> > +	local_lock_init(lock)
> > +
> > +#define pw_trylock_init(lock)				\
> > +	local_trylock_init(lock)
> > +
> > +#define pw_lock(lock, cpu)				\
> > +	local_lock(lock)
> > +
> > +#define pw_lock_local(lock)				\
> > +	local_lock(lock)
> > +
> > +#define pw_lock_irqsave(lock, flags, cpu)		\
> > +	local_lock_irqsave(lock, flags)
> 
> The part where you have a `cpu' argument which is not used is entirely
> confusing.
> 

That is how we compile-out when CONFIG_PWLOCKS=n, it has to receive the cpu 
parameter as the version with CONFIG_PWLOCKS=y below use the cpu parameter 
to decide where to find the per-cpu data.

> > +
> > +#define pw_lock_local_irqsave(lock, flags)		\
> > +	local_lock_irqsave(lock, flags)
> > +
> > +#define pw_trylock(lock, cpu)				\
> > +	local_trylock(lock)
> > +
> > +#define pw_trylock_local(lock)				\
> > +	local_trylock(lock)
> > +
> > +#define pw_trylock_irqsave(lock, flags, cpu)		\
> > +	local_trylock_irqsave(lock, flags)
> > +
> > +#define pw_unlock(lock, cpu)				\
> > +	local_unlock(lock)
> > +
> > +#define pw_unlock_local(lock)				\
> > +	local_unlock(lock)
> > +
> > +#define pw_unlock_irqrestore(lock, flags, cpu)		\
> > +	local_unlock_irqrestore(lock, flags)
> > +
> > +#define pw_unlock_local_irqrestore(lock, flags)		\
> > +	local_unlock_irqrestore(lock, flags)
> > +
> > +#define pw_lockdep_assert_held(lock)			\
> > +	lockdep_assert_held(lock)
> > +
> > +#define pw_queue_on(c, wq, pw)				\
> > +	queue_work_on(c, wq, &(pw)->work)
> > +
> > +#define pw_flush(pw)					\
> > +	flush_work(&(pw)->work)
> > +
> > +#define pw_get_cpu(pw)	smp_processor_id()
> > +
> > +#define pw_is_cpu_remote(cpu)		(false)
> > +
> > +#define INIT_PW(pw, func, c)				\
> > +	INIT_WORK(&(pw)->work, (func))
> > +
> > +#else /* CONFIG_PWLOCKS */
> > +
> > +DECLARE_STATIC_KEY_MAYBE(CONFIG_PWLOCKS_DEFAULT, pw_sl);
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_lock_t ll;
> > +} pw_lock_t;
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_trylock_t ll;
> > +} pw_trylock_t;
> 
> Why do you use local_trylock_t ? Its use case is different compared to
> local_lock_t. _IF_ you are fine with local_trylock_t then you should be
> able to deal with a per-CPU spinlock_t and none of this should be
> needed.

IIRC there is code that use both local_trylock and and local_lock, so we 
needed this to be able to convert the user completely.

> 
> > +struct pw_struct {
> > +	struct work_struct work;
> > +	int cpu;
> > +};
> > +
> > +#ifdef CONFIG_PREEMPT_RT
> > +#define preempt_or_migrate_disable migrate_disable
> > +#define preempt_or_migrate_enable migrate_enable
> > +#else
> > +#define preempt_or_migrate_disable preempt_disable
> > +#define preempt_or_migrate_enable preempt_enable
> > +#endif
> 
> if then () but this looks terrible.

Agree, have to figure a better naming.

> 
> > +
> > +#define pw_lock_init(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_init(lock.sl);					\
> > +	else									\
> > +		local_lock_init(lock.ll);					\
> > +} while (0)
> > +
> > +#define pw_trylock_init(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_init(lock.sl);					\
> > +	else									\
> > +		local_trylock_init(lock.ll);					\
> > +} while (0)
> > +
> > +#define pw_lock(lock, cpu)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock(per_cpu_ptr(lock.sl, cpu));				\
> > +	else									\
> > +		local_lock(lock.ll);						\
> > +} while (0)
> > +
> > +#define pw_lock_local(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		spin_lock(this_cpu_ptr(lock.sl));				\
> > +	} else {								\
> > +		local_lock(lock.ll);						\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_lock_irqsave(lock, flags, cpu)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_irqsave(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		local_lock_irqsave(lock.ll, flags);				\
> > +} while (0)
> > +
> > +#define pw_lock_local_irqsave(lock, flags)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		spin_lock_irqsave(this_cpu_ptr(lock.sl), flags);		\
> > +	} else {								\
> > +		local_lock_irqsave(lock.ll, flags);				\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_trylock(lock, cpu)							\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		t = spin_trylock(per_cpu_ptr(lock.sl, cpu));			\
> > +	else									\
> > +		t = local_trylock(lock.ll);					\
> > +	t;									\
> > +})
> > +
> > +#define pw_trylock_local(lock)							\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		preempt_or_migrate_disable();					\
> > +		t = spin_trylock(this_cpu_ptr(lock.sl));			\
> > +		if (!t)								\
> > +			preempt_or_migrate_enable();				\
> > +	} else {								\
> > +		t = local_trylock(lock.ll);					\
> > +	}									\
> > +	t;									\
> > +})
> > +
> > +#define pw_trylock_irqsave(lock, flags, cpu)					\
> > +({										\
> > +	int t;									\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		t = spin_trylock_irqsave(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		t = local_trylock_irqsave(lock.ll, flags);			\
> > +	t;									\
> > +})
> > +
> > +#define pw_unlock(lock, cpu)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_unlock(per_cpu_ptr(lock.sl, cpu));			\
> > +	else									\
> > +		local_unlock(lock.ll);					\
> > +} while (0)
> > +
> > +#define pw_unlock_local(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		spin_unlock(this_cpu_ptr(lock.sl));				\
> > +		preempt_or_migrate_enable();					\
> > +	} else {								\
> > +		local_unlock(lock.ll);						\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_unlock_irqrestore(lock, flags, cpu)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_unlock_irqrestore(per_cpu_ptr(lock.sl, cpu), flags);	\
> > +	else									\
> > +		local_unlock_irqrestore(lock.ll, flags);			\
> > +} while (0)
> > +
> > +#define pw_unlock_local_irqrestore(lock, flags)					\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		spin_unlock_irqrestore(this_cpu_ptr(lock.sl), flags);	\
> > +		preempt_or_migrate_enable();					\
> > +	} else {								\
> > +		local_unlock_irqrestore(lock.ll, flags);			\
> > +	}									\
> > +} while (0)
> > +
> > +#define pw_lockdep_assert_held(lock)						\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		lockdep_assert_held(this_cpu_ptr(lock.sl));			\
> > +	else									\
> > +		lockdep_assert_held(this_cpu_ptr(lock.ll));			\
> > +} while (0)
> > +
> > +#define pw_queue_on(c, wq, pw)							\
> > +do {										\
> > +	int __c = c;								\
> > +	struct pw_struct *__pw = (pw);						\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl)) {		\
> > +		WARN_ON((__c) != __pw->cpu);					\
> > +		__pw->work.func(&__pw->work);					\
> > +	} else {								\
> > +		queue_work_on(__c, wq, &(__pw)->work);				\
> > +	}									\
> > +} while (0)
> > +
> > +/*
> > + * Does nothing if PWLOCKS is set to use spinlock, as the task is already done at the
> > + * time pw_queue_on() returns.
> > + */
> > +#define pw_flush(pw)								\
> > +do {										\
> > +	struct pw_struct *__pw = (pw);						\
> > +	if (!static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		flush_work(&__pw->work);					\
> > +} while (0)
> 
> I don't think this should be a collection of macros. Either proper
> functions or static inline _if_ this is performance critical for some
> reason.
> 

Agree, I remember the only macro that was hard to do so was _irqsave() 
versions, as it uses an output as a parameter, and I ended up letting all 
of them being macro due to them looking similar.

Will convert on next version.

(Only the _local*() funcs are performance-critial IIRC.

> > +
> > +#define pw_get_cpu(w)			container_of((w), struct pw_struct, work)->cpu
> > +
> > +#define pw_is_cpu_remote(cpu)		((cpu) != smp_processor_id())
> > +
> > +#define INIT_PW(pw, func, c)							\
> > +do {										\
> > +	struct pw_struct *__pw = (pw);						\
> > +	INIT_WORK(&__pw->work, (func));						\
> > +	__pw->cpu = (c);							\
> > +} while (0)
> > +
> > +#endif /* CONFIG_PWLOCKS */
> > +#endif /* LINUX_PWLOCKS_H */
> > diff --git a/kernel/pwlocks.c b/kernel/pwlocks.c
> > new file mode 100644
> > index 000000000000..1ebf5cb979b9
> > --- /dev/null
> > +++ b/kernel/pwlocks.c
> > @@ -0,0 +1,47 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +#include "linux/export.h"
> > +#include <linux/sched.h>
> > +#include <linux/pwlocks.h>
> > +#include <linux/string.h>
> > +#include <linux/sched/isolation.h>
> > +
> > +DEFINE_STATIC_KEY_MAYBE(CONFIG_PWLOCKS_DEFAULT, pw_sl);
> > +EXPORT_SYMBOL(pw_sl);
> > +
> > +static bool pwlocks_param_specified;
> > +
> > +static int __init pwlocks_setup(char *str)
> > +{
> > +	int opt;
> > +
> > +	if (!get_option(&str, &opt)) {
> > +		pr_warn("PWLOCKS: invalid pwlocks parameter: %s, ignoring.\n", str);
> > +		return 0;
> > +	}
> > +
> > +	if (opt)
> > +		static_branch_enable(&pw_sl);
> > +	else
> > +		static_branch_disable(&pw_sl);
> > +
> > +	pwlocks_param_specified = true;
> > +
> > +	return 1;
> > +}
> > +__setup("pwlocks=", pwlocks_setup);
> > +
> > +/*
> > + * Enable PWLOCKS if CPUs want to avoid kernel noise.
> > + */
> > +static int __init pwlocks_init(void)
> > +{
> > +	if (pwlocks_param_specified)
> > +		return 0;
> > +
> > +	if (housekeeping_enabled(HK_TYPE_KERNEL_NOISE))
> > +		static_branch_enable(&pw_sl);
> 
> How likely is it, that you you had users before late_initcall()? Also
> can it happen that one of them uses one function to lock and the other
> unlock in this brief window? There is no check if this was used before
> static_branch usage.
> 

I don't really understand that much of initcall :(
That part was done by Marcelo, I have to reach out for him for more 
understanding of his decision here.

I have to take a better look here :)

Thanks!
Leo

^ permalink raw reply

* Re: [PATCH v4 1/4] Introducing pw_lock() and per-cpu queue & flush work
From: Leonardo Bras @ 2026-07-12 21:17 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: Leonardo Bras, Sebastian Andrzej Siewior, Jonathan Corbet,
	Shuah Khan, Peter Zijlstra, Ingo Molnar, Will Deacon, Boqun Feng,
	Waiman Long, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jann Horn, Pedro Falcato,
	Brendan Jackman, Johannes Weiner, Zi Yan, Harry Yoo, Hao Li,
	Christoph Lameter, David Rientjes, Roman Gushchin, Chris Li,
	Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
	Youngjun Park, Qi Zheng, Shakeel Butt, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Borislav Petkov (AMD), Randy Dunlap,
	Feng Tang, Dapeng Mi, Kees Cook, Marco Elver, Jakub Kicinski,
	Li RongQing, Eric Biggers, Paul E. McKenney, Nathan Chancellor,
	Nicolas Schier, Miguel Ojeda, Thomas Weißschuh,
	Thomas Gleixner, Douglas Anderson, Gary Guo, Christian Brauner,
	Pasha Tatashin, Coiby Xu, Masahiro Yamada, linux-doc,
	linux-kernel, linux-mm, linux-rt-devel, Marcelo Tosatti
In-Reply-To: <ag3Jh-8iUdgKvw5y@localhost.localdomain>

On Wed, May 20, 2026 at 04:47:35PM +0200, Frederic Weisbecker wrote:
> Le Wed, May 20, 2026 at 03:48:32PM +0200, Sebastian Andrzej Siewior a écrit :
> > How likely is it, that you you had users before late_initcall()? Also
> > can it happen that one of them uses one function to lock and the other
> > unlock in this brief window? There is no check if this was used before
> > static_branch usage.
> 
> Or let alone initialization on the wrong member of the union.

Right!

> 
> -- 
> Frederic Weisbecker
> SUSE Labs

^ permalink raw reply

* Re: [PATCH v4 1/4] Introducing pw_lock() and per-cpu queue & flush work
From: Leonardo Bras @ 2026-07-12 21:23 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Feng Tang, Dapeng Mi, Kees Cook, Marco Elver, Jakub Kicinski,
	Li RongQing, Eric Biggers, Paul E. McKenney, Nathan Chancellor,
	Nicolas Schier, Miguel Ojeda, Thomas Weißschuh,
	Thomas Gleixner, Douglas Anderson, Gary Guo, Christian Brauner,
	Pasha Tatashin, Coiby Xu, Masahiro Yamada, Frederic Weisbecker,
	linux-doc, linux-kernel, linux-mm, linux-rt-devel,
	Marcelo Tosatti
In-Reply-To: <fec6554d-3639-4c27-9a14-3d3914c51588@infradead.org>

On Wed, May 20, 2026 at 03:06:30PM -0700, Randy Dunlap wrote:
> 
> 
> On 5/18/26 6:27 PM, Leonardo Bras wrote:
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index c2c6d79275c6..7102031207c9 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -21775,20 +21775,27 @@ QORIQ DPAA2 FSL-MC BUS DRIVER
> >  M:	Ioana Ciornei <ioana.ciornei@nxp.com>
> >  L:	linuxppc-dev@lists.ozlabs.org
> >  L:	linux-kernel@vger.kernel.org
> >  S:	Maintained
> >  F:	Documentation/ABI/stable/sysfs-bus-fsl-mc
> >  F:	Documentation/devicetree/bindings/misc/fsl,qoriq-mc.yaml
> >  F:	Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
> >  F:	drivers/bus/fsl-mc/
> >  F:	include/uapi/linux/fsl_mc.h
> >  
> > +PW Locks
> > +M:	Leonardo Bras <leobras.c@gmail.com>
> > +S:	Supported
> > +F:	Documentation/locking/pwlocks.rst
> > +F:	include/linux/pwlocks.h
> > +F:	kernel/pwlocks.c
> 
> MAINTAINERS entries should be in alphabetical order: PW is not in the
> middle of the Q entries.

Hi Randy, thank you for reviewing!

Argh, sorry, it used to be called QPW. I renamed and forgot to reorder.

> 
> > +
> >  QT1010 MEDIA DRIVER
> >  L:	linux-media@vger.kernel.org
> >  S:	Orphan
> >  W:	https://linuxtv.org
> >  Q:	http://patchwork.linuxtv.org/project/linux-media/list/
> >  F:	drivers/media/tuners/qt1010*
> >  
> >  QUALCOMM ATH12K WIRELESS DRIVER
> >  M:	Jeff Johnson <jjohnson@kernel.org>
> >  L:	linux-wireless@vger.kernel.org
> 
> 
> > diff --git a/Documentation/locking/pwlocks.rst b/Documentation/locking/pwlocks.rst
> > new file mode 100644
> > index 000000000000..09f4a5417bc1
> > --- /dev/null
> > +++ b/Documentation/locking/pwlocks.rst
> > @@ -0,0 +1,76 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +=========
> > +PW (Per-CPU Work) locks
> > +=========
> 
> Overline and underline should be at least as long as the heading text.
>

Noted!
 
> > +
> > +Some places in the kernel implement a parallel programming strategy
> > +consisting on local_locks() for most of the work, and some rare remote
> > +operations are scheduled on target cpu. This keeps cache bouncing low since
> 
>                             on a target CPU.

Right

> 
> > +cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> > +kernels, even though the very few remote operations will be expensive due
> > +to scheduling overhead.
> > +
> > +On the other hand, for RT workloads this can represent a problem:
> > +scheduling work on remote cpu that are executing low latency tasks
> 
>                              CPUs

Will fix


> 
> > +is undesired and can introduce unexpected deadline misses.
> 
>       undesirable
> ?

Yes

> 
> > +
> > +PW locks help to convert sites that use local_locks (for cpu local operations)
> > +and queue_work_on (for queueing work remotely, to be executed
> > +locally on the owner cpu of the lock) to a spinlocks.
> 
>                                          to spinlocks.
> 

Right

> > +
> > +The lock is declared pw_lock_t type.
> > +The lock is initialized with pw_lock_init.
> > +The lock is locked with pw_lock (takes a lock and cpu as a parameter).
> > +The lock is unlocked with pw_unlock (takes a lock and cpu as a parameter).
> > +
> > +The pw_lock_irqsave function disables interrupts and saves current interrupt state,
> > +cpu as a parameter.
> > +
> > +For trylock variant, there is the pw_trylock_t type, initialized with
> > +pw_trylock_init. Then the corresponding pw_trylock and pw_trylock_irqsave.
> > +
> > +work_struct should be replaced by pw_struct, which contains a cpu parameter
> > +(owner cpu of the lock), initialized by INIT_PW.
> > +
> > +The queue work related functions (analogous to queue_work_on and flush_work) are:
> > +pw_queue_on and pw_flush.
> > +
> > +The behaviour of the PW lock functions is as follows:
> > +
> > +* !CONFIG_PWLOCKS (or CONFIG_PWLOCKS and pwlocks=off kernel boot parameter):
> > +        - pw_lock:			local_lock
> > +        - pw_lock_irqsave:		local_lock_irqsave
> > +        - pw_trylock:			local_trylock
> > +        - pw_trylock_irqsave:		local_trylock_irqsave
> > +        - pw_unlock:			local_unlock
> > +        - pw_lock_local:		local_lock
> > +        - pw_trylock_local:		local_trylock
> > +        - pw_unlock_local:		local_unlock
> > +        - pw_queue_on:         		queue_work_on
> > +        - pw_flush:	            	flush_work
> > +
> > +* CONFIG_PWLOCKS (and CONFIG_PWLOCKS_DEFAULT=y or pwlocks=on kernel boot parameter),
> > +        - pw_lock:			spin_lock
> > +        - pw_lock_irqsave:		spin_lock_irqsave
> > +        - pw_trylock:			spin_trylock
> > +        - pw_trylock_irqsave:		spin_trylock_irqsave
> > +        - pw_unlock:			spin_unlock
> > +        - pw_lock_local:		preempt_disable OR migrate_disable + spin_lock
> > +        - pw_trylock_local:		preempt_disable OR migrate_disable + spin_trylock
> > +        - pw_unlock_local:		preempt_enable OR migrate_enable + spin_unlock
> > +        - pw_queue_on:         		executes work function on caller cpu
> > +        - pw_flush:            		empty
> > +
> > +pw_get_cpu(work_struct), to be called from within per-cpu work function,
> > +returns the target cpu.
> 
>                       CPU.
> 

Will fix

> > +
> > +On the locking functions above, there are the local locking functions
> > +(pw_lock_local, pw_trylock_local and pw_unlock_local) that must only
> > +be used to access per-CPU data from the CPU that owns that data,
> > +and never remotely. They disable preemption/migration and don't require
> > +a cpu parameter, making them a replacement for local_lock functions that
> > +does not introduce overhead.
> > +
> > +These should only be used when accessing per-CPU data of the local CPU.
> > +
> 
> Running "make htmldocs" with this patch says:
> 
> Documentation/locking/pwlocks.rst: WARNING: document isn't included in any toctree [toc.not_included]
> 

Humm, I will figure out a way of including it in a relevant toctree.

> > diff --git a/init/Kconfig b/init/Kconfig
> > index 2937c4d308ae..3fb751dc4530 100644
> > --- a/init/Kconfig
> > +++ b/init/Kconfig
> > @@ -764,20 +764,55 @@ config CPU_ISOLATION
> >  	depends on SMP
> >  	default y
> >  	help
> >  	  Make sure that CPUs running critical tasks are not disturbed by
> >  	  any source of "noise" such as unbound workqueues, timers, kthreads...
> >  	  Unbound jobs get offloaded to housekeeping CPUs. This is driven by
> >  	  the "isolcpus=" boot parameter.
> >  
> >  	  Say Y if unsure.
> >  
> > +config PWLOCKS
> > +	bool "Per-CPU Work locks"
> > +	depends on SMP || COMPILE_TEST
> > +	default n
> > +	help
> > +	  Allow changing the behavior on per-CPU resource sharing with cache,
> > +	  from the regular local_locks() + queue_work_on(remote_cpu) to using
> > +	  per-CPU spinlocks on both local and remote operations.
> > +
> > +	  This is useful to give user the option on reducing IPIs to CPUs, and
> 
> 	                 to give the user

Right

> 
> > +	  thus reduce interruptions and context switches. On the other hand, it
> > +	  increases generated code and will use atomic operations if spinlocks
> > +	  are selected.
> > +
> > +	  If set, will use the default behavior set in PWLOCKS_DEFAULT unless boot
> 
> 	                                                               unless the boot
> 

Correct

> > +	  parameter pwlocks is passed with a different behavior.
> > +
> > +	  If unset, will use the local_lock() + queue_work_on() strategy,
> > +	  regardless of the boot parameter or PWLOCKS_DEFAULT.
> > +
> > +	  Say N if unsure.
> > +
> > +config PWLOCKS_DEFAULT
> > +	bool "Use per-CPU spinlocks by default on PWLOCKS"
> > +	depends on PWLOCKS
> > +	default n
> > +	help
> > +	  If set, will use per-CPU spinlocks as default behavior for per-CPU
> > +	  remote operations.
> > +
> > +	  If unset, will use local_lock() + queue_work_on(cpu) as default
> > +	  behavior for remote operations.
> > +
> > +	  Say N if unsure
> 
> 	           unsure.
> 

Yeap :)

> > +
> >  source "kernel/rcu/Kconfig"
> >  
> >  config IKCONFIG
> >  	tristate "Kernel .config support"
> >  	help
> >  	  This option enables the complete Linux kernel ".config" file
> >  	  contents to be saved in the kernel. It provides documentation
> >  	  of which kernel options are used in a running kernel or in an
> >  	  on-disk kernel.  This information can be extracted from the kernel
> >  	  image file with the script scripts/extract-ikconfig and used as
> 
> -- 
> ~Randy
> 


Thanks!
Leo

^ permalink raw reply

* Re: [PATCH v4 1/4] Introducing pw_lock() and per-cpu queue & flush work
From: Leonardo Bras @ 2026-07-12 21:32 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Leonardo Bras, Shuah Khan, Peter Zijlstra, Ingo Molnar,
	Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Feng Tang, Dapeng Mi, Kees Cook, Marco Elver,
	Jakub Kicinski, Li RongQing, Eric Biggers, Paul E. McKenney,
	Nathan Chancellor, Nicolas Schier, Miguel Ojeda,
	Thomas Weißschuh, Thomas Gleixner, Douglas Anderson,
	Gary Guo, Christian Brauner, Pasha Tatashin, Coiby Xu,
	Masahiro Yamada, Frederic Weisbecker, linux-doc, linux-kernel,
	linux-mm, linux-rt-devel, Marcelo Tosatti
In-Reply-To: <87tsruvv6z.fsf@trenco.lwn.net>

On Tue, May 26, 2026 at 01:15:32PM -0600, Jonathan Corbet wrote:
> Leonardo Bras <leobras.c@gmail.com> writes:
> 
> > Some places in the kernel implement a parallel programming strategy
> > consisting on local_locks() for most of the work, and some rare remote
> > operations are scheduled on target cpu. This keeps cache bouncing low since
> > cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> > kernels, even though the very few remote operations will be expensive due
> > to scheduling overhead.

Hi Jonathan, thanks for reviewing!

> 
> A couple of documentation-related nits:
> 
> > ---
> >  MAINTAINERS                                   |   7 +
> >  .../admin-guide/kernel-parameters.txt         |  10 +
> >  Documentation/locking/pwlocks.rst             |  76 +++++
> 
> You have added a new RST file here, but haven't added it to the table of
> contents in index.rst.  So it won't be part of the docs build.

Ooops, will find a place to add it then :)

This part was added by Marcelo, I have no experience on adding docs to the 
kernel tree. Your suggestions will be really useful :)


> 
> >  init/Kconfig                                  |  35 +++
> >  kernel/Makefile                               |   2 +
> >  include/linux/pwlocks.h                       | 265 ++++++++++++++++++
> >  kernel/pwlocks.c                              |  47 ++++
> >  7 files changed, 442 insertions(+)
> >  create mode 100644 Documentation/locking/pwlocks.rst
> >  create mode 100644 include/linux/pwlocks.h
> >  create mode 100644 kernel/pwlocks.c
> 
> [...]
> 
> > diff --git a/Documentation/locking/pwlocks.rst b/Documentation/locking/pwlocks.rst
> > new file mode 100644
> > index 000000000000..09f4a5417bc1
> > --- /dev/null
> > +++ b/Documentation/locking/pwlocks.rst
> > @@ -0,0 +1,76 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +=========
> > +PW (Per-CPU Work) locks
> > +=========
> 
> The over/underlines should match the text in length.
> 

Will change!

> > +Some places in the kernel implement a parallel programming strategy
> > +consisting on local_locks() for most of the work, and some rare remote
> > +operations are scheduled on target cpu. This keeps cache bouncing low since
> > +cacheline tends to be mostly local, and avoids the cost of locks in non-RT
> > +kernels, even though the very few remote operations will be expensive due
> > +to scheduling overhead.
> > +
> > +On the other hand, for RT workloads this can represent a problem:
> > +scheduling work on remote cpu that are executing low latency tasks
> > +is undesired and can introduce unexpected deadline misses.
> > +
> > +PW locks help to convert sites that use local_locks (for cpu local operations)
> > +and queue_work_on (for queueing work remotely, to be executed
> > +locally on the owner cpu of the lock) to a spinlocks.
> > +
> > +The lock is declared pw_lock_t type.
> > +The lock is initialized with pw_lock_init.
> > +The lock is locked with pw_lock (takes a lock and cpu as a parameter).
> > +The lock is unlocked with pw_unlock (takes a lock and cpu as a parameter).
> 
> Did you want that to be an itemized list?  If so, put "- " in front of
> each line.

Oh, good idea!

> 
> > +The pw_lock_irqsave function disables interrupts and saves current interrupt state,
> > +cpu as a parameter.
> > +
> > +For trylock variant, there is the pw_trylock_t type, initialized with
> > +pw_trylock_init. Then the corresponding pw_trylock and pw_trylock_irqsave.
> > +
> > +work_struct should be replaced by pw_struct, which contains a cpu parameter
> > +(owner cpu of the lock), initialized by INIT_PW.
> > +
> > +The queue work related functions (analogous to queue_work_on and flush_work) are:
> > +pw_queue_on and pw_flush.
> > +
> > +The behaviour of the PW lock functions is as follows:
> > +
> > +* !CONFIG_PWLOCKS (or CONFIG_PWLOCKS and pwlocks=off kernel boot parameter):
> > +        - pw_lock:			local_lock
> > +        - pw_lock_irqsave:		local_lock_irqsave
> > +        - pw_trylock:			local_trylock
> > +        - pw_trylock_irqsave:		local_trylock_irqsave
> > +        - pw_unlock:			local_unlock
> > +        - pw_lock_local:		local_lock
> > +        - pw_trylock_local:		local_trylock
> > +        - pw_unlock_local:		local_unlock
> > +        - pw_queue_on:         		queue_work_on
> > +        - pw_flush:	            	flush_work
> 
> This will not render the way you expect it to.  You want a literal block
> ere.  So end the text with "...is as follows::"  and indent the entire
> literal block.

Will do like this!

> 
> > +* CONFIG_PWLOCKS (and CONFIG_PWLOCKS_DEFAULT=y or pwlocks=on kernel boot parameter),
> > +        - pw_lock:			spin_lock
> > +        - pw_lock_irqsave:		spin_lock_irqsave
> > +        - pw_trylock:			spin_trylock
> > +        - pw_trylock_irqsave:		spin_trylock_irqsave
> > +        - pw_unlock:			spin_unlock
> > +        - pw_lock_local:		preempt_disable OR migrate_disable + spin_lock
> > +        - pw_trylock_local:		preempt_disable OR migrate_disable + spin_trylock
> > +        - pw_unlock_local:		preempt_enable OR migrate_enable + spin_unlock
> > +        - pw_queue_on:         		executes work function on caller cpu
> > +        - pw_flush:            		empty
> > +
> > +pw_get_cpu(work_struct), to be called from within per-cpu work function,
> > +returns the target cpu.
> > +
> > +On the locking functions above, there are the local locking functions
> > +(pw_lock_local, pw_trylock_local and pw_unlock_local) that must only
> 
> If you write functions like pw_lock_local(), you'll get automatic cross
> links to the kerneldoc documentation ... which I'm sure must exist ...

They will be added at this patch, so I will add the () so the link works :)

> 
> > +be used to access per-CPU data from the CPU that owns that data,
> > +and never remotely. They disable preemption/migration and don't require
> > +a cpu parameter, making them a replacement for local_lock functions that
> > +does not introduce overhead.
> > +
> > +These should only be used when accessing per-CPU data of the local CPU.
> > +
> 
> [...]
> 
> > +#else /* CONFIG_PWLOCKS */
> > +
> > +DECLARE_STATIC_KEY_MAYBE(CONFIG_PWLOCKS_DEFAULT, pw_sl);
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_lock_t ll;
> > +} pw_lock_t;
> > +
> > +typedef union {
> > +	spinlock_t sl;
> > +	local_trylock_t ll;
> > +} pw_trylock_t;
> > +
> > +struct pw_struct {
> > +	struct work_struct work;
> > +	int cpu;
> > +};
> > +
> > +#ifdef CONFIG_PREEMPT_RT
> > +#define preempt_or_migrate_disable migrate_disable
> > +#define preempt_or_migrate_enable migrate_enable
> > +#else
> > +#define preempt_or_migrate_disable preempt_disable
> > +#define preempt_or_migrate_enable preempt_enable
> > +#endif
> > +
> > +#define pw_lock_init(lock)							\
> > +do {										\
> > +	if (static_branch_maybe(CONFIG_PWLOCKS_DEFAULT, &pw_sl))		\
> > +		spin_lock_init(lock.sl);					\
> > +	else									\
> > +		local_lock_init(lock.ll);					\
> > +} while (0)
> 
> Sigh, I guess I was over-optimistic about kerneldoc comments.
> 
> Is there a reason why these aren't inline functions?
> 

I could not find a way of making *_irqsave() an inline function, so ended 
up using macros as they looked simple enough (and the underlying functions 
would take care of type check). Already working on converting as many of 
the above as possible. 

Thanks again for reviewing!

Leo

^ permalink raw reply

* Re: [PATCH v4 3/4] swap: apply new pw_queue_on() interface
From: Leonardo Bras @ 2026-07-12 21:43 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Feng Tang, Dapeng Mi, Kees Cook, Marco Elver,
	Jakub Kicinski, Li RongQing, Eric Biggers, Paul E. McKenney,
	Nathan Chancellor, Nicolas Schier, Miguel Ojeda,
	Thomas Weißschuh, Thomas Gleixner, Douglas Anderson,
	Gary Guo, Christian Brauner, Pasha Tatashin, Coiby Xu,
	Masahiro Yamada, Frederic Weisbecker, linux-doc, linux-kernel,
	linux-mm, linux-rt-devel, Marcelo Tosatti
In-Reply-To: <20260520150736.HZnlFkv7@linutronix.de>

On Wed, May 20, 2026 at 05:07:36PM +0200, Sebastian Andrzej Siewior wrote:
> On 2026-05-18 22:27:49 [-0300], Leonardo Bras wrote:
> 
> after digesting the slub patch,
> 
> > @@ -882,38 +879,38 @@ static inline void __lru_add_drain_all(bool force_all_cpus)
> >  	 * If the paired barrier is done at any later step, e.g. after the
> >  	 * loop, CPU #x will just exit at (C) and miss flushing out all of its
> >  	 * added pages.
> >  	 */
> >  	WRITE_ONCE(lru_drain_gen, lru_drain_gen + 1);
> >  	smp_mb();
> >  
> >  	cpumask_clear(&has_mm_work);
> >  	cpumask_clear(&has_bh_work);
> >  	for_each_online_cpu(cpu) {
> > -		struct work_struct *mm_work = &per_cpu(lru_add_drain_work, cpu);
> > +		struct pw_struct *mm_pw = &per_cpu(lru_add_drain_pw, cpu);
> >  		struct work_struct *bh_work = &per_cpu(bh_add_drain_work, cpu);
> >  
> >  		if (cpu_needs_mm_drain(cpu)) {
> > -			INIT_WORK(mm_work, lru_add_drain_per_cpu);
> > -			queue_work_on(cpu, mm_percpu_wq, mm_work);
> > +			INIT_PW(mm_pw, lru_add_drain_per_cpu, cpu);
> > +			pw_queue_on(cpu, mm_percpu_wq, mm_pw);
> >  			__cpumask_set_cpu(cpu, &has_mm_work);
> >  		}
> >  
> >  		if (cpu_needs_bh_drain(cpu)) {
> >  			INIT_WORK(bh_work, bh_add_drain_per_cpu);
> >  			queue_work_on(cpu, mm_percpu_wq, bh_work);
> >  			__cpumask_set_cpu(cpu, &has_bh_work);
> >  		}
> >  	}
> >  
> >  	for_each_cpu(cpu, &has_mm_work)
> > -		flush_work(&per_cpu(lru_add_drain_work, cpu));
> > +		pw_flush(&per_cpu(lru_add_drain_pw, cpu));
> >  
> >  	for_each_cpu(cpu, &has_bh_work)
> >  		flush_work(&per_cpu(bh_add_drain_work, cpu));
> 
> Why do we have two iterations here? Is it just a proof of concept that
> is not complete yet? I am curious why it is okay/needed to "remove" the
> one workqueue but not the other. Maybe the other does not bother as much
> as the other does.

Argh, sorry about the above :/

Slub was converted on a previous patchset version, and rebasing worked 
fine. I should have properly checked if any other mechanism was added in 
the file, but ended up just checking the one that was already converted.

> 
> But essentially we can't use a spin_lock_t here because due to the
> hotpath nature of the code it will kill performance. 

Correct

> So instead we do it
> anyway but behind a switch so that only those suffer from this that do
> not want to suffer from workqueue interruption on a NOHZ full system,
> right?

Yes, one can choose to pay the price to use spinlocks here and have less 
workqueue interruptions, if !CONFIG_PREEMPT_RT

In case of CONFIG_PREEMPT_RT, we have the local_lock() already becoming a 
rt_spinlock(), so it already pays the price to hold the lock. So it should 
be basically free on this scenario, and save time by doing the operation 
remotelly instead of scheduling it.
 
> 
> I thought that this improved since commit
>   ff042f4a9b050 ("mm: lru_cache_disable: replace work queue synchronization with synchronize_rcu")
> 
> Did it get worse or was it not entirely gone?
> 

I worked in this patchset majorly after that commit date, and it was still 
an issue up to last time Marcelo tested. Not sure of the impact of above 
commit, but I suppose it may have brought some improvements without fully 
fixing it.

Thanks!
Leo

^ permalink raw reply

* Re: [PATCH v7 10/10] RAS: add firmware-first CPER provider
From: Uwe Kleine-König @ 2026-07-12 22:21 UTC (permalink / raw)
  To: Ahmed Tiba
  Cc: Rafael J. Wysocki, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Len Brown, Saket Dumbre,
	Davidlohr Bueso, Jonathan Cameron, Dave Jiang, Alison Schofield,
	Vishal Verma, Dan Williams, Ira Weiny, Li Ming,
	Mahesh J Salgaonkar, Oliver O'Halloran, Bjorn Helgaas,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
	Shuah Khan, linux-kernel, linux-acpi, acpica-devel, linux-cxl,
	linuxppc-dev, linux-pci, devicetree, linux-edac, linux-doc,
	Dmitry.Lamerov
In-Reply-To: <20260708-topics-ahmtib01-ras_ffh_arm_internal_review-v7-10-8b3a85216cef@arm.com>

[-- Attachment #1: Type: text/plain, Size: 244 bytes --]

Hello Ahmed,

On Wed, Jul 08, 2026 at 02:59:09PM +0100, Ahmed Tiba wrote:
> +#include <linux/mod_devicetable.h>

Please don't add new users for this header file. Only use those
<linux/device-id/*.h> that you actually need (if any).

Thanks
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v4 4/4] slub: apply new pw_queue_on() interface
From: Leonardo Bras @ 2026-07-12 22:35 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Leonardo Bras, Jonathan Corbet, Shuah Khan, Peter Zijlstra,
	Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Jann Horn, Pedro Falcato, Brendan Jackman, Johannes Weiner,
	Zi Yan, Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
	Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Borislav Petkov (AMD),
	Randy Dunlap, Feng Tang, Dapeng Mi, Kees Cook, Marco Elver,
	Jakub Kicinski, Li RongQing, Eric Biggers, Paul E. McKenney,
	Nathan Chancellor, Nicolas Schier, Miguel Ojeda,
	Thomas Weißschuh, Thomas Gleixner, Douglas Anderson,
	Gary Guo, Christian Brauner, Pasha Tatashin, Coiby Xu,
	Masahiro Yamada, Frederic Weisbecker, linux-doc, linux-kernel,
	linux-mm, linux-rt-devel, Marcelo Tosatti
In-Reply-To: <20260520145308.nay9zt6r@linutronix.de>

On Wed, May 20, 2026 at 04:53:08PM +0200, Sebastian Andrzej Siewior wrote:
> On 2026-05-18 22:27:50 [-0300], Leonardo Bras wrote:
> > @@ -4733,121 +4735,121 @@ void *alloc_from_pcs(struct kmem_cache *s, gfp_t gfp, int node)
> >  
> >  	/*
> >  	 * We assume the percpu sheaves contain only local objects although it's
> >  	 * not completely guaranteed, so we verify later.
> >  	 */
> >  	if (unlikely(node_requested && node != numa_mem_id())) {
> >  		stat(s, ALLOC_NODE_MISMATCH);
> >  		return NULL;
> >  	}
> >  
> > -	if (!local_trylock(&s->cpu_sheaves->lock))
> > +	if (!pw_trylock_local(&s->cpu_sheaves->lock))
> >  		return NULL;
> 
> alloc_from_pcs() can be called from kmalloc_nolock()/ NMI context.
> I don't remember why exactly local_trylock_t was introduced here instead
> of a per-CPU spinlock_t. 

Probably to save the cost of using atomic operations on locking, and having 
about the same restrictions that would allow using local_locks

> But there should be nothing wrong with a
> trylock on it from NMI as you do here.

Awesome!

> 
> One thing worth noting, on !PREEMPT_RT, spin_trylock() always succeeds
> on UP. kmalloc_nolock() checks for it, not sure about other callers.


Sorry, I did not sure I understand that part. 
You mean we have since it always returns true, we may be in NMI context, 
after it was interrupted holding this lock, and it will return true which 
will use the protected area even though the lock should avoid it?

Humm, but if that scenario exist, then is it actually ok to return true on 
trylock() in that scenario?

Thanks!
Leo

^ permalink raw reply

* [PATCH v2 1/4] docs/zh_CN: Update rust/quick-start.rst translation
From: Ben Guo @ 2026-07-13  1:46 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <cover.1783905132.git.ben.guo@openatom.club>

Update Documentation/rust/quick-start.rst translation.

Update the translation through commit a4392ed1c8b9
("docs: rust: quick-start: remove GDB/Binutils mention")

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Ben Guo <ben.guo@openatom.club>
---
 .../translations/zh_CN/rust/quick-start.rst   | 48 ++++++++-----------
 1 file changed, 19 insertions(+), 29 deletions(-)

diff --git a/Documentation/translations/zh_CN/rust/quick-start.rst b/Documentation/translations/zh_CN/rust/quick-start.rst
index 5f0ece6411f..0396137f3c1 100644
--- a/Documentation/translations/zh_CN/rust/quick-start.rst
+++ b/Documentation/translations/zh_CN/rust/quick-start.rst
@@ -59,7 +59,7 @@ Fedora Linux 提供较新的 Rust 版本,因此通常开箱即用,例如::
 Gentoo Linux
 ************
 
-Gentoo Linux(尤其是 testing 分支)提供较新的 Rust 版本,因此通常开箱即用,
+Gentoo Linux 提供较新的 Rust 版本,因此通常开箱即用,
 例如::
 
 	USE='rust-src rustfmt clippy' emerge dev-lang/rust dev-util/bindgen
@@ -70,7 +70,7 @@ Gentoo Linux(尤其是 testing 分支)提供较新的 Rust 版本,因此
 Nix
 ***
 
-Nix(unstable 频道)提供较新的 Rust 版本,因此通常开箱即用,例如::
+Nix 提供较新的 Rust 版本,因此通常开箱即用,例如::
 
 	{ pkgs ? import <nixpkgs> {} }:
 	pkgs.mkShell {
@@ -85,16 +85,14 @@ openSUSE
 openSUSE Slowroll 和 openSUSE Tumbleweed 提供较新的 Rust 版本,因此通常开箱
 即用,例如::
 
-	zypper install rust rust1.79-src rust-bindgen clang
+	zypper install rust rust-src rust-bindgen clang
 
 
 Ubuntu
 ******
 
-25.04
-~~~~~
-
-最新的 Ubuntu 版本提供较新的 Rust 版本,因此通常开箱即用,例如::
+Ubuntu 25.10 和 26.04 LTS 提供较新的 Rust 版本,因此通常开箱即用,
+例如::
 
 	apt install rustc rust-src bindgen rustfmt rust-clippy
 
@@ -111,32 +109,32 @@ Ubuntu
 虽然 Ubuntu 24.04 LTS 及更早版本仍然提供较新的 Rust 版本,但它们需要一些额外的配
 置,使用带版本号的软件包,例如::
 
-	apt install rustc-1.80 rust-1.80-src bindgen-0.65 rustfmt-1.80 \
-		rust-1.80-clippy
-	ln -s /usr/lib/rust-1.80/bin/rustfmt /usr/bin/rustfmt-1.80
-	ln -s /usr/lib/rust-1.80/bin/clippy-driver /usr/bin/clippy-driver-1.80
+	apt install rustc-1.85 rust-1.85-src bindgen-0.71 rustfmt-1.85 \
+		rust-1.85-clippy
+	ln -s /usr/lib/rust-1.85/bin/rustfmt /usr/bin/rustfmt-1.85
+	ln -s /usr/lib/rust-1.85/bin/clippy-driver /usr/bin/clippy-driver-1.85
 
 这些软件包都不会将其工具设置为默认值;因此应该显式指定它们,例如::
 
-	make LLVM=1 RUSTC=rustc-1.80 RUSTDOC=rustdoc-1.80 RUSTFMT=rustfmt-1.80 \
-		CLIPPY_DRIVER=clippy-driver-1.80 BINDGEN=bindgen-0.65
+	make LLVM=1 RUSTC=rustc-1.85 RUSTDOC=rustdoc-1.85 RUSTFMT=rustfmt-1.85 \
+		CLIPPY_DRIVER=clippy-driver-1.85 BINDGEN=bindgen-0.71
 
-或者,修改 ``PATH`` 变量将 Rust 1.80 的二进制文件放在前面,并将 ``bindgen`` 设
+或者,修改 ``PATH`` 变量将 Rust 1.85 的二进制文件放在前面,并将 ``bindgen`` 设
 置为默认值,例如::
 
-	PATH=/usr/lib/rust-1.80/bin:$PATH
+	PATH=/usr/lib/rust-1.85/bin:$PATH
 	update-alternatives --install /usr/bin/bindgen bindgen \
-		/usr/bin/bindgen-0.65 100
-	update-alternatives --set bindgen /usr/bin/bindgen-0.65
+		/usr/bin/bindgen-0.71 100
+	update-alternatives --set bindgen /usr/bin/bindgen-0.71
 
-使用带版本号的软件包时需要设置 ``RUST_LIB_SRC``,例如::
+使用带版本号的软件包时可能需要设置 ``RUST_LIB_SRC``,例如::
 
-	RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.80 --version | cut -d' ' -f2)/library
+	RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.85 --version | cut -d' ' -f2)/library
 
 为方便起见,可以将 ``RUST_LIB_SRC`` 导出到全局环境中。
 
-此外, ``bindgen-0.65`` 在较新的版本(24.04 LTS 和 24.10)中可用,但在更早的版
-本(20.04 LTS 和 22.04 LTS)中可能不可用,因此可能需要手动构建 ``bindgen``
+此外, ``bindgen-0.71`` 在较新的版本(24.04 LTS)中可用,但在更早的版本
+(20.04 LTS 和 22.04 LTS)中可能不可用,因此可能需要手动构建 ``bindgen``
 (请参见下文)。
 
 
@@ -325,11 +323,3 @@ Rust支持(CONFIG_RUST)需要在 ``General setup`` 菜单中启用。在其
 
 要想深入了解,请看 ``samples/rust/`` 下的样例源代码、 ``rust/`` 下的Rust支持代码和
 ``Kernel hacking`` 下的 ``Rust hacking`` 菜单。
-
-如果使用的是GDB/Binutils,而Rust符号没有被demangled,原因是工具链还不支持Rust的新v0
-mangling方案。有几个办法可以解决:
-
-- 安装一个较新的版本(GDB >= 10.2, Binutils >= 2.36)。
-
-- 一些版本的GDB(例如vanilla GDB 10.1)能够使用嵌入在调试信息(``CONFIG_DEBUG_INFO``)
-  中的pre-demangled的名字。
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 0/4] docs/zh_CN: update rust documentation translations
From: Ben Guo @ 2026-07-13  1:46 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches

Update Chinese translations for the Rust subsystem documentation,
syncing with the latest upstream changes.

- quick-start.rst: update distro-specific install instructions, Ubuntu
  package versions, openSUSE rust-src package, and remove GDB/Binutils note
- general-information.rst: add no_std section, rustdoc links, abstractions
  and bindings diagram, Bindings/Abstractions sections, and Kconfig example
- arch-support.rst: add s390 support note
- testing.rst: add Kconfig guidance for KUnit test suites

Changes in v2:
- Add Reviewed-by from Gary Guo
- Translate "sound" as "可靠" in general-information.rst

Ben Guo (4):
  docs/zh_CN: Update rust/quick-start.rst translation
  docs/zh_CN: Update rust/general-information.rst translation
  docs/zh_CN: Update rust/arch-support.rst translation
  docs/zh_CN: Update rust/testing.rst translation

 .../translations/zh_CN/rust/arch-support.rst  |  1 +
 .../zh_CN/rust/general-information.rst        | 82 ++++++++++++++++++-
 .../translations/zh_CN/rust/quick-start.rst   | 48 +++++------
 .../translations/zh_CN/rust/testing.rst       |  4 +
 4 files changed, 103 insertions(+), 32 deletions(-)

-- 
2.53.0

^ permalink raw reply

* [PATCH v2 4/4] docs/zh_CN: Update rust/testing.rst translation
From: Ben Guo @ 2026-07-13  1:46 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <cover.1783905132.git.ben.guo@openatom.club>

Update Documentation/rust/testing.rst translation.

Update the translation through commit 09699b24199a
("Documentation: rust: testing: add Kconfig guidance")

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Ben Guo <ben.guo@openatom.club>
---
 Documentation/translations/zh_CN/rust/testing.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/translations/zh_CN/rust/testing.rst b/Documentation/translations/zh_CN/rust/testing.rst
index ca81f1cef6e..6747d001299 100644
--- a/Documentation/translations/zh_CN/rust/testing.rst
+++ b/Documentation/translations/zh_CN/rust/testing.rst
@@ -128,10 +128,13 @@ Rust 测试中常用的断言宏是来自 Rust 标准库( ``core`` )中的 `
 
 这些测试通过 ``kunit_tests`` 过程宏引入,该宏将测试套件的名称作为参数。
 
+每个测试套件都应该由 ``rust/kernel/Kconfig.test`` 中的 Kconfig 选项保护。
+
 例如,假设想要测试前面文档测试示例中的函数 ``f``,我们可以在定义该函数的同一文件中编写:
 
 .. code-block:: rust
 
+	#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
 	#[kunit_tests(rust_kernel_mymod)]
 	mod tests {
 	    use super::*;
@@ -158,6 +161,7 @@ Rust 测试中常用的断言宏是来自 Rust 标准库( ``core`` )中的 `
 
 .. code-block:: rust
 
+	#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
 	#[kunit_tests(rust_kernel_mymod)]
 	mod tests {
 	    use super::*;
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 2/4] docs/zh_CN: Update rust/general-information.rst translation
From: Ben Guo @ 2026-07-13  1:46 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <cover.1783905132.git.ben.guo@openatom.club>

Update Documentation/rust/general-information.rst translation.

Update the translation through commit 86c5d1c6740c
("docs: rust: general-information: use real example")

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Ben Guo <ben.guo@openatom.club>
---
 .../zh_CN/rust/general-information.rst        | 82 ++++++++++++++++++-
 1 file changed, 79 insertions(+), 3 deletions(-)

diff --git a/Documentation/translations/zh_CN/rust/general-information.rst b/Documentation/translations/zh_CN/rust/general-information.rst
index 9b5e37e13f3..ff9355cb8c8 100644
--- a/Documentation/translations/zh_CN/rust/general-information.rst
+++ b/Documentation/translations/zh_CN/rust/general-information.rst
@@ -13,6 +13,14 @@
 
 本文档包含了在内核中使用Rust支持时需要了解的有用信息。
 
+``no_std``
+----------
+
+内核中的 Rust 支持只能链接 `core <https://doc.rust-lang.org/core/>`_,
+而不能链接 `std <https://doc.rust-lang.org/std/>`_。供内核使用的 crate
+必须使用 ``#![no_std]`` 属性选择这种行为。
+
+
 .. _rust_code_documentation_zh_cn:
 
 代码文档
@@ -20,10 +28,18 @@
 
 Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
 
-生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。它们可以在以下地址阅读
-(TODO:当在主线中时链接,与其他文档一起生成):
+生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。
+它们可以在以下地址阅读:
+
+		https://rust.docs.kernel.org
+
+对于 linux-next,请参阅:
 
-	http://kernel.org/
+		https://rust.docs.kernel.org/next/
+
+每个主要版本也有对应的标签,例如:
+
+		https://rust.docs.kernel.org/6.10/
 
 这些文档也可以很容易地在本地生成和阅读。这相当快(与编译代码本身的顺序相同),而且不需要特
 殊的工具或环境。这有一个额外的好处,那就是它们将根据所使用的特定内核配置进行定制。要生成它
@@ -62,6 +78,58 @@ Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
 模块(例如,驱动程序)不应该直接使用C语言的绑定。相反,子系统应该根据需要提供尽可能安
 全的抽象。
 
+.. code-block::
+
+	                                                rust/bindings/
+	                                               (rust/helpers/)
+
+	                                                   include/ -----+ <-+
+	                                                                 |   |
+	  drivers/              rust/kernel/              +----------+ <-+   |
+	    fs/                                           | bindgen  |       |
+	   .../            +-------------------+          +----------+ --+   |
+	                   |    Abstractions   |                         |   |
+	+---------+        | +------+ +------+ |          +----------+   |   |
+	| my_foo  | -----> | | foo  | | bar  | | -------> | Bindings | <-+   |
+	| driver  |  Safe  | | sub- | | sub- | |  Unsafe  |          |       |
+	+---------+        | |system| |system| |          | bindings | <-----+
+	     |             | +------+ +------+ |          |  crate   |       |
+	     |             |   kernel crate    |          +----------+       |
+	     |             +-------------------+                             |
+	     |                                                               |
+	     +------------------# FORBIDDEN #--------------------------------+
+
+主要思想是将所有与内核 C API 的直接交互封装到经过仔细审查和文档化的抽象
+中。这样,只要满足以下条件,这些抽象的用户就不能引入未定义行为
+(undefined behavior,UB):
+
+#. 抽象是正确的("可靠")。
+#. 任何 ``unsafe`` 块都遵守调用块内操作所需的安全契约。类似地,任何
+   ``unsafe impl`` 都遵守实现该特性所需的安全契约。
+
+绑定
+~~~~
+
+通过从 ``include/`` 中将 C 头文件包含到
+``rust/bindings/bindings_helper.h``, ``bindgen`` 工具将为所包含的子系统
+自动生成绑定。构建后,请查看 ``rust/bindings/`` 目录中的
+``*_generated.rs`` 输出文件。
+
+对于 ``bindgen`` 不会自动生成的 C 头文件部分,例如 C ``inline`` 函数或
+非平凡宏,可以在 ``rust/helpers/`` 中添加一个小型包装函数,使其也可供
+Rust 端使用。
+
+抽象
+~~~~
+
+抽象是绑定和内核内用户之间的层。它们位于 ``rust/kernel/`` 中,其作用是
+将对绑定的不安全访问封装到尽可能安全并暴露给用户的 API 中。抽象的用户
+包括用 Rust 编写的驱动程序或文件系统等。
+
+除了安全方面,这些抽象还应该易于使用,也就是说,把 C 接口转换为符合
+Rust 惯例的代码。基本示例包括将 C 的资源获取和释放转换为 Rust 的初始化
+和清理模式,或者将 C 整数错误码转换为 Rust 的 ``Result``。
+
 
 有条件的编译
 ------------
@@ -74,3 +142,11 @@ Rust代码可以访问基于内核配置的条件性编译:
 	#[cfg(CONFIG_X="y")]   // Enabled as a built-in (`y`)
 	#[cfg(CONFIG_X="m")]   // Enabled as a module   (`m`)
 	#[cfg(not(CONFIG_X))]  // Disabled
+
+对于 Rust 的 ``cfg`` 不支持的其他条件,例如带有数值比较的表达式,可以
+定义一个新的 Kconfig 符号:
+
+.. code-block:: kconfig
+
+	config RUSTC_HAS_SPAN_FILE
+		def_bool RUSTC_VERSION >= 108800
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 3/4] docs/zh_CN: Update rust/arch-support.rst translation
From: Ben Guo @ 2026-07-13  1:46 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <cover.1783905132.git.ben.guo@openatom.club>

Update Documentation/rust/arch-support.rst translation.

Update the translation through commit 3f70ebe63858
("s390: Enable Rust support")

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Ben Guo <ben.guo@openatom.club>
---
 Documentation/translations/zh_CN/rust/arch-support.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/translations/zh_CN/rust/arch-support.rst b/Documentation/translations/zh_CN/rust/arch-support.rst
index f5ae44588a5..0ca4be6e176 100644
--- a/Documentation/translations/zh_CN/rust/arch-support.rst
+++ b/Documentation/translations/zh_CN/rust/arch-support.rst
@@ -23,6 +23,7 @@
 ``arm64``      Maintained        仅小端序。
 ``loongarch``  Maintained        \-
 ``riscv``      Maintained        仅 ``riscv64``,且仅限 LLVM/Clang。
+``s390``       Maintained        必须禁用 ``CONFIG_EXPOLINE``。
 ``um``         Maintained        \-
 ``x86``        Maintained        仅 ``x86_64``。
 =============  ================  ==============================================
-- 
2.53.0

^ permalink raw reply related

* RE: [PATCH v2 1/5] dt-bindings: hwmon: (pmbus/max20830): add enable-gpios property and complete examples
From: Torreno, Alexis Czezar @ 2026-07-13  1:55 UTC (permalink / raw)
  To: Guenter Roeck, Krzysztof Kozlowski
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
	Shuah Khan, linux-hwmon@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-doc@vger.kernel.org
In-Reply-To: <6c26aa82-2efe-4493-8992-b6d2c5889fe5@roeck-us.net>


> >>>> How did you address previous feedback?
> >>>>
> >>>
> >>> Regarding the enable pin, I added this since I know bindings like
> >>> being complete and saw that I didn't add it the first time I submitted
> max20830.
> >>> I added driver code for the gpio but learned that it wasn't really a
> >>> use case so I simply dropped the patch for it.
> >>>
> >>
> >> I guess I am completely missing the point here. I can not imagine a
> >> situation where one would want to connect the enable pin to a
> >> driver-controlled GPIO pin, or why would one connect the chip's PGOOD
> >> output pin to a GPIO input pin and connect that back to the driver.
> >>
> >> I think we will need guidance from devicetree maintainers explaining
> >> what "complete" means in such a context to avoid having to repeat
> >> this discussion for every driver going forward.
> >
> > I think complete means all reasonable hardware resources/properties,
> > regardless whether current OS implementation uses them or not. That's
> > why if there is enable-gpios which is not used by Linux but could be
> > in the future, then it should be documented.
> >
> > However if you claim that enable-gpios will absolutely NEVER be used
> > by Linux or bootloader or any other DT bindings user (*BSD, Barebox,
> > U-boot etc), then I would skip it, just like we do not describe many
> > other parts which simply have no use for the software.
> >
> > IOW, DTS is description of non-discoverable hardware for the software.
> > We do not describe hardware for the sake of description, to mirror
> > schematics. That's not the goal. The goal is to make some software
> > happy, even if this is a future software implementation.
> >
> > What is the case here - I rely on your guidance whether enable-gpios
> > can EVER be used by software. If there is a chance, then IMO property
> > could stay.
> >
> 
> Unfortunately, as it turns out, some of the chips handled by this driver do _not_
> implement software-override for the enable pin (or at least so I am told; the
> chip datasheets are not public). Given that, we will have to support the enable
> pin property.
> 
> Sorry, I was not aware of this detail.
> 

Just to straighten possible mix up of parts/submissions (sad they all start with 'max20')

The parts that have no software override for the enable pin are MAX20912, MAX20916
and other chips that we would be submitting with it (as the original submitter
deferred to us to submit our series instead + the datasheet)

This series deal with MAX20830, and MAX20830C/MAX20840C.
In relation to the discussion above about the enable-gpio and "completeness", the parts
here don't have anything special to their enables.
With the clarification that the DTS goal isn't just to describe for the sake of
mirroring schematics, then this patch I believe can be dropped as well.

Can drop in v3 after the other patches gets reviewed.

Thanks again for the clarification!,
Alexis

^ permalink raw reply

* Re: [PATCH v2 1/4] docs/zh_CN: Update rust/quick-start.rst translation
From: Dongliang Mu @ 2026-07-13  2:33 UTC (permalink / raw)
  To: Ben Guo, Alex Shi, Yanteng Si, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <78a525ba7344a334bc70664b34327dbb51024e90.1783905132.git.ben.guo@openatom.club>


On 7/13/26 9:46 AM, Ben Guo wrote:
> Update Documentation/rust/quick-start.rst translation.
>
> Update the translation through commit a4392ed1c8b9
> ("docs: rust: quick-start: remove GDB/Binutils mention")
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
> Signed-off-by: Ben Guo <ben.guo@openatom.club>
> ---
>   .../translations/zh_CN/rust/quick-start.rst   | 48 ++++++++-----------
>   1 file changed, 19 insertions(+), 29 deletions(-)
>
> diff --git a/Documentation/translations/zh_CN/rust/quick-start.rst b/Documentation/translations/zh_CN/rust/quick-start.rst
> index 5f0ece6411f..0396137f3c1 100644
> --- a/Documentation/translations/zh_CN/rust/quick-start.rst
> +++ b/Documentation/translations/zh_CN/rust/quick-start.rst
> @@ -59,7 +59,7 @@ Fedora Linux 提供较新的 Rust 版本,因此通常开箱即用,例如::
>   Gentoo Linux
>   ************
>   
> -Gentoo Linux(尤其是 testing 分支)提供较新的 Rust 版本,因此通常开箱即用,
> +Gentoo Linux 提供较新的 Rust 版本,因此通常开箱即用,
>   例如::
>   
>   	USE='rust-src rustfmt clippy' emerge dev-lang/rust dev-util/bindgen
> @@ -70,7 +70,7 @@ Gentoo Linux(尤其是 testing 分支)提供较新的 Rust 版本,因此
>   Nix
>   ***
>   
> -Nix(unstable 频道)提供较新的 Rust 版本,因此通常开箱即用,例如::
> +Nix 提供较新的 Rust 版本,因此通常开箱即用,例如::
>   
>   	{ pkgs ? import <nixpkgs> {} }:
>   	pkgs.mkShell {
> @@ -85,16 +85,14 @@ openSUSE
>   openSUSE Slowroll 和 openSUSE Tumbleweed 提供较新的 Rust 版本,因此通常开箱
>   即用,例如::
>   
> -	zypper install rust rust1.79-src rust-bindgen clang
> +	zypper install rust rust-src rust-bindgen clang
>   
>   
>   Ubuntu
>   ******
>   
> -25.04
> -~~~~~
> -
> -最新的 Ubuntu 版本提供较新的 Rust 版本,因此通常开箱即用,例如::
> +Ubuntu 25.10 和 26.04 LTS 提供较新的 Rust 版本,因此通常开箱即用,
> +例如::
>   
>   	apt install rustc rust-src bindgen rustfmt rust-clippy
>   
> @@ -111,32 +109,32 @@ Ubuntu
>   虽然 Ubuntu 24.04 LTS 及更早版本仍然提供较新的 Rust 版本,但它们需要一些额外的配
>   置,使用带版本号的软件包,例如::
>   
> -	apt install rustc-1.80 rust-1.80-src bindgen-0.65 rustfmt-1.80 \
> -		rust-1.80-clippy
> -	ln -s /usr/lib/rust-1.80/bin/rustfmt /usr/bin/rustfmt-1.80
> -	ln -s /usr/lib/rust-1.80/bin/clippy-driver /usr/bin/clippy-driver-1.80
> +	apt install rustc-1.85 rust-1.85-src bindgen-0.71 rustfmt-1.85 \
> +		rust-1.85-clippy
> +	ln -s /usr/lib/rust-1.85/bin/rustfmt /usr/bin/rustfmt-1.85
> +	ln -s /usr/lib/rust-1.85/bin/clippy-driver /usr/bin/clippy-driver-1.85
>   
>   这些软件包都不会将其工具设置为默认值;因此应该显式指定它们,例如::
>   
> -	make LLVM=1 RUSTC=rustc-1.80 RUSTDOC=rustdoc-1.80 RUSTFMT=rustfmt-1.80 \
> -		CLIPPY_DRIVER=clippy-driver-1.80 BINDGEN=bindgen-0.65
> +	make LLVM=1 RUSTC=rustc-1.85 RUSTDOC=rustdoc-1.85 RUSTFMT=rustfmt-1.85 \
> +		CLIPPY_DRIVER=clippy-driver-1.85 BINDGEN=bindgen-0.71
>   
> -或者,修改 ``PATH`` 变量将 Rust 1.80 的二进制文件放在前面,并将 ``bindgen`` 设
> +或者,修改 ``PATH`` 变量将 Rust 1.85 的二进制文件放在前面,并将 ``bindgen`` 设
>   置为默认值,例如::
>   
> -	PATH=/usr/lib/rust-1.80/bin:$PATH
> +	PATH=/usr/lib/rust-1.85/bin:$PATH
>   	update-alternatives --install /usr/bin/bindgen bindgen \
> -		/usr/bin/bindgen-0.65 100
> -	update-alternatives --set bindgen /usr/bin/bindgen-0.65
> +		/usr/bin/bindgen-0.71 100
> +	update-alternatives --set bindgen /usr/bin/bindgen-0.71
>   
> -使用带版本号的软件包时需要设置 ``RUST_LIB_SRC``,例如::
> +使用带版本号的软件包时可能需要设置 ``RUST_LIB_SRC``,例如::
>   
> -	RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.80 --version | cut -d' ' -f2)/library
> +	RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.85 --version | cut -d' ' -f2)/library
>   
>   为方便起见,可以将 ``RUST_LIB_SRC`` 导出到全局环境中。
>   
> -此外, ``bindgen-0.65`` 在较新的版本(24.04 LTS 和 24.10)中可用,但在更早的版
> -本(20.04 LTS 和 22.04 LTS)中可能不可用,因此可能需要手动构建 ``bindgen``
> +此外, ``bindgen-0.71`` 在较新的版本(24.04 LTS)中可用,但在更早的版本
> +(20.04 LTS 和 22.04 LTS)中可能不可用,因此可能需要手动构建 ``bindgen``
>   (请参见下文)。
>   
>   
> @@ -325,11 +323,3 @@ Rust支持(CONFIG_RUST)需要在 ``General setup`` 菜单中启用。在其
>   
>   要想深入了解,请看 ``samples/rust/`` 下的样例源代码、 ``rust/`` 下的Rust支持代码和
>   ``Kernel hacking`` 下的 ``Rust hacking`` 菜单。
> -
> -如果使用的是GDB/Binutils,而Rust符号没有被demangled,原因是工具链还不支持Rust的新v0
> -mangling方案。有几个办法可以解决:
> -
> -- 安装一个较新的版本(GDB >= 10.2, Binutils >= 2.36)。
> -
> -- 一些版本的GDB(例如vanilla GDB 10.1)能够使用嵌入在调试信息(``CONFIG_DEBUG_INFO``)
> -  中的pre-demangled的名字。


^ permalink raw reply

* Re: [PATCH v2 2/4] docs/zh_CN: Update rust/general-information.rst translation
From: Dongliang Mu @ 2026-07-13  2:37 UTC (permalink / raw)
  To: Ben Guo, Alex Shi, Yanteng Si, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <f7c671881801e1b24fa2965b2e730d0fb0931e32.1783905132.git.ben.guo@openatom.club>


On 7/13/26 9:46 AM, Ben Guo wrote:
> Update Documentation/rust/general-information.rst translation.
>
> Update the translation through commit 86c5d1c6740c
> ("docs: rust: general-information: use real example")
>
> Reviewed-by: Gary Guo <gary@garyguo.net>


Revise the small issue below.

Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>


> Signed-off-by: Ben Guo <ben.guo@openatom.club>
> ---
>   .../zh_CN/rust/general-information.rst        | 82 ++++++++++++++++++-
>   1 file changed, 79 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/translations/zh_CN/rust/general-information.rst b/Documentation/translations/zh_CN/rust/general-information.rst
> index 9b5e37e13f3..ff9355cb8c8 100644
> --- a/Documentation/translations/zh_CN/rust/general-information.rst
> +++ b/Documentation/translations/zh_CN/rust/general-information.rst
> @@ -13,6 +13,14 @@
>   
>   本文档包含了在内核中使用Rust支持时需要了解的有用信息。
>   
> +``no_std``
> +----------
> +
> +内核中的 Rust 支持只能链接 `core <https://doc.rust-lang.org/core/>`_,
> +而不能链接 `std <https://doc.rust-lang.org/std/>`_。供内核使用的 crate
> +必须使用 ``#![no_std]`` 属性选择这种行为。
> +
> +
>   .. _rust_code_documentation_zh_cn:
>   
>   代码文档
> @@ -20,10 +28,18 @@
>   
>   Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
>   
> -生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。它们可以在以下地址阅读
> -(TODO:当在主线中时链接,与其他文档一起生成):
> +生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。
Add spaces before and after HTML
> +它们可以在以下地址阅读:
> +
> +		https://rust.docs.kernel.org
> +
> +对于 linux-next,请参阅:
>   
> -	http://kernel.org/
> +		https://rust.docs.kernel.org/next/
> +
> +每个主要版本也有对应的标签,例如:
> +
> +		https://rust.docs.kernel.org/6.10/
>   
>   这些文档也可以很容易地在本地生成和阅读。这相当快(与编译代码本身的顺序相同),而且不需要特
>   殊的工具或环境。这有一个额外的好处,那就是它们将根据所使用的特定内核配置进行定制。要生成它
> @@ -62,6 +78,58 @@ Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
>   模块(例如,驱动程序)不应该直接使用C语言的绑定。相反,子系统应该根据需要提供尽可能安
>   全的抽象。
>   
> +.. code-block::
> +
> +	                                                rust/bindings/
> +	                                               (rust/helpers/)
> +
> +	                                                   include/ -----+ <-+
> +	                                                                 |   |
> +	  drivers/              rust/kernel/              +----------+ <-+   |
> +	    fs/                                           | bindgen  |       |
> +	   .../            +-------------------+          +----------+ --+   |
> +	                   |    Abstractions   |                         |   |
> +	+---------+        | +------+ +------+ |          +----------+   |   |
> +	| my_foo  | -----> | | foo  | | bar  | | -------> | Bindings | <-+   |
> +	| driver  |  Safe  | | sub- | | sub- | |  Unsafe  |          |       |
> +	+---------+        | |system| |system| |          | bindings | <-----+
> +	     |             | +------+ +------+ |          |  crate   |       |
> +	     |             |   kernel crate    |          +----------+       |
> +	     |             +-------------------+                             |
> +	     |                                                               |
> +	     +------------------# FORBIDDEN #--------------------------------+
> +
> +主要思想是将所有与内核 C API 的直接交互封装到经过仔细审查和文档化的抽象
> +中。这样,只要满足以下条件,这些抽象的用户就不能引入未定义行为
> +(undefined behavior,UB):
> +
> +#. 抽象是正确的("可靠")。
> +#. 任何 ``unsafe`` 块都遵守调用块内操作所需的安全契约。类似地,任何
> +   ``unsafe impl`` 都遵守实现该特性所需的安全契约。
> +
> +绑定
> +~~~~
> +
> +通过从 ``include/`` 中将 C 头文件包含到
> +``rust/bindings/bindings_helper.h``, ``bindgen`` 工具将为所包含的子系统
> +自动生成绑定。构建后,请查看 ``rust/bindings/`` 目录中的
> +``*_generated.rs`` 输出文件。
> +
> +对于 ``bindgen`` 不会自动生成的 C 头文件部分,例如 C ``inline`` 函数或
> +非平凡宏,可以在 ``rust/helpers/`` 中添加一个小型包装函数,使其也可供
> +Rust 端使用。
> +
> +抽象
> +~~~~
> +
> +抽象是绑定和内核内用户之间的层。它们位于 ``rust/kernel/`` 中,其作用是
> +将对绑定的不安全访问封装到尽可能安全并暴露给用户的 API 中。抽象的用户
> +包括用 Rust 编写的驱动程序或文件系统等。
> +
> +除了安全方面,这些抽象还应该易于使用,也就是说,把 C 接口转换为符合
> +Rust 惯例的代码。基本示例包括将 C 的资源获取和释放转换为 Rust 的初始化
> +和清理模式,或者将 C 整数错误码转换为 Rust 的 ``Result``。
> +
>   
>   有条件的编译
>   ------------
> @@ -74,3 +142,11 @@ Rust代码可以访问基于内核配置的条件性编译:
>   	#[cfg(CONFIG_X="y")]   // Enabled as a built-in (`y`)
>   	#[cfg(CONFIG_X="m")]   // Enabled as a module   (`m`)
>   	#[cfg(not(CONFIG_X))]  // Disabled
> +
> +对于 Rust 的 ``cfg`` 不支持的其他条件,例如带有数值比较的表达式,可以
> +定义一个新的 Kconfig 符号:
> +
> +.. code-block:: kconfig
> +
> +	config RUSTC_HAS_SPAN_FILE
> +		def_bool RUSTC_VERSION >= 108800


^ permalink raw reply

* Re: [PATCH v2 3/4] docs/zh_CN: Update rust/arch-support.rst translation
From: Dongliang Mu @ 2026-07-13  2:40 UTC (permalink / raw)
  To: Ben Guo, Alex Shi, Yanteng Si, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <ea65566150d1b7797051ac2e9bb2b8725f041513.1783905132.git.ben.guo@openatom.club>


On 7/13/26 9:46 AM, Ben Guo wrote:
> Update Documentation/rust/arch-support.rst translation.
>
> Update the translation through commit 3f70ebe63858
> ("s390: Enable Rust support")
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
> Signed-off-by: Ben Guo <ben.guo@openatom.club>
> ---
>   Documentation/translations/zh_CN/rust/arch-support.rst | 1 +
>   1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/translations/zh_CN/rust/arch-support.rst b/Documentation/translations/zh_CN/rust/arch-support.rst
> index f5ae44588a5..0ca4be6e176 100644
> --- a/Documentation/translations/zh_CN/rust/arch-support.rst
> +++ b/Documentation/translations/zh_CN/rust/arch-support.rst
> @@ -23,6 +23,7 @@
>   ``arm64``      Maintained        仅小端序。
>   ``loongarch``  Maintained        \-
>   ``riscv``      Maintained        仅 ``riscv64``,且仅限 LLVM/Clang。
> +``s390``       Maintained        必须禁用 ``CONFIG_EXPOLINE``。
>   ``um``         Maintained        \-
>   ``x86``        Maintained        仅 ``x86_64``。
>   =============  ================  ==============================================


^ permalink raw reply

* Re: [PATCH v2 4/4] docs/zh_CN: Update rust/testing.rst translation
From: Dongliang Mu @ 2026-07-13  2:41 UTC (permalink / raw)
  To: Ben Guo, Alex Shi, Yanteng Si, Jonathan Corbet
  Cc: Gary Guo, linux-doc, linux-kernel, rust-for-linux,
	hust-os-kernel-patches
In-Reply-To: <a08043009080e3c9bc4717aba9783c3474ec2711.1783905132.git.ben.guo@openatom.club>


On 7/13/26 9:46 AM, Ben Guo wrote:
> Update Documentation/rust/testing.rst translation.
>
> Update the translation through commit 09699b24199a
> ("Documentation: rust: testing: add Kconfig guidance")
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Ben Guo <ben.guo@openatom.club>
Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
> ---
>   Documentation/translations/zh_CN/rust/testing.rst | 4 ++++
>   1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/translations/zh_CN/rust/testing.rst b/Documentation/translations/zh_CN/rust/testing.rst
> index ca81f1cef6e..6747d001299 100644
> --- a/Documentation/translations/zh_CN/rust/testing.rst
> +++ b/Documentation/translations/zh_CN/rust/testing.rst
> @@ -128,10 +128,13 @@ Rust 测试中常用的断言宏是来自 Rust 标准库( ``core`` )中的 `
>   
>   这些测试通过 ``kunit_tests`` 过程宏引入,该宏将测试套件的名称作为参数。
>   
> +每个测试套件都应该由 ``rust/kernel/Kconfig.test`` 中的 Kconfig 选项保护。
> +
>   例如,假设想要测试前面文档测试示例中的函数 ``f``,我们可以在定义该函数的同一文件中编写:
>   
>   .. code-block:: rust
>   
> +	#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
>   	#[kunit_tests(rust_kernel_mymod)]
>   	mod tests {
>   	    use super::*;
> @@ -158,6 +161,7 @@ Rust 测试中常用的断言宏是来自 Rust 标准库( ``core`` )中的 `
>   
>   .. code-block:: rust
>   
> +	#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
>   	#[kunit_tests(rust_kernel_mymod)]
>   	mod tests {
>   	    use super::*;


^ permalink raw reply

* Re: [PATCH v2] docs: zh_TW: process: localize terminologies and improve fluency in 8.Conclusion
From: 葉宸佑 @ 2026-07-13  2:44 UTC (permalink / raw)
  To: Weijie Yuan
  Cc: Alex Shi, Dongliang Mu, Hu Haowen, Jonathan Corbet, Shuah Khan,
	Dongliang Mu, linux-doc, linux-kernel, Yuchen Tian, Alex Shi,
	Yanteng Si
In-Reply-To: <alNBB1Ju2GGk6Uqu@wyuan.org>

Hi Weijie,

> I suspect that some contributors would run the get_maintainers.pl script
> or b4 prep --auto-to-cc, so they did not cc Alex, as they didn't know
> the current situation. Because I noticed that for both two versions,
> Chen-yu didn't cc Alex or Dongliang or Yanteng. Am I right, @Chen-yu? ;-)

Yes, exactly. For both v1 and v2 I ran get_maintainer.pl, which only
lists Hu Haowen and the mailing lists for zh_TW files, so Alex and the
zh_CN team were never on cc.

> Given that this document has not been maintained for ~2 years and these
> patches to the terminology actually don't have much significance, it
> might be more appropriate to directly declare the status of Traditional
> Chinese as "Orphan" provisionally for now, and remove it directly in the
> near future, until Hao Wen's return and opinion. Or maybe, waiting for a
> new good soul to take over, which is unpredictable.

Before it comes to that: I would like to step up and help carry zh_TW
forward. I am a native zh_TW speaker from Taiwan, and I understand
this means staying with it, not a one-off effort.

Dongliang, since you kindly offered to help review zh_TW patches:
would you be open to doing this together -- either as co-maintainers,
or with me listed as a reviewer (R:) first if that is a more
reasonable starting point for a newcomer?

> > To avoid scattering our efforts, I suggest we minimize fragmentation
> > as much as possible. When it comes to technical documentation
> > translation, not literary translation, a straightforward, unadorned,
> > and free from misunderstandings is the best translation and easy to
> > maintain. Let's keep thing simple, unless sth is really necessary.

Alex, I think this concern is fair, and I have no intention of
forking the translation effort. The scope I have in mind is
deliberately narrow: keep zh_TW aligned with zh_CN in structure and
coverage, and localize only where terminology genuinely differs
(e.g. 軟體 vs 软件, 介面 vs 接口) -- exactly the kind of differences
you mentioned. Plain, accurate technical translation, no literary
rewriting.

Weijie, as a first concrete step I will prepare a terminology series
(rather than one-word-at-a-time patches, as you suggested) covering
the existing process/ documents, and use it to build a small glossary
that future patches and reviews can follow.

Jon, if this direction sounds acceptable, I am happy to send a
MAINTAINERS patch once the details are settled in this thread.

Thanks,
Chen-Yu

^ permalink raw reply

* Re: [PATCH v2 0/5] binfmt_misc: bpf-backed binary type handlers
From: Farid Zakaria @ 2026-07-13  3:29 UTC (permalink / raw)
  To: Christian Brauner, Farid Zakaria
  Cc: Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Shuah Khan,
	Andrii Nakryiko, Kees Cook, Alexander Viro, Jan Kara,
	Jonathan Corbet, Jann Horn, John Ericson, linux-fsdevel, linux-mm,
	linux-kernel, bpf, linux-doc, linux-kselftest
In-Reply-To: <20260712-abluft-brutkasten-aufladen-c8063a4a1a0a@brauner>

On Sun Jul 12, 2026 at 5:32 AM PDT, Christian Brauner wrote:
>> This is a continuation of Christian's bpf-backed binfmt_misc POC [1], which he offered
>> to hand off to me. I am carrying it forward. The kernel design is his and is
>> unchanged. This series rebases it onto his binfmt_misc locking/cleanup series [2]
>> and adds selftests (+ fixed from the one's shared), and therefore does
>> not apply to mainline alone.
>> 
>> As for motivation for this whole change, Christian did a great VL;MR;
>> write-up [1].
>> 
>> TL;DR: binfmt_misc can match a binary and hand it to a fixed interpreter,
>> but it can't match programmatically or compute the interpreter per binary.
>> The Nix community would love to support relocatable binaries, where the
>> correct loader can only be found relative to the binary itself.
>> This adds a 'B' handler type: a binfmt_misc_ops struct_ops program that
>> inspects the binary and picks the interpreter with one new kfunc,
>> bpf_binprm_set_interp().
>> 
>>   bpftool struct_ops register nix_origin.bpf.o /sys/fs/bpf
>>   echo ':nix-origin:B:nix_origin::::' > /proc/sys/fs/binfmt_misc/register
>
> Thanks! So I've spent some more time working on this because I had some
> future ideas that I needed to make sure could be accomodated by this
> (currently on vacation but hey...). So the version I have givex this a
> better design and has future extensibility in mind:
>

I also enjoy hacking over my vacation. I'm often told to take break but
some of the best ideas come when on vacation :)

> - The single sleepable load op is split into two ops:
>
>       struct binfmt_misc_ops {
>       	bool (*match)(struct linux_binprm *bprm);
>       	int (*load)(struct linux_binprm *bprm);
>       	char name[BINFMT_MISC_OPS_NAME_MAX];
>       };
>
>   The non-sleepable match program runs from the RCU entry lookup
>   walk itself, exactly like magic and extension matching: same
>   registration order, same first-match-wins semantics, and it can
>   only rely on the prefetched bprm->buf. It must be free of side
>   effects since the walk may be restarted.
>

Is relying on brpm->buf enough?
Right now that's only 256 bytes I think, which is not enough to read
segments we might care about. That worked fine when it was just a magic
number but the idea with the eBPF program is to make decisions based on
more data.

In the selftest I provided, the `PT_INTERP` segment is already at file
offset 0x318 (792). I was imaginging NixOS having to support
`PT_INTERP_NIX` in order for the produced binaries to be backwards
compatible with older kernels.

The other idea would be to make the `match()` broad and select
everything but then nearly all ELF64 binaries would match and then pay
the price to `load()` and ultimately `-ENOEXEC`. Seems like it would
make multiple BPF binfmt programs less useful.


>   The sleepable load program runs once the walk has committed to the
>   entry and does the file reading and the interpreter selection. Both
>   ops are mandatory, the struct_ops plumbing enforces the sleepability
>   of each, and since bpf_binprm_set_interp() is KF_SLEEPABLE a match
>   program cannot select an interpreter by construction.
>
> - A match is a commitment. A failing load program fails the exec instead
>   of falling through to later entries. -ENOEXEC keeps its usual meaning
>   and hands the binary to the remaining binary formats, for a handler
>   that discovers it cannot serve the binary after all.
>
>   This kills the part of v1 I disliked the most: the skip cursor and the
>   leave-and-rescan loop in load_misc_binary() are gone. The walk is
>   never left and re-entered, and 'B' entries need no special semantics
>   against concurrent (un)registration anymore.
>
>   Your v2 changelog note about keeping the bpf retry loop in the
>   __free() style is moot as a consequence. The loop no longer exists.
>
> - The load return convention flipped: 0 now means success after the
>   program called bpf_binprm_set_interp(). Returning 0 without having
>   selected an interpreter or returning a positive value is treated as
>   -ENOEXEC, other negative errnos fail the exec.
>
>   So the "return bpf_binprm_set_interp(...) ?: 1" idiom from the v1-era
>   programs becomes plain "return bpf_binprm_set_interp(...)".
>
> - The handler name moved from the offset field to the interpreter field
>   that field consistently names whoever supplies the interpreter, a path
>   for static entries, a handler for 'B' entries. Offset, magic, and mask
>   must be empty:
>
> 	echo ':nix-origin:B::::nix_origin:' > register
>
> - 'C' is allowed now, v1 rejected it. It behaves exactly as for a static
>    entry. The setuid transition stays gated by vfsuid_has_mapping() in
>    the caller's user namespace. Which makes 'B' handlers usable for a
>    per-binary loader over setuid binaries. 'F' stays rejected as there
>    is no fixed interpreter to pre-open (I have other ideas how we'll do
>    something like it later.).
>
> Nothing changed in the exec patch, the fs kfuncs patch, the kfunc
> itself, or the registry/namespacing model.
>
> I can send v3 in a bit if that's ok.

I don't mind at all you sending v3 and in fact I've been enjoying your
involvement. I didn't know what to expect when I offered this idea up to
the community. 

I'm happy to keep co-developing this with you within a design you feel
acceptable with. Please let me know how I can remain engaged and
helpful.

One last thing I was thinking about is that we will also need to support
$ORIGIN in the shebang path, however I just tested it and this current broad
BPF solution can largely handle it [1], with a small wrinkle.

  $ printf '#!$ORIGIN/interp\n' > /opt/app/greet
  $ cp ./interp /opt/app/interp     # any interpreter/loader
  $ chmod +x /opt/app/greet /opt/app/interp

  # stock kernel: binfmt_script opens the literal "$ORIGIN/interp"
  $ /opt/app/greet
  bash: /opt/app/greet: $ORIGIN/interp: bad interpreter: No such file or directory

  # with the handler registered, $ORIGIN resolves to the script's dir
  $ bpftool struct_ops register shebang_origin.bpf.o /sys/fs/bpf
  $ echo ':shebang-origin:B:shebang_origin::::' > /proc/sys/fs/binfmt_misc/register
  $ /opt/app/greet
  <runs /opt/app/interp, the loader found next to the script>

The wrinkle is that it can't express today is the single optional argument.
(i.e. `#!interp arg" -> argv[1]=arg`). We might ned a way to express
that in the load.

Anywyas, thanks again. All your ideas made sense modulo I'm unsure if
`bprm->buf` is enough to make a decision...

[1] https://gist.github.com/fzakaria/2e1e1c44fa488a951674f8761c672366


^ permalink raw reply

* Re: [PATCH v19 39/40] rust: completion: Add __rust_helper to rust_helper_wait_for_completion()
From: Byungchul Park @ 2026-07-13  3:36 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Gary Guo, linux-kernel, max.byungchul.park, kernel_team, torvalds,
	damien.lemoal, linux-ide, adilger.kernel, linux-ext4, mingo,
	peterz, will, tglx, rostedt, joel, sashal, daniel.vetter,
	duyuyang, johannes.berg, tj, tytso, willy, david, amir73il,
	gregkh, kernel-team, linux-mm, akpm, mhocko, minchan, hannes,
	vdavydov.dev, sj, jglisse, dennis, cl, penberg, rientjes, vbabka,
	ngupta, linux-block, josef, linux-fsdevel, jack, jlayton,
	dan.j.williams, hch, djwong, dri-devel, rodrigosiqueiramelo,
	melissa.srw, hamohammed.sa, harry.yoo, chris.p.wilson,
	gwan-gyeong.mun, boqun.feng, longman, yunseong.kim, ysk,
	yeoreum.yun, netdev, matthew.brost, her0gyugyu, corbet,
	catalin.marinas, bp, x86, hpa, luto, sumit.semwal, gustavo,
	christian.koenig, andi.shyti, arnd, lorenzo.stoakes, Liam.Howlett,
	rppt, surenb, mcgrof, petr.pavlu, da.gomez, samitolvanen, paulmck,
	frederic, neeraj.upadhyay, joelagnelf, josh, urezki,
	mathieu.desnoyers, jiangshanlai, qiang.zhang, juri.lelli,
	vincent.guittot, dietmar.eggemann, bsegall, mgorman, vschneid,
	chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy, anna, kees,
	bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
	kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
	shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
	joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
	alexander.shishkin, lillian, chenhuacai, francesco,
	guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
	thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
	linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
	linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
	2407018371, dakr, neilb, bagasdotme, wsa+renesas, dave.hansen,
	geert, ojeda, alex.gaynor, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, rust-for-linux
In-Reply-To: <CANiq72kEo=bGcHNaSA9JZhv4iuE+YDvu0kN+Z7aopVp3=2C+Wg@mail.gmail.com>

On Sat, Jul 11, 2026 at 02:13:05PM +0200, Miguel Ojeda wrote:
> On Mon, Jul 6, 2026 at 8:22 AM Byungchul Park <byungchul@sk.com> wrote:
> >
> > This is needed to inline these helpers into Rust code, which is required
> > for DEPT to play with wait_for_completion().
> >
> > Signed-off-by: Byungchul Park <byungchul@sk.com>
> 
> Apart from what Gary said -- why did you need to do this in a separate
> patch in the same series?

Not necessary.  I will make them into one patch.  Thanks.

	Byungchul
> 
> Cheers,
> Miguel

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox