* [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
@ 2026-09-04 8:29 Ye Liu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
` (7 more replies)
0 siblings, 8 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Andrew Morton, Michal Hocko, Peter Zijlstra, Paul E. McKenney,
Ingo Molnar, Steven Rostedt, Josh Poimboeuf,
Mickaël Salaün
Cc: Ye Liu, David Hildenbrand, Miaohe Lin, Naoya Horiguchi,
Rafael J. Wysocki, linux-mm, linux-kernel, linux-pm, rcu,
linux-trace-kernel, linux-fsdevel, linux-security-module,
Günther Noack
From: Ye Liu <liuye@kylinos.cn>
Introduce for_each_process_rcu(), for_each_thread_rcu() and
for_each_process_thread_rcu() macros that combine the existing
iteration macros with scoped_guard(rcu), so that the RCU read lock
is automatically acquired before iteration and released when the
loop exits — including via break, goto, or return.
The rest of the series converts manual rcu_read_lock()/
rcu_read_unlock() and guard(rcu)() pairs across mm/, kernel/, fs/,
lib/ and security/ to use the new macros.
Patch 1 may trigger checkpatch "Macros with complex values should be
enclosed in parentheses" errors. These are false positives — the
scoped_guard() pattern is a control-flow construct, not a multi-
statement macro, and the same idiom is used elsewhere in the kernel.
Suggested by Michal Hocko for the oom_kill path [1].
[1] https://lore.kernel.org/all/20260813092933.562028-1-ye.liu@linux.dev/
Ye Liu (8):
mm: introduce for_each_process_rcu and for_each_thread_rcu
mm/oom_kill: convert process/thread iterators to for_each_*_rcu
mm/ksm: convert process iterator to for_each_process_rcu
mm/memory-failure: convert process iterator to for_each_process_rcu
kernel: convert process/thread iterators to for_each_*_rcu
fs: convert process/thread iterators to for_each_*_rcu
lib: convert process iterator to for_each_process_rcu
security/landlock: convert thread iterator to for_each_thread_rcu
fs/proc/base.c | 4 +---
fs/resctrl/rdtgroup.c | 8 ++------
include/linux/sched/signal.h | 19 +++++++++++++++++++
kernel/cpu.c | 4 +---
kernel/freezer.c | 4 +---
kernel/hung_task.c | 7 ++-----
kernel/locking/lockdep.c | 4 +---
kernel/rcu/update.c | 4 +---
kernel/sched/core.c | 3 +--
kernel/sched/debug.c | 4 +---
kernel/trace/fgraph.c | 8 ++------
kernel/unwind/deferred.c | 3 +--
lib/is_single_threaded.c | 5 +----
mm/ksm.c | 4 +---
mm/memory-failure.c | 16 ++++------------
mm/oom_kill.c | 20 +++++---------------
security/landlock/tsync.c | 8 ++------
17 files changed, 46 insertions(+), 79 deletions(-)
Signed-off-by: Ye Liu <liuye@kylinos.cn>
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:03 ` Michal Hocko
2026-09-04 16:25 ` Steven Rostedt
2026-09-04 8:29 ` [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu Ye Liu
` (6 subsequent siblings)
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner
Cc: linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Introduce for_each_process_rcu(), for_each_thread_rcu() and
for_each_process_thread_rcu() macros that acquire the RCU read lock
before the iteration starts and release it when the loop is left, so
that the RCU read-side critical section is scoped to the loop body
instead of an externally managed rcu_read_lock()/rcu_read_unlock()
pair.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
include/linux/sched/signal.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 584ae88b435e..fe0c41dc99a1 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_SCHED_SIGNAL_H
#define _LINUX_SCHED_SIGNAL_H
+#include <linux/cleanup.h>
#include <linux/rculist.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -663,6 +664,24 @@ extern bool current_is_single_threaded(void);
#define for_each_process_thread(p, t) \
for_each_process(p) for_each_thread(p, t)
+/*
+ * RCU-internal variants: automatically acquire and release the RCU read
+ * lock around the iteration. Equivalent to scoped_guard(rcu) combined
+ * with the respective non-_rcu variant.
+ */
+#define for_each_process_rcu(p) \
+ scoped_guard(rcu) \
+ for (p = &init_task ; (p = next_task(p)) != &init_task ; )
+
+#define for_each_thread_rcu(p, t) \
+ scoped_guard(rcu) \
+ __for_each_thread((p)->signal, t)
+
+/* Careful: this is a double loop, 'break' won't work as expected. */
+#define for_each_process_thread_rcu(p, t) \
+ scoped_guard(rcu) \
+ for_each_process(p) for_each_thread(p, t)
+
typedef int (*proc_visitor)(struct task_struct *p, void *data);
void walk_process_tree(struct task_struct *top, proc_visitor, void *);
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:32 ` SJ Park
2026-09-04 8:29 ` [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu Ye Liu
` (5 subsequent siblings)
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Michal Hocko, Andrew Morton
Cc: Ye Liu, David Rientjes, Shakeel Butt, linux-mm, linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() pairs wrapping
for_each_process()/for_each_thread() loops with for_each_process_rcu()
and for_each_thread_rcu(), so that the RCU read-side critical section
is scoped to the loop body.
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
mm/oom_kill.c | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5f372f6e26fa..8dd025965810 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -94,8 +94,7 @@ static bool oom_cpuset_eligible(struct task_struct *start,
bool ret = false;
const nodemask_t *mask = oc->nodemask;
- rcu_read_lock();
- for_each_thread(start, tsk) {
+ for_each_thread_rcu(start, tsk) {
if (mask) {
/*
* If this is a mempolicy constrained oom, tsk's
@@ -114,7 +113,6 @@ static bool oom_cpuset_eligible(struct task_struct *start,
if (ret)
break;
}
- rcu_read_unlock();
return ret;
}
@@ -368,11 +366,9 @@ static void select_bad_process(struct oom_control *oc)
else {
struct task_struct *p;
- rcu_read_lock();
- for_each_process(p)
+ for_each_process_rcu(p)
if (oom_evaluate_task(p, oc))
break;
- rcu_read_unlock();
}
}
@@ -430,14 +426,12 @@ static void dump_tasks(struct oom_control *oc)
struct task_struct *p;
int i = 0;
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
/* Avoid potential softlockup warning */
if ((++i & 1023) == 0)
touch_softlockup_watchdog();
dump_task(p, oc);
}
- rcu_read_unlock();
}
}
@@ -894,8 +888,7 @@ static bool task_will_free_mem(struct task_struct *task)
* are dying as well to make sure that a) nobody pins its mm and
* b) the task is also reapable by the oom reaper.
*/
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
if (!process_shares_mm(p, mm))
continue;
if (same_thread_group(task, p))
@@ -904,7 +897,6 @@ static bool task_will_free_mem(struct task_struct *task)
if (!ret)
break;
}
- rcu_read_unlock();
return ret;
}
@@ -960,8 +952,7 @@ static void __oom_kill_process(struct task_struct *victim, const char *message)
* That thread will now get access to memory reserves since it has a
* pending fatal signal.
*/
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
if (!process_shares_mm(p, mm))
continue;
if (same_thread_group(p, victim))
@@ -982,7 +973,6 @@ static void __oom_kill_process(struct task_struct *victim, const char *message)
continue;
do_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_TGID);
}
- rcu_read_unlock();
if (can_oom_reap)
queue_oom_reaper(victim);
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
2026-09-04 8:29 ` [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:33 ` SJ Park
2026-09-04 8:29 ` [PATCH 4/8] mm/memory-failure: " Ye Liu
` (4 subsequent siblings)
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand
Cc: Ye Liu, Xu Xin, Chengming Zhou, linux-mm, linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() pair combined
with for_each_process() loop in mm/ksm.c with for_each_process_rcu().
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
mm/ksm.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/mm/ksm.c b/mm/ksm.c
index 49d48d1e0998..fa5e4c47fb1b 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -3280,8 +3280,7 @@ void collect_procs_ksm(const struct folio *folio, const struct page *page,
struct anon_vma *av = rmap_item->anon_vma;
anon_vma_lock_read(av);
- rcu_read_lock();
- for_each_process(tsk) {
+ for_each_process_rcu(tsk) {
struct anon_vma_chain *vmac;
const unsigned long addr = rmap_item->address & PAGE_MASK;
const unsigned long index = rmap_item->linear_page_index;
@@ -3298,7 +3297,6 @@ void collect_procs_ksm(const struct folio *folio, const struct page *page,
}
}
}
- rcu_read_unlock();
anon_vma_unlock_read(av);
}
}
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 4/8] mm/memory-failure: convert process iterator to for_each_process_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
` (2 preceding siblings ...)
2026-09-04 8:29 ` [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:05 ` Michal Hocko
2026-09-05 0:39 ` SJ Park
2026-09-04 8:29 ` [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu
` (3 subsequent siblings)
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton; +Cc: Ye Liu, Naoya Horiguchi, linux-mm, linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
with for_each_process() loop in mm/memory-failure.c with
for_each_process_rcu().
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
mm/memory-failure.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index a8b03e2920ba..63a2ff08ee33 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -555,8 +555,7 @@ static void collect_procs_anon(const struct folio *folio,
return;
pgoff = page_pgoff(folio, page);
- rcu_read_lock();
- for_each_process(tsk) {
+ for_each_process_rcu(tsk) {
struct vm_area_struct *vma;
struct anon_vma_chain *vmac;
struct task_struct *t = task_early_kill(tsk, force_early);
@@ -572,7 +571,6 @@ static void collect_procs_anon(const struct folio *folio,
add_to_kill_anon_file(t, page, vma, to_kill, addr);
}
}
- rcu_read_unlock();
anon_vma_unlock_read(av);
}
@@ -589,9 +587,8 @@ static void collect_procs_file(const struct folio *folio,
pgoff_t pgoff;
i_mmap_lock_read(mapping);
- rcu_read_lock();
pgoff = page_pgoff(folio, page);
- for_each_process(tsk) {
+ for_each_process_rcu(tsk) {
struct task_struct *t = task_early_kill(tsk, force_early);
unsigned long addr;
@@ -611,7 +608,6 @@ static void collect_procs_file(const struct folio *folio,
add_to_kill_anon_file(t, page, vma, to_kill, addr);
}
}
- rcu_read_unlock();
i_mmap_unlock_read(mapping);
}
@@ -635,8 +631,7 @@ static void collect_procs_fsdax(const struct page *page,
struct task_struct *tsk;
i_mmap_lock_read(mapping);
- rcu_read_lock();
- for_each_process(tsk) {
+ for_each_process_rcu(tsk) {
struct task_struct *t = tsk;
/*
@@ -653,7 +648,6 @@ static void collect_procs_fsdax(const struct page *page,
add_to_kill_fsdax(t, page, vma, to_kill, pgoff);
}
}
- rcu_read_unlock();
i_mmap_unlock_read(mapping);
}
#endif /* CONFIG_FS_DAX */
@@ -2288,8 +2282,7 @@ static void collect_procs_pfn(struct pfn_address_space *pfn_space,
struct address_space *mapping = pfn_space->mapping;
i_mmap_lock_read(mapping);
- rcu_read_lock();
- for_each_process(tsk) {
+ for_each_process_rcu(tsk) {
struct task_struct *t = tsk;
t = task_early_kill(tsk, true);
@@ -2303,7 +2296,6 @@ static void collect_procs_pfn(struct pfn_address_space *pfn_space,
add_to_kill_pgoff(t, vma, to_kill, pgoff);
}
}
- rcu_read_unlock();
i_mmap_unlock_read(mapping);
}
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
` (3 preceding siblings ...)
2026-09-04 8:29 ` [PATCH 4/8] mm/memory-failure: " Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:06 ` Michal Hocko
2026-09-04 14:14 ` Günther Noack
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
` (2 subsequent siblings)
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Thomas Gleixner, Peter Zijlstra, Rafael J. Wysocki,
Andrew Morton, Ingo Molnar, Will Deacon, Boqun Feng,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Juri Lelli,
Vincent Guittot, Steven Rostedt, Masami Hiramatsu,
Josh Poimboeuf
Cc: Ye Liu, Pavel Machek, Lance Yang, Petr Mladek, Waiman Long,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Dietmar Eggemann,
Ben Segall, Mel Gorman, Valentin Schneider, K Prateek Nayak,
Mark Rutland, linux-kernel, linux-pm, rcu, linux-trace-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() and guard(rcu)
pairs combined with for_each_process(), for_each_thread() and
for_each_process_thread() loops across kernel/ with the
for_each_*_rcu() macros.
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
kernel/cpu.c | 4 +---
kernel/freezer.c | 4 +---
kernel/hung_task.c | 7 ++-----
kernel/locking/lockdep.c | 4 +---
kernel/rcu/update.c | 4 +---
kernel/sched/core.c | 3 +--
kernel/sched/debug.c | 4 +---
kernel/trace/fgraph.c | 8 ++------
kernel/unwind/deferred.c | 3 +--
9 files changed, 11 insertions(+), 30 deletions(-)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b3c8553d7bd6..bc70fd21561a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1254,8 +1254,7 @@ void clear_tasks_mm_cpumask(int cpu)
* full-fledged tasklist_lock.
*/
WARN_ON(cpu_online(cpu));
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
struct task_struct *t;
/*
@@ -1268,7 +1267,6 @@ void clear_tasks_mm_cpumask(int cpu)
arch_clear_mm_cpumask_cpu(cpu, t->mm);
task_unlock(t);
}
- rcu_read_unlock();
}
/* Take this CPU down. */
diff --git a/kernel/freezer.c b/kernel/freezer.c
index a76bf957fb32..a27b2382fda9 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -217,11 +217,9 @@ void thaw_process(struct task_struct *p)
{
struct task_struct *t;
- rcu_read_lock();
- for_each_thread(p, t) {
+ for_each_thread_rcu(p, t) {
__thaw_task(t);
}
- rcu_read_unlock();
}
/**
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 6fcc94ce4ca9..76871f78497f 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -315,8 +315,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
return;
this_round_count = 0;
- rcu_read_lock();
- for_each_process_thread(g, t) {
+ for_each_process_thread_rcu(g, t) {
if (!max_count--)
goto unlock;
if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
@@ -337,9 +336,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
hung_task_info(t, timeout, this_round_count);
}
}
- unlock:
- rcu_read_unlock();
-
+unlock:
if (!this_round_count)
return;
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index c56a7f91d72e..9c3dce0f0c4b 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -6834,15 +6834,13 @@ void debug_show_all_locks(void)
}
pr_warn("\nShowing all locks held in the system:\n");
- rcu_read_lock();
- for_each_process_thread(g, p) {
+ for_each_process_thread_rcu(g, p) {
if (!p->lockdep_depth)
continue;
lockdep_print_held_locks(p);
touch_nmi_watchdog();
touch_all_softlockup_watchdogs();
}
- rcu_read_unlock();
pr_warn("\n");
pr_warn("=============================================\n\n");
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 2a778b8ab4ad..c48a84a0da82 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -548,15 +548,13 @@ void synchronize_rcu_trivial_preempt(void)
struct task_struct *t;
smp_mb(); // Order prior accesses before grace-period start.
- rcu_read_lock(); // Protect task list.
- for_each_process_thread(g, t) {
+ for_each_process_thread_rcu(g, t) {
if (t == current)
continue; // Don't deadlock on ourselves!
// Order later rcu_read_lock() on other tasks after QS.
while (smp_load_acquire(&t->rcu_trivial_preempt_nesting))
continue;
}
- rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(synchronize_rcu_trivial_preempt);
#endif // #if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0697ed0f1c3d..a41cdd2ff02f 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2005,8 +2005,7 @@ static void uclamp_sync_util_min_rt_default(void)
smp_mb__after_spinlock();
read_unlock(&tasklist_lock);
- guard(rcu)();
- for_each_process_thread(g, p)
+ for_each_process_thread_rcu(g, p)
uclamp_update_util_min_rt_default(p);
}
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 72236db67983..8f37b1a7adfe 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -1029,14 +1029,12 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
#endif
"\n");
- rcu_read_lock();
- for_each_process_thread(g, p) {
+ for_each_process_thread_rcu(g, p) {
if (task_cpu(p) != rq_cpu)
continue;
print_task(m, rq, p);
}
- rcu_read_unlock();
}
void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
index 40d373d65f9b..e522433ec8a5 100644
--- a/kernel/trace/fgraph.c
+++ b/kernel/trace/fgraph.c
@@ -1057,11 +1057,10 @@ static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
}
}
- rcu_read_lock();
- for_each_process_thread(g, t) {
+ for_each_process_thread_rcu(g, t) {
if (start == end) {
ret = -EAGAIN;
- goto unlock;
+ goto free;
}
if (t->ret_stack == NULL) {
@@ -1074,9 +1073,6 @@ static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
t->ret_stack = ret_stack_list[start++];
}
}
-
-unlock:
- rcu_read_unlock();
free:
for (i = start; i < end; i++)
kmem_cache_free(fgraph_stack_cachep, ret_stack_list[i]);
diff --git a/kernel/unwind/deferred.c b/kernel/unwind/deferred.c
index 5bea47314254..61fe2d4727ce 100644
--- a/kernel/unwind/deferred.c
+++ b/kernel/unwind/deferred.c
@@ -319,9 +319,8 @@ void unwind_deferred_cancel(struct unwind_work *work)
synchronize_srcu(&unwind_srcu);
- guard(rcu)();
/* Clear this bit from all threads */
- for_each_process_thread(g, t) {
+ for_each_process_thread_rcu(g, t) {
atomic_long_andnot(BIT(bit),
&t->unwind_info.unwind_mask);
if (t->unwind_info.cache)
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 6/8] fs: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
` (4 preceding siblings ...)
2026-09-04 8:29 ` [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 9:05 ` Oleg Nesterov
` (2 more replies)
2026-09-04 8:29 ` [PATCH 7/8] lib: convert process iterator to for_each_process_rcu Ye Liu
2026-09-04 8:30 ` [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu Ye Liu
7 siblings, 3 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Tony Luck, Reinette Chatre, x86, Christian Brauner,
Andrew Morton, Jann Horn, David Hildenbrand (arm),
Mike Rapoport (Microsoft),
Alexey Dobriyan, Lorenzo Stoakes, Oleg Nesterov
Cc: Ye Liu, Dave Martin, James Morse, Babu Moger, linux-kernel,
linux-fsdevel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
with for_each_process() and for_each_process_thread() loops in fs/
with the for_each_*_rcu() macros.
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
fs/proc/base.c | 4 +---
fs/resctrl/rdtgroup.c | 8 ++------
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6a39de424f62..da36ba73dc17 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1160,8 +1160,7 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
if (mm) {
struct task_struct *p;
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
if (same_thread_group(task, p))
continue;
@@ -1177,7 +1176,6 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
}
task_unlock(p);
}
- rcu_read_unlock();
mmdrop(mm);
}
err_unlock:
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dcbb0a964e8..3f96d21b84ab 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -709,14 +709,12 @@ int rdtgroup_tasks_assigned(struct rdtgroup *r)
lockdep_assert_held(&rdtgroup_mutex);
- rcu_read_lock();
- for_each_process_thread(p, t) {
+ for_each_process_thread_rcu(p, t) {
if (is_closid_match(t, r) || is_rmid_match(t, r)) {
ret = 1;
break;
}
}
- rcu_read_unlock();
return ret;
}
@@ -826,15 +824,13 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
struct task_struct *p, *t;
pid_t pid;
- rcu_read_lock();
- for_each_process_thread(p, t) {
+ for_each_process_thread_rcu(p, t) {
if (is_closid_match(t, r) || is_rmid_match(t, r)) {
pid = task_pid_vnr(t);
if (pid)
seq_printf(s, "%d\n", pid);
}
}
- rcu_read_unlock();
}
static int rdtgroup_tasks_show(struct kernfs_open_file *of,
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 7/8] lib: convert process iterator to for_each_process_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
` (5 preceding siblings ...)
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
@ 2026-09-04 8:29 ` Ye Liu
2026-09-04 11:09 ` Michal Hocko
2026-09-04 8:30 ` [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu Ye Liu
7 siblings, 1 reply; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: Ye Liu, linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace the manual rcu_read_lock()/rcu_read_unlock() pair combined
with for_each_process() loop in lib/ with for_each_process_rcu().
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
lib/is_single_threaded.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
index 8c98b20bfc41..0682dc87bcdf 100644
--- a/lib/is_single_threaded.c
+++ b/lib/is_single_threaded.c
@@ -26,8 +26,7 @@ bool current_is_single_threaded(void)
return true;
ret = false;
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
if (unlikely(p->flags & PF_KTHREAD))
continue;
if (unlikely(p == task->group_leader))
@@ -48,7 +47,5 @@ bool current_is_single_threaded(void)
}
ret = true;
found:
- rcu_read_unlock();
-
return ret;
}
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
` (6 preceding siblings ...)
2026-09-04 8:29 ` [PATCH 7/8] lib: convert process iterator to for_each_process_rcu Ye Liu
@ 2026-09-04 8:30 ` Ye Liu
2026-09-04 12:21 ` Justin Suess
2026-09-04 14:17 ` Günther Noack
7 siblings, 2 replies; 28+ messages in thread
From: Ye Liu @ 2026-09-04 8:30 UTC (permalink / raw)
To: Mickaël Salaün, Paul Moore, James Morris, Serge E. Hallyn
Cc: Ye Liu, Günther Noack, linux-security-module, linux-kernel
From: Ye Liu <liuye@kylinos.cn>
Replace guard(rcu)() + for_each_thread() with for_each_thread_rcu(),
so that the RCU read-side critical section is scoped to the loop body.
No functional change.
Signed-off-by: Ye Liu <liuye@kylinos.cn>
---
security/landlock/tsync.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index 0b71e158c3f5..f1c08aae179b 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -335,9 +335,7 @@ static size_t count_additional_threads(const struct tsync_works *works)
caller = current;
- guard(rcu)();
-
- for_each_thread(caller, thread) {
+ for_each_thread_rcu(caller, thread) {
/* Skip current, since it is initiating the sync. */
if (thread == caller)
continue;
@@ -376,9 +374,7 @@ static bool schedule_task_work(struct tsync_works *works,
caller = current;
- guard(rcu)();
-
- for_each_thread(caller, thread) {
+ for_each_thread_rcu(caller, thread) {
/* Skip current, since it is initiating the sync. */
if (thread == caller)
continue;
--
2.25.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 6/8] fs: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
@ 2026-09-04 9:05 ` Oleg Nesterov
2026-09-04 9:22 ` Lorenzo Stoakes (ARM)
2026-09-04 11:06 ` Michal Hocko
2 siblings, 0 replies; 28+ messages in thread
From: Oleg Nesterov @ 2026-09-04 9:05 UTC (permalink / raw)
To: Ye Liu
Cc: Tony Luck, Reinette Chatre, x86, Christian Brauner,
Andrew Morton, Jann Horn, David Hildenbrand (arm),
Mike Rapoport (Microsoft),
Alexey Dobriyan, Lorenzo Stoakes, Ye Liu, Dave Martin,
James Morse, Babu Moger, linux-kernel, linux-fsdevel
On 09/04, Ye Liu wrote:
>
> @@ -1160,8 +1160,7 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
> if (mm) {
> struct task_struct *p;
>
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (same_thread_group(task, p))
> continue;
Hmm... I am not aware of for_each_process_rcu(), but looking at this
change I guess it includes something like scope_guard(rcu) ?
Perhaps makes sense, but the naming looks sligthly confusing to me.
I mean, to for_each_process_rcu() looks like (say) list_for_each_entry_rcu()
where _rcu has another meaning...
Oleg.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 6/8] fs: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
2026-09-04 9:05 ` Oleg Nesterov
@ 2026-09-04 9:22 ` Lorenzo Stoakes (ARM)
2026-09-04 11:06 ` Michal Hocko
2 siblings, 0 replies; 28+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-09-04 9:22 UTC (permalink / raw)
To: Ye Liu
Cc: Tony Luck, Reinette Chatre, x86, Christian Brauner,
Andrew Morton, Jann Horn, David Hildenbrand (arm),
Mike Rapoport (Microsoft),
Alexey Dobriyan, Oleg Nesterov, Ye Liu, Dave Martin, James Morse,
Babu Moger, linux-kernel, linux-fsdevel
Please cc everybody on every patch in the series :) it makes it incredible hard
for me to see context otherwise.
I can already see a comment I'd like to leave on another patch in the series but
it's a total pain for me go retrieve that to do it.
And I worry about acking one bit only to find out a horrible flaw in another
part :P
Can you please make sure to do that on any respin?...
On Fri, Sep 04, 2026 at 04:29:58PM +0800, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
> with for_each_process() and for_each_process_thread() loops in fs/
> with the for_each_*_rcu() macros.
Probably worth mentioning that they hold the RCU lock in a scoped guard over the
operation.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
In general it looks reasonable to me, but I wonder if you're correctly including
linux/cleanup.h to have the scope guard available...
Anyway can check that on respin with the right cc ;)
> ---
> fs/proc/base.c | 4 +---
> fs/resctrl/rdtgroup.c | 8 ++------
> 2 files changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 6a39de424f62..da36ba73dc17 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -1160,8 +1160,7 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
Side-note - I wonder if this really belongs in mm/oom_kill.c? Seems really odd
to have it here.
> if (mm) {
> struct task_struct *p;
>
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (same_thread_group(task, p))
> continue;
>
> @@ -1177,7 +1176,6 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
> }
> task_unlock(p);
> }
> - rcu_read_unlock();
> mmdrop(mm);
> }
> err_unlock:
> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
> index 5dcbb0a964e8..3f96d21b84ab 100644
> --- a/fs/resctrl/rdtgroup.c
> +++ b/fs/resctrl/rdtgroup.c
> @@ -709,14 +709,12 @@ int rdtgroup_tasks_assigned(struct rdtgroup *r)
>
> lockdep_assert_held(&rdtgroup_mutex);
>
> - rcu_read_lock();
> - for_each_process_thread(p, t) {
> + for_each_process_thread_rcu(p, t) {
> if (is_closid_match(t, r) || is_rmid_match(t, r)) {
> ret = 1;
> break;
> }
> }
> - rcu_read_unlock();
>
> return ret;
> }
> @@ -826,15 +824,13 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
> struct task_struct *p, *t;
> pid_t pid;
>
> - rcu_read_lock();
> - for_each_process_thread(p, t) {
> + for_each_process_thread_rcu(p, t) {
> if (is_closid_match(t, r) || is_rmid_match(t, r)) {
> pid = task_pid_vnr(t);
> if (pid)
> seq_printf(s, "%d\n", pid);
> }
> }
> - rcu_read_unlock();
> }
>
> static int rdtgroup_tasks_show(struct kernfs_open_file *of,
> --
> 2.25.1
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
@ 2026-09-04 11:03 ` Michal Hocko
2026-09-04 16:25 ` Steven Rostedt
1 sibling, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:03 UTC (permalink / raw)
To: Ye Liu
Cc: Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner, linux-kernel, Oleg Nesterov
You want to CC Oleg at least. Now added
Also prefixing this patch with mm is confusing as this has nothing to do
with mm.
On Fri 04-09-26 16:29:53, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Introduce for_each_process_rcu(), for_each_thread_rcu() and
> for_each_process_thread_rcu() macros that acquire the RCU read lock
> before the iteration starts and release it when the loop is left, so
> that the RCU read-side critical section is scoped to the loop body
> instead of an externally managed rcu_read_lock()/rcu_read_unlock()
> pair.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Apparat from potential naming changes this makes a lot of sense to me.
Many users really need RCU in the scope of iteration and this simplifies
the code and it makes less prone to bugs.
I do not really care much about the naming TBH
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> include/linux/sched/signal.h | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
> index 584ae88b435e..fe0c41dc99a1 100644
> --- a/include/linux/sched/signal.h
> +++ b/include/linux/sched/signal.h
> @@ -2,6 +2,7 @@
> #ifndef _LINUX_SCHED_SIGNAL_H
> #define _LINUX_SCHED_SIGNAL_H
>
> +#include <linux/cleanup.h>
> #include <linux/rculist.h>
> #include <linux/signal.h>
> #include <linux/sched.h>
> @@ -663,6 +664,24 @@ extern bool current_is_single_threaded(void);
> #define for_each_process_thread(p, t) \
> for_each_process(p) for_each_thread(p, t)
>
> +/*
> + * RCU-internal variants: automatically acquire and release the RCU read
> + * lock around the iteration. Equivalent to scoped_guard(rcu) combined
> + * with the respective non-_rcu variant.
> + */
> +#define for_each_process_rcu(p) \
> + scoped_guard(rcu) \
> + for (p = &init_task ; (p = next_task(p)) != &init_task ; )
> +
> +#define for_each_thread_rcu(p, t) \
> + scoped_guard(rcu) \
> + __for_each_thread((p)->signal, t)
> +
> +/* Careful: this is a double loop, 'break' won't work as expected. */
> +#define for_each_process_thread_rcu(p, t) \
> + scoped_guard(rcu) \
> + for_each_process(p) for_each_thread(p, t)
> +
> typedef int (*proc_visitor)(struct task_struct *p, void *data);
> void walk_process_tree(struct task_struct *top, proc_visitor, void *);
>
> --
> 2.25.1
>
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu Ye Liu
@ 2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:32 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:04 UTC (permalink / raw)
To: Ye Liu
Cc: Andrew Morton, Ye Liu, David Rientjes, Shakeel Butt, linux-mm,
linux-kernel
On Fri 04-09-26 16:29:54, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs wrapping
> for_each_process()/for_each_thread() loops with for_each_process_rcu()
> and for_each_thread_rcu(), so that the RCU read-side critical section
> is scoped to the loop body.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> mm/oom_kill.c | 20 +++++---------------
> 1 file changed, 5 insertions(+), 15 deletions(-)
>
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 5f372f6e26fa..8dd025965810 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -94,8 +94,7 @@ static bool oom_cpuset_eligible(struct task_struct *start,
> bool ret = false;
> const nodemask_t *mask = oc->nodemask;
>
> - rcu_read_lock();
> - for_each_thread(start, tsk) {
> + for_each_thread_rcu(start, tsk) {
> if (mask) {
> /*
> * If this is a mempolicy constrained oom, tsk's
> @@ -114,7 +113,6 @@ static bool oom_cpuset_eligible(struct task_struct *start,
> if (ret)
> break;
> }
> - rcu_read_unlock();
>
> return ret;
> }
> @@ -368,11 +366,9 @@ static void select_bad_process(struct oom_control *oc)
> else {
> struct task_struct *p;
>
> - rcu_read_lock();
> - for_each_process(p)
> + for_each_process_rcu(p)
> if (oom_evaluate_task(p, oc))
> break;
> - rcu_read_unlock();
> }
> }
>
> @@ -430,14 +426,12 @@ static void dump_tasks(struct oom_control *oc)
> struct task_struct *p;
> int i = 0;
>
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> /* Avoid potential softlockup warning */
> if ((++i & 1023) == 0)
> touch_softlockup_watchdog();
> dump_task(p, oc);
> }
> - rcu_read_unlock();
> }
> }
>
> @@ -894,8 +888,7 @@ static bool task_will_free_mem(struct task_struct *task)
> * are dying as well to make sure that a) nobody pins its mm and
> * b) the task is also reapable by the oom reaper.
> */
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (!process_shares_mm(p, mm))
> continue;
> if (same_thread_group(task, p))
> @@ -904,7 +897,6 @@ static bool task_will_free_mem(struct task_struct *task)
> if (!ret)
> break;
> }
> - rcu_read_unlock();
>
> return ret;
> }
> @@ -960,8 +952,7 @@ static void __oom_kill_process(struct task_struct *victim, const char *message)
> * That thread will now get access to memory reserves since it has a
> * pending fatal signal.
> */
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (!process_shares_mm(p, mm))
> continue;
> if (same_thread_group(p, victim))
> @@ -982,7 +973,6 @@ static void __oom_kill_process(struct task_struct *victim, const char *message)
> continue;
> do_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_TGID);
> }
> - rcu_read_unlock();
>
> if (can_oom_reap)
> queue_oom_reaper(victim);
> --
> 2.25.1
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu
2026-09-04 8:29 ` [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu Ye Liu
@ 2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:33 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:04 UTC (permalink / raw)
To: Ye Liu
Cc: Andrew Morton, David Hildenbrand, Ye Liu, Xu Xin, Chengming Zhou,
linux-mm, linux-kernel
On Fri 04-09-26 16:29:55, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pair combined
> with for_each_process() loop in mm/ksm.c with for_each_process_rcu().
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> mm/ksm.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/mm/ksm.c b/mm/ksm.c
> index 49d48d1e0998..fa5e4c47fb1b 100644
> --- a/mm/ksm.c
> +++ b/mm/ksm.c
> @@ -3280,8 +3280,7 @@ void collect_procs_ksm(const struct folio *folio, const struct page *page,
> struct anon_vma *av = rmap_item->anon_vma;
>
> anon_vma_lock_read(av);
> - rcu_read_lock();
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct anon_vma_chain *vmac;
> const unsigned long addr = rmap_item->address & PAGE_MASK;
> const unsigned long index = rmap_item->linear_page_index;
> @@ -3298,7 +3297,6 @@ void collect_procs_ksm(const struct folio *folio, const struct page *page,
> }
> }
> }
> - rcu_read_unlock();
> anon_vma_unlock_read(av);
> }
> }
> --
> 2.25.1
>
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 4/8] mm/memory-failure: convert process iterator to for_each_process_rcu
2026-09-04 8:29 ` [PATCH 4/8] mm/memory-failure: " Ye Liu
@ 2026-09-04 11:05 ` Michal Hocko
2026-09-05 0:39 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:05 UTC (permalink / raw)
To: Ye Liu
Cc: Miaohe Lin, Andrew Morton, Ye Liu, Naoya Horiguchi, linux-mm,
linux-kernel
On Fri 04-09-26 16:29:56, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
> with for_each_process() loop in mm/memory-failure.c with
> for_each_process_rcu().
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> mm/memory-failure.c | 16 ++++------------
> 1 file changed, 4 insertions(+), 12 deletions(-)
>
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index a8b03e2920ba..63a2ff08ee33 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -555,8 +555,7 @@ static void collect_procs_anon(const struct folio *folio,
> return;
>
> pgoff = page_pgoff(folio, page);
> - rcu_read_lock();
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct vm_area_struct *vma;
> struct anon_vma_chain *vmac;
> struct task_struct *t = task_early_kill(tsk, force_early);
> @@ -572,7 +571,6 @@ static void collect_procs_anon(const struct folio *folio,
> add_to_kill_anon_file(t, page, vma, to_kill, addr);
> }
> }
> - rcu_read_unlock();
> anon_vma_unlock_read(av);
> }
>
> @@ -589,9 +587,8 @@ static void collect_procs_file(const struct folio *folio,
> pgoff_t pgoff;
>
> i_mmap_lock_read(mapping);
> - rcu_read_lock();
> pgoff = page_pgoff(folio, page);
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct task_struct *t = task_early_kill(tsk, force_early);
> unsigned long addr;
>
> @@ -611,7 +608,6 @@ static void collect_procs_file(const struct folio *folio,
> add_to_kill_anon_file(t, page, vma, to_kill, addr);
> }
> }
> - rcu_read_unlock();
> i_mmap_unlock_read(mapping);
> }
>
> @@ -635,8 +631,7 @@ static void collect_procs_fsdax(const struct page *page,
> struct task_struct *tsk;
>
> i_mmap_lock_read(mapping);
> - rcu_read_lock();
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct task_struct *t = tsk;
>
> /*
> @@ -653,7 +648,6 @@ static void collect_procs_fsdax(const struct page *page,
> add_to_kill_fsdax(t, page, vma, to_kill, pgoff);
> }
> }
> - rcu_read_unlock();
> i_mmap_unlock_read(mapping);
> }
> #endif /* CONFIG_FS_DAX */
> @@ -2288,8 +2282,7 @@ static void collect_procs_pfn(struct pfn_address_space *pfn_space,
> struct address_space *mapping = pfn_space->mapping;
>
> i_mmap_lock_read(mapping);
> - rcu_read_lock();
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct task_struct *t = tsk;
>
> t = task_early_kill(tsk, true);
> @@ -2303,7 +2296,6 @@ static void collect_procs_pfn(struct pfn_address_space *pfn_space,
> add_to_kill_pgoff(t, vma, to_kill, pgoff);
> }
> }
> - rcu_read_unlock();
> i_mmap_unlock_read(mapping);
> }
>
> --
> 2.25.1
>
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu
@ 2026-09-04 11:06 ` Michal Hocko
2026-09-04 14:14 ` Günther Noack
1 sibling, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:06 UTC (permalink / raw)
To: Ye Liu
Cc: Thomas Gleixner, Peter Zijlstra, Rafael J. Wysocki,
Andrew Morton, Ingo Molnar, Will Deacon, Boqun Feng,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Juri Lelli,
Vincent Guittot, Steven Rostedt, Masami Hiramatsu,
Josh Poimboeuf, Ye Liu, Pavel Machek, Lance Yang, Petr Mladek,
Waiman Long, Mathieu Desnoyers, Lai Jiangshan, Zqiang,
Dietmar Eggemann, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Mark Rutland, linux-kernel, linux-pm, rcu,
linux-trace-kernel
On Fri 04-09-26 16:29:57, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() and guard(rcu)
> pairs combined with for_each_process(), for_each_thread() and
> for_each_process_thread() loops across kernel/ with the
> for_each_*_rcu() macros.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> kernel/cpu.c | 4 +---
> kernel/freezer.c | 4 +---
> kernel/hung_task.c | 7 ++-----
> kernel/locking/lockdep.c | 4 +---
> kernel/rcu/update.c | 4 +---
> kernel/sched/core.c | 3 +--
> kernel/sched/debug.c | 4 +---
> kernel/trace/fgraph.c | 8 ++------
> kernel/unwind/deferred.c | 3 +--
> 9 files changed, 11 insertions(+), 30 deletions(-)
>
> diff --git a/kernel/cpu.c b/kernel/cpu.c
> index b3c8553d7bd6..bc70fd21561a 100644
> --- a/kernel/cpu.c
> +++ b/kernel/cpu.c
> @@ -1254,8 +1254,7 @@ void clear_tasks_mm_cpumask(int cpu)
> * full-fledged tasklist_lock.
> */
> WARN_ON(cpu_online(cpu));
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> struct task_struct *t;
>
> /*
> @@ -1268,7 +1267,6 @@ void clear_tasks_mm_cpumask(int cpu)
> arch_clear_mm_cpumask_cpu(cpu, t->mm);
> task_unlock(t);
> }
> - rcu_read_unlock();
> }
>
> /* Take this CPU down. */
> diff --git a/kernel/freezer.c b/kernel/freezer.c
> index a76bf957fb32..a27b2382fda9 100644
> --- a/kernel/freezer.c
> +++ b/kernel/freezer.c
> @@ -217,11 +217,9 @@ void thaw_process(struct task_struct *p)
> {
> struct task_struct *t;
>
> - rcu_read_lock();
> - for_each_thread(p, t) {
> + for_each_thread_rcu(p, t) {
> __thaw_task(t);
> }
> - rcu_read_unlock();
> }
>
> /**
> diff --git a/kernel/hung_task.c b/kernel/hung_task.c
> index 6fcc94ce4ca9..76871f78497f 100644
> --- a/kernel/hung_task.c
> +++ b/kernel/hung_task.c
> @@ -315,8 +315,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
> return;
>
> this_round_count = 0;
> - rcu_read_lock();
> - for_each_process_thread(g, t) {
> + for_each_process_thread_rcu(g, t) {
> if (!max_count--)
> goto unlock;
> if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
> @@ -337,9 +336,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
> hung_task_info(t, timeout, this_round_count);
> }
> }
> - unlock:
> - rcu_read_unlock();
> -
> +unlock:
> if (!this_round_count)
> return;
>
> diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
> index c56a7f91d72e..9c3dce0f0c4b 100644
> --- a/kernel/locking/lockdep.c
> +++ b/kernel/locking/lockdep.c
> @@ -6834,15 +6834,13 @@ void debug_show_all_locks(void)
> }
> pr_warn("\nShowing all locks held in the system:\n");
>
> - rcu_read_lock();
> - for_each_process_thread(g, p) {
> + for_each_process_thread_rcu(g, p) {
> if (!p->lockdep_depth)
> continue;
> lockdep_print_held_locks(p);
> touch_nmi_watchdog();
> touch_all_softlockup_watchdogs();
> }
> - rcu_read_unlock();
>
> pr_warn("\n");
> pr_warn("=============================================\n\n");
> diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
> index 2a778b8ab4ad..c48a84a0da82 100644
> --- a/kernel/rcu/update.c
> +++ b/kernel/rcu/update.c
> @@ -548,15 +548,13 @@ void synchronize_rcu_trivial_preempt(void)
> struct task_struct *t;
>
> smp_mb(); // Order prior accesses before grace-period start.
> - rcu_read_lock(); // Protect task list.
> - for_each_process_thread(g, t) {
> + for_each_process_thread_rcu(g, t) {
> if (t == current)
> continue; // Don't deadlock on ourselves!
> // Order later rcu_read_lock() on other tasks after QS.
> while (smp_load_acquire(&t->rcu_trivial_preempt_nesting))
> continue;
> }
> - rcu_read_unlock();
> }
> EXPORT_SYMBOL_GPL(synchronize_rcu_trivial_preempt);
> #endif // #if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU)
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 0697ed0f1c3d..a41cdd2ff02f 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -2005,8 +2005,7 @@ static void uclamp_sync_util_min_rt_default(void)
> smp_mb__after_spinlock();
> read_unlock(&tasklist_lock);
>
> - guard(rcu)();
> - for_each_process_thread(g, p)
> + for_each_process_thread_rcu(g, p)
> uclamp_update_util_min_rt_default(p);
> }
>
> diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
> index 72236db67983..8f37b1a7adfe 100644
> --- a/kernel/sched/debug.c
> +++ b/kernel/sched/debug.c
> @@ -1029,14 +1029,12 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
> #endif
> "\n");
>
> - rcu_read_lock();
> - for_each_process_thread(g, p) {
> + for_each_process_thread_rcu(g, p) {
> if (task_cpu(p) != rq_cpu)
> continue;
>
> print_task(m, rq, p);
> }
> - rcu_read_unlock();
> }
>
> void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
> diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
> index 40d373d65f9b..e522433ec8a5 100644
> --- a/kernel/trace/fgraph.c
> +++ b/kernel/trace/fgraph.c
> @@ -1057,11 +1057,10 @@ static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
> }
> }
>
> - rcu_read_lock();
> - for_each_process_thread(g, t) {
> + for_each_process_thread_rcu(g, t) {
> if (start == end) {
> ret = -EAGAIN;
> - goto unlock;
> + goto free;
> }
>
> if (t->ret_stack == NULL) {
> @@ -1074,9 +1073,6 @@ static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
> t->ret_stack = ret_stack_list[start++];
> }
> }
> -
> -unlock:
> - rcu_read_unlock();
> free:
> for (i = start; i < end; i++)
> kmem_cache_free(fgraph_stack_cachep, ret_stack_list[i]);
> diff --git a/kernel/unwind/deferred.c b/kernel/unwind/deferred.c
> index 5bea47314254..61fe2d4727ce 100644
> --- a/kernel/unwind/deferred.c
> +++ b/kernel/unwind/deferred.c
> @@ -319,9 +319,8 @@ void unwind_deferred_cancel(struct unwind_work *work)
>
> synchronize_srcu(&unwind_srcu);
>
> - guard(rcu)();
> /* Clear this bit from all threads */
> - for_each_process_thread(g, t) {
> + for_each_process_thread_rcu(g, t) {
> atomic_long_andnot(BIT(bit),
> &t->unwind_info.unwind_mask);
> if (t->unwind_info.cache)
> --
> 2.25.1
>
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 6/8] fs: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
2026-09-04 9:05 ` Oleg Nesterov
2026-09-04 9:22 ` Lorenzo Stoakes (ARM)
@ 2026-09-04 11:06 ` Michal Hocko
2 siblings, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:06 UTC (permalink / raw)
To: Ye Liu
Cc: Tony Luck, Reinette Chatre, x86, Christian Brauner,
Andrew Morton, Jann Horn, David Hildenbrand (arm),
Mike Rapoport (Microsoft),
Alexey Dobriyan, Lorenzo Stoakes, Oleg Nesterov, Ye Liu,
Dave Martin, James Morse, Babu Moger, linux-kernel,
linux-fsdevel
On Fri 04-09-26 16:29:58, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
> with for_each_process() and for_each_process_thread() loops in fs/
> with the for_each_*_rcu() macros.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
> fs/proc/base.c | 4 +---
> fs/resctrl/rdtgroup.c | 8 ++------
> 2 files changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 6a39de424f62..da36ba73dc17 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -1160,8 +1160,7 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
> if (mm) {
> struct task_struct *p;
>
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (same_thread_group(task, p))
> continue;
>
> @@ -1177,7 +1176,6 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)
> }
> task_unlock(p);
> }
> - rcu_read_unlock();
> mmdrop(mm);
> }
> err_unlock:
> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
> index 5dcbb0a964e8..3f96d21b84ab 100644
> --- a/fs/resctrl/rdtgroup.c
> +++ b/fs/resctrl/rdtgroup.c
> @@ -709,14 +709,12 @@ int rdtgroup_tasks_assigned(struct rdtgroup *r)
>
> lockdep_assert_held(&rdtgroup_mutex);
>
> - rcu_read_lock();
> - for_each_process_thread(p, t) {
> + for_each_process_thread_rcu(p, t) {
> if (is_closid_match(t, r) || is_rmid_match(t, r)) {
> ret = 1;
> break;
> }
> }
> - rcu_read_unlock();
>
> return ret;
> }
> @@ -826,15 +824,13 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
> struct task_struct *p, *t;
> pid_t pid;
>
> - rcu_read_lock();
> - for_each_process_thread(p, t) {
> + for_each_process_thread_rcu(p, t) {
> if (is_closid_match(t, r) || is_rmid_match(t, r)) {
> pid = task_pid_vnr(t);
> if (pid)
> seq_printf(s, "%d\n", pid);
> }
> }
> - rcu_read_unlock();
> }
>
> static int rdtgroup_tasks_show(struct kernfs_open_file *of,
> --
> 2.25.1
>
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 7/8] lib: convert process iterator to for_each_process_rcu
2026-09-04 8:29 ` [PATCH 7/8] lib: convert process iterator to for_each_process_rcu Ye Liu
@ 2026-09-04 11:09 ` Michal Hocko
0 siblings, 0 replies; 28+ messages in thread
From: Michal Hocko @ 2026-09-04 11:09 UTC (permalink / raw)
To: Ye Liu; +Cc: Andrew Morton, Ye Liu, linux-kernel
On Fri 04-09-26 16:29:59, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pair combined
> with for_each_process() loop in lib/ with for_each_process_rcu().
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
> ---
> lib/is_single_threaded.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
> index 8c98b20bfc41..0682dc87bcdf 100644
> --- a/lib/is_single_threaded.c
> +++ b/lib/is_single_threaded.c
> @@ -26,8 +26,7 @@ bool current_is_single_threaded(void)
> return true;
>
> ret = false;
> - rcu_read_lock();
> - for_each_process(p) {
> + for_each_process_rcu(p) {
> if (unlikely(p->flags & PF_KTHREAD))
> continue;
> if (unlikely(p == task->group_leader))
> @@ -48,7 +47,5 @@ bool current_is_single_threaded(void)
> }
> ret = true;
> found:
> - rcu_read_unlock();
> -
> return ret;
This can be slightly simplified as below. Anyway
Acked-by: Michal Hocko <mhocko@suse.com>
---
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
index 8c98b20bfc41..4f7620481066 100644
--- a/lib/is_single_threaded.c
+++ b/lib/is_single_threaded.c
@@ -17,7 +17,6 @@ bool current_is_single_threaded(void)
struct task_struct *task = current;
struct mm_struct *mm = task->mm;
struct task_struct *p, *t;
- bool ret;
if (atomic_read(&task->signal->live) != 1)
return false;
@@ -25,9 +24,7 @@ bool current_is_single_threaded(void)
if (atomic_read(&mm->mm_users) == 1)
return true;
- ret = false;
- rcu_read_lock();
- for_each_process(p) {
+ for_each_process_rcu(p) {
if (unlikely(p->flags & PF_KTHREAD))
continue;
if (unlikely(p == task->group_leader))
@@ -35,7 +32,7 @@ bool current_is_single_threaded(void)
for_each_thread(p, t) {
if (unlikely(t->mm == mm))
- goto found;
+ return false
if (likely(t->mm))
break;
/*
@@ -46,9 +43,5 @@ bool current_is_single_threaded(void)
smp_rmb();
}
}
- ret = true;
-found:
- rcu_read_unlock();
-
- return ret;
+ return true;
}
--
Michal Hocko
SUSE Labs
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu
2026-09-04 8:30 ` [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu Ye Liu
@ 2026-09-04 12:21 ` Justin Suess
2026-09-04 14:17 ` Günther Noack
1 sibling, 0 replies; 28+ messages in thread
From: Justin Suess @ 2026-09-04 12:21 UTC (permalink / raw)
To: Ye Liu
Cc: Mickaël Salaün, Paul Moore, James Morris,
Serge E. Hallyn, Ye Liu, Günther Noack,
linux-security-module, linux-kernel
On Fri, Sep 04, 2026 at 04:30:00PM +0800, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace guard(rcu)() + for_each_thread() with for_each_thread_rcu(),
> so that the RCU read-side critical section is scoped to the loop body.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
> ---
> security/landlock/tsync.c | 8 ++------
> 1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> index 0b71e158c3f5..f1c08aae179b 100644
> --- a/security/landlock/tsync.c
> +++ b/security/landlock/tsync.c
> @@ -335,9 +335,7 @@ static size_t count_additional_threads(const struct tsync_works *works)
>
> caller = current;
>
> - guard(rcu)();
> -
> - for_each_thread(caller, thread) {
> + for_each_thread_rcu(caller, thread) {
> /* Skip current, since it is initiating the sync. */
> if (thread == caller)
> continue;
> @@ -376,9 +374,7 @@ static bool schedule_task_work(struct tsync_works *works,
>
> caller = current;
>
> - guard(rcu)();
> -
> - for_each_thread(caller, thread) {
> + for_each_thread_rcu(caller, thread) {
> /* Skip current, since it is initiating the sync. */
> if (thread == caller)
> continue;
Reviewed-by: Justin Suess <utilityemal77@gmail.com>
> --
> 2.25.1
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu
2026-09-04 11:06 ` Michal Hocko
@ 2026-09-04 14:14 ` Günther Noack
1 sibling, 0 replies; 28+ messages in thread
From: Günther Noack @ 2026-09-04 14:14 UTC (permalink / raw)
To: Ye Liu
Cc: Thomas Gleixner, Peter Zijlstra, Rafael J. Wysocki,
Andrew Morton, Ingo Molnar, Will Deacon, Boqun Feng,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Juri Lelli,
Vincent Guittot, Steven Rostedt, Masami Hiramatsu,
Josh Poimboeuf, Ye Liu, Pavel Machek, Lance Yang, Petr Mladek,
Waiman Long, Mathieu Desnoyers, Lai Jiangshan, Zqiang,
Dietmar Eggemann, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Mark Rutland, linux-kernel, linux-pm, rcu,
linux-trace-kernel
On Fri, Sep 04, 2026 at 04:29:57PM +0800, Ye Liu wrote:
> diff --git a/kernel/hung_task.c b/kernel/hung_task.c
> index 6fcc94ce4ca9..76871f78497f 100644
> --- a/kernel/hung_task.c
> +++ b/kernel/hung_task.c
> @@ -337,9 +336,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
> hung_task_info(t, timeout, this_round_count);
> }
> }
> - unlock:
> - rcu_read_unlock();
> -
> +unlock:
> if (!this_round_count)
> return;
The label name "unlock" is misleading now. There is no further unlock
happening after it any more.
–Günther
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu
2026-09-04 8:30 ` [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu Ye Liu
2026-09-04 12:21 ` Justin Suess
@ 2026-09-04 14:17 ` Günther Noack
1 sibling, 0 replies; 28+ messages in thread
From: Günther Noack @ 2026-09-04 14:17 UTC (permalink / raw)
To: Ye Liu
Cc: Mickaël Salaün, Paul Moore, James Morris,
Serge E. Hallyn, Ye Liu, Günther Noack,
linux-security-module, linux-kernel
On Fri, Sep 04, 2026 at 04:30:00PM +0800, Ye Liu wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace guard(rcu)() + for_each_thread() with for_each_thread_rcu(),
> so that the RCU read-side critical section is scoped to the loop body.
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
> ---
> security/landlock/tsync.c | 8 ++------
> 1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> index 0b71e158c3f5..f1c08aae179b 100644
> --- a/security/landlock/tsync.c
> +++ b/security/landlock/tsync.c
> @@ -335,9 +335,7 @@ static size_t count_additional_threads(const struct tsync_works *works)
>
> caller = current;
>
> - guard(rcu)();
> -
> - for_each_thread(caller, thread) {
> + for_each_thread_rcu(caller, thread) {
> /* Skip current, since it is initiating the sync. */
> if (thread == caller)
> continue;
> @@ -376,9 +374,7 @@ static bool schedule_task_work(struct tsync_works *works,
>
> caller = current;
>
> - guard(rcu)();
> -
> - for_each_thread(caller, thread) {
> + for_each_thread_rcu(caller, thread) {
> /* Skip current, since it is initiating the sync. */
> if (thread == caller)
> continue;
> --
> 2.25.1
>
Reviewed-by: Günther Noack <gnoack3000@gmail.com>
Looks good, provided that the for_each_thread_rcu() macro gets
accepted.
Although, I find that in the Landlock case, it does not provide a very
strong advantage over the explicit "guard(rcu)();", and I find it
normally preferrable to use orthogonal APIs.
–Günther
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
2026-09-04 11:03 ` Michal Hocko
@ 2026-09-04 16:25 ` Steven Rostedt
2026-09-04 21:17 ` Thomas Gleixner
1 sibling, 1 reply; 28+ messages in thread
From: Steven Rostedt @ 2026-09-04 16:25 UTC (permalink / raw)
To: Ye Liu
Cc: Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner, linux-kernel
On Fri, 4 Sep 2026 16:29:53 +0800
Ye Liu <ye.liu@linux.dev> wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Introduce for_each_process_rcu(), for_each_thread_rcu() and
> for_each_process_thread_rcu() macros that acquire the RCU read lock
> before the iteration starts and release it when the loop is left, so
> that the RCU read-side critical section is scoped to the loop body
> instead of an externally managed rcu_read_lock()/rcu_read_unlock()
> pair.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
> ---
> include/linux/sched/signal.h | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
> index 584ae88b435e..fe0c41dc99a1 100644
> --- a/include/linux/sched/signal.h
> +++ b/include/linux/sched/signal.h
> @@ -2,6 +2,7 @@
> #ifndef _LINUX_SCHED_SIGNAL_H
> #define _LINUX_SCHED_SIGNAL_H
>
> +#include <linux/cleanup.h>
> #include <linux/rculist.h>
> #include <linux/signal.h>
> #include <linux/sched.h>
> @@ -663,6 +664,24 @@ extern bool current_is_single_threaded(void);
> #define for_each_process_thread(p, t) \
> for_each_process(p) for_each_thread(p, t)
>
> +/*
> + * RCU-internal variants: automatically acquire and release the RCU read
> + * lock around the iteration. Equivalent to scoped_guard(rcu) combined
> + * with the respective non-_rcu variant.
> + */
> +#define for_each_process_rcu(p) \
> + scoped_guard(rcu) \
> + for (p = &init_task ; (p = next_task(p)) != &init_task ; )
> +
> +#define for_each_thread_rcu(p, t) \
> + scoped_guard(rcu) \
> + __for_each_thread((p)->signal, t)
> +
I would rename it to: *_rculock()
as there are already *_rcu() list iterators that are used to be done within
an rcu locked region. Using just *_rcu() would make it confusing to know if
the rcu lock was taken or if the loop is expected to be locked within RCU.
> +/* Careful: this is a double loop, 'break' won't work as expected. */
> +#define for_each_process_thread_rcu(p, t) \
> + scoped_guard(rcu) \
> + for_each_process(p) for_each_thread(p, t)
I would not do this one. It is prone to bugs. As it is a double loop, the
way to "break" is to do a goto. That will be bug to have a goto jump out of
a scoped_guard().
-- Steve
> +
> typedef int (*proc_visitor)(struct task_struct *p, void *data);
> void walk_process_tree(struct task_struct *top, proc_visitor, void *);
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 16:25 ` Steven Rostedt
@ 2026-09-04 21:17 ` Thomas Gleixner
2026-09-04 23:07 ` Steven Rostedt
0 siblings, 1 reply; 28+ messages in thread
From: Thomas Gleixner @ 2026-09-04 21:17 UTC (permalink / raw)
To: Steven Rostedt, Ye Liu
Cc: Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner, linux-kernel
On Fri, Sep 04 2026 at 12:25, Steven Rostedt wrote:
> On Fri, 4 Sep 2026 16:29:53 +0800
> Ye Liu <ye.liu@linux.dev> wrote:
>> +#define for_each_thread_rcu(p, t) \
>> + scoped_guard(rcu) \
>> + __for_each_thread((p)->signal, t)
>> +
>
> I would rename it to: *_rculock()
>
> as there are already *_rcu() list iterators that are used to be done within
> an rcu locked region. Using just *_rcu() would make it confusing to know if
> the rcu lock was taken or if the loop is expected to be locked within RCU.
Ack.
>> +/* Careful: this is a double loop, 'break' won't work as expected. */
>> +#define for_each_process_thread_rcu(p, t) \
>> + scoped_guard(rcu) \
>> + for_each_process(p) for_each_thread(p, t)
>
> I would not do this one. It is prone to bugs. As it is a double loop, the
> way to "break" is to do a goto. That will be bug to have a goto jump out of
> a scoped_guard().
No. Scopes can be left by any valid termination mechanism.
The only problematic case of leaving a scoped_guard() with goto is when
the goto is actually implemented as an ASM goto. See the comment above
arch_unsafe_get_user() in linux/uaccess.h.
But I agree that requiring a goto to break out of the nested loop is
nasty especially when it's not well documented. The copied original
comment is pretty useless.
Thanks,
tglx
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 21:17 ` Thomas Gleixner
@ 2026-09-04 23:07 ` Steven Rostedt
2026-09-05 7:27 ` Thomas Gleixner
0 siblings, 1 reply; 28+ messages in thread
From: Steven Rostedt @ 2026-09-04 23:07 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Ye Liu, Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner, linux-kernel
On Fri, 04 Sep 2026 23:17:38 +0200
Thomas Gleixner <tglx@kernel.org> wrote:
> No. Scopes can be left by any valid termination mechanism.
>
> The only problematic case of leaving a scoped_guard() with goto is when
> the goto is actually implemented as an ASM goto. See the comment above
> arch_unsafe_get_user() in linux/uaccess.h.
Oh OK. I was under the impression that goto's could cause undefined
behavior with guards. Or is that just when a goto jumps over one? Or is
that OK too?
-- Steve
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu
2026-09-04 8:29 ` [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu Ye Liu
2026-09-04 11:04 ` Michal Hocko
@ 2026-09-05 0:32 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: SJ Park @ 2026-09-05 0:32 UTC (permalink / raw)
To: Ye Liu
Cc: SJ Park, Michal Hocko, Andrew Morton, Ye Liu, David Rientjes,
Shakeel Butt, linux-mm, linux-kernel
On Fri, 4 Sep 2026 16:29:54 +0800 Ye Liu <ye.liu@linux.dev> wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs wrapping
> for_each_process()/for_each_thread() loops with for_each_process_rcu()
> and for_each_thread_rcu(), so that the RCU read-side critical section
> is scoped to the loop body.
Looks clean to me :)
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Reviewed-by: SJ Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu
2026-09-04 8:29 ` [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu Ye Liu
2026-09-04 11:04 ` Michal Hocko
@ 2026-09-05 0:33 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: SJ Park @ 2026-09-05 0:33 UTC (permalink / raw)
To: Ye Liu
Cc: SJ Park, Andrew Morton, David Hildenbrand, Ye Liu, Xu Xin,
Chengming Zhou, linux-mm, linux-kernel
On Fri, 4 Sep 2026 16:29:55 +0800 Ye Liu <ye.liu@linux.dev> wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pair combined
> with for_each_process() loop in mm/ksm.c with for_each_process_rcu().
>
> No functional change.
Looks clean to me, thank you.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
Reviewed-by: SJ Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 4/8] mm/memory-failure: convert process iterator to for_each_process_rcu
2026-09-04 8:29 ` [PATCH 4/8] mm/memory-failure: " Ye Liu
2026-09-04 11:05 ` Michal Hocko
@ 2026-09-05 0:39 ` SJ Park
1 sibling, 0 replies; 28+ messages in thread
From: SJ Park @ 2026-09-05 0:39 UTC (permalink / raw)
To: Ye Liu
Cc: SJ Park, Miaohe Lin, Andrew Morton, Ye Liu, Naoya Horiguchi,
linux-mm, linux-kernel
On Fri, 4 Sep 2026 16:29:56 +0800 Ye Liu <ye.liu@linux.dev> wrote:
> From: Ye Liu <liuye@kylinos.cn>
>
> Replace the manual rcu_read_lock()/rcu_read_unlock() pairs combined
> with for_each_process() loop in mm/memory-failure.c with
> for_each_process_rcu().
>
> No functional change.
>
> Signed-off-by: Ye Liu <liuye@kylinos.cn>
> ---
> mm/memory-failure.c | 16 ++++------------
> 1 file changed, 4 insertions(+), 12 deletions(-)
>
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index a8b03e2920ba..63a2ff08ee33 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -555,8 +555,7 @@ static void collect_procs_anon(const struct folio *folio,
> return;
>
> pgoff = page_pgoff(folio, page);
> - rcu_read_lock();
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct vm_area_struct *vma;
> struct anon_vma_chain *vmac;
> struct task_struct *t = task_early_kill(tsk, force_early);
> @@ -572,7 +571,6 @@ static void collect_procs_anon(const struct folio *folio,
> add_to_kill_anon_file(t, page, vma, to_kill, addr);
> }
> }
> - rcu_read_unlock();
> anon_vma_unlock_read(av);
> }
>
> @@ -589,9 +587,8 @@ static void collect_procs_file(const struct folio *folio,
> pgoff_t pgoff;
>
> i_mmap_lock_read(mapping);
> - rcu_read_lock();
> pgoff = page_pgoff(folio, page);
> - for_each_process(tsk) {
> + for_each_process_rcu(tsk) {
> struct task_struct *t = task_early_kill(tsk, force_early);
> unsigned long addr;
This moves pgoff assignment out of the RCU critical section. Is this fine and
making no real functional change? If it is fine and no functiona change, could
we clarify the reasons on the commit message?
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 1/8] mm: introduce for_each_process_rcu and for_each_thread_rcu
2026-09-04 23:07 ` Steven Rostedt
@ 2026-09-05 7:27 ` Thomas Gleixner
0 siblings, 0 replies; 28+ messages in thread
From: Thomas Gleixner @ 2026-09-05 7:27 UTC (permalink / raw)
To: Steven Rostedt
Cc: Ye Liu, Peter Zijlstra (Intel),
Marco Elver, Ye Liu, Yi Tao, Tejun Heo, Bart Van Assche,
Christian Brauner, linux-kernel
On Fri, Sep 04 2026 at 19:07, Steven Rostedt wrote:
> On Fri, 04 Sep 2026 23:17:38 +0200
> Thomas Gleixner <tglx@kernel.org> wrote:
>
>> No. Scopes can be left by any valid termination mechanism.
>>
>> The only problematic case of leaving a scoped_guard() with goto is when
>> the goto is actually implemented as an ASM goto. See the comment above
>> arch_unsafe_get_user() in linux/uaccess.h.
>
> Oh OK. I was under the impression that goto's could cause undefined
> behavior with guards. Or is that just when a goto jumps over one? Or is
> that OK too?
Jump where ever you want. The keyword is 'scope'.
The normal visibility rules of variables in C scopes apply. So if the
scope for which a variable is defined is left and the variable is
defined with __attribute__((__cleanup__(cleanup_func))) then the compiler
inserts a call to 'cleanup_func()'.
The problem with ASM GOTO is that the 'goto' is not visible to the C
compiler because it is burried in the asm inline. Clang detects it at
some later point and fails the build. GCC simply emits buggy code or at
least used to. Haven't checked whether that's still the case.
So we worked around that by letting the ASM goto jump to a local label
within the scope and use goto 'outofscope' from there. That makes it
observe that the scope is left and the cleanup call is inserted at the
right place. See 3eb6660f26d1 ("uaccess: Provide ASM GOTO safe wrappers
for unsafe_*_user()")
Thanks,
tglx
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2026-09-05 7:27 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 8:29 [PATCH 0/8] mm: introduce for_each_process_rcu and for_each_thread_rcu Ye Liu
2026-09-04 8:29 ` [PATCH 1/8] " Ye Liu
2026-09-04 11:03 ` Michal Hocko
2026-09-04 16:25 ` Steven Rostedt
2026-09-04 21:17 ` Thomas Gleixner
2026-09-04 23:07 ` Steven Rostedt
2026-09-05 7:27 ` Thomas Gleixner
2026-09-04 8:29 ` [PATCH 2/8] mm/oom_kill: convert process/thread iterators to for_each_*_rcu Ye Liu
2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:32 ` SJ Park
2026-09-04 8:29 ` [PATCH 3/8] mm/ksm: convert process iterator to for_each_process_rcu Ye Liu
2026-09-04 11:04 ` Michal Hocko
2026-09-05 0:33 ` SJ Park
2026-09-04 8:29 ` [PATCH 4/8] mm/memory-failure: " Ye Liu
2026-09-04 11:05 ` Michal Hocko
2026-09-05 0:39 ` SJ Park
2026-09-04 8:29 ` [PATCH 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu
2026-09-04 11:06 ` Michal Hocko
2026-09-04 14:14 ` Günther Noack
2026-09-04 8:29 ` [PATCH 6/8] fs: " Ye Liu
2026-09-04 9:05 ` Oleg Nesterov
2026-09-04 9:22 ` Lorenzo Stoakes (ARM)
2026-09-04 11:06 ` Michal Hocko
2026-09-04 8:29 ` [PATCH 7/8] lib: convert process iterator to for_each_process_rcu Ye Liu
2026-09-04 11:09 ` Michal Hocko
2026-09-04 8:30 ` [PATCH 8/8] security/landlock: convert thread iterator to for_each_thread_rcu Ye Liu
2026-09-04 12:21 ` Justin Suess
2026-09-04 14:17 ` Günther Noack
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®