* [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 5/8] kernel: convert process/thread iterators to for_each_*_rcu Ye Liu 0 siblings, 1 reply; 4+ 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] 4+ 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 @ 2026-09-04 8:29 ` Ye Liu 2026-09-04 11:06 ` Michal Hocko 2026-09-04 14:14 ` Günther Noack 0 siblings, 2 replies; 4+ 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 related [flat|nested] 4+ 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; 4+ 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] 4+ 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; 4+ 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] 4+ messages in thread
end of thread, other threads:[~2026-09-04 14:14 UTC | newest] Thread overview: 4+ 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 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox