All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
@ 2026-06-22  4:05 Kaitao Cheng
  2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
                   ` (8 more replies)
  0 siblings, 9 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, chengkaitao

From: chengkaitao <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may remove
the current entry.  Their current interface, however, forces every caller
to define a temporary cursor outside the macro and pass it in, even when
the caller never uses that cursor directly.  For most call sites this
extra cursor is just boilerplate required by the macro implementation.

This is awkward because the saved next pointer is an internal detail of
the iteration.  Callers that only remove or move the current entry do not
need to spell it out.

The _safe() suffix has also caused confusion.  Christian Koenig pointed
out that the name is easy to read as a thread-safe variant, especially
for beginners, even though it only means that the iterator keeps enough
state to tolerate removal of the current entry.  He suggested _mutable()
as a clearer description of what the loop permits.

Add *_mutable() iterator variants for list, hlist and llist.  The new
helpers are variadic and support both forms.  In the common case, the
caller omits the temporary cursor and the macro creates a unique internal
cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
explicit temporary cursor, the caller can still pass it and the helper
keeps the existing *_safe() behaviour.

For example, a call site may use the shorter form:

  list_for_each_entry_mutable(pos, head, member)

or keep the explicit temporary cursor form:

  list_for_each_entry_mutable(pos, tmp, head, member)

The existing *_safe() helpers remain available for compatibility.  This
series only converts users in mm, block, kernel, init and io_uring.  If
this approach looks acceptable, the remaining users can be converted in
follow-up series.

Changes in v3 (Christian König, Andy Shevchenko):
- Convert safe list walks to mutable iterators

Changes in v2 (Muchun Song, Andy Shevchenko):
- Drop the list_for_each_entry_mutable*() helpers from v1 and make the
  cursor change directly in the existing list_for_each_entry*() helpers.
- Open-code special list walks that rely on updating the loop cursor in
  the body, preserving their existing traversal semantics.

Link to v2:
https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/

Link to v1:
https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/

Kaitao Cheng (7):
  list: Add mutable iterator variants
  llist: Add mutable iterator variants
  mm: Use mutable list iterators
  block: Use mutable list iterators
  kernel: Use mutable list iterators
  initramfs: Use mutable list iterator
  io_uring: Use mutable list iterators

 block/bfq-iosched.c                 |  17 +-
 block/blk-cgroup.c                  |  12 +-
 block/blk-flush.c                   |   4 +-
 block/blk-iocost.c                  |  18 +-
 block/blk-mq.c                      |   8 +-
 block/blk-throttle.c                |   4 +-
 block/kyber-iosched.c               |   4 +-
 block/partitions/ldm.c              |   8 +-
 block/sed-opal.c                    |   4 +-
 include/linux/list.h                | 269 ++++++++++++++++++++++++----
 include/linux/llist.h               |  81 +++++++--
 init/initramfs.c                    |   5 +-
 io_uring/cancel.c                   |   6 +-
 io_uring/poll.c                     |   3 +-
 io_uring/rw.c                       |   4 +-
 io_uring/timeout.c                  |   8 +-
 io_uring/uring_cmd.c                |   3 +-
 kernel/audit_tree.c                 |   4 +-
 kernel/audit_watch.c                |  16 +-
 kernel/auditfilter.c                |   4 +-
 kernel/auditsc.c                    |   4 +-
 kernel/bpf/arena.c                  |  10 +-
 kernel/bpf/arraymap.c               |   8 +-
 kernel/bpf/bpf_local_storage.c      |   3 +-
 kernel/bpf/bpf_lru_list.c           |  25 ++-
 kernel/bpf/btf.c                    |  18 +-
 kernel/bpf/cgroup.c                 |   7 +-
 kernel/bpf/cpumap.c                 |   4 +-
 kernel/bpf/devmap.c                 |  10 +-
 kernel/bpf/helpers.c                |   8 +-
 kernel/bpf/local_storage.c          |   4 +-
 kernel/bpf/memalloc.c               |  16 +-
 kernel/bpf/offload.c                |   8 +-
 kernel/bpf/states.c                 |   4 +-
 kernel/bpf/stream.c                 |   4 +-
 kernel/bpf/verifier.c               |   6 +-
 kernel/cgroup/cgroup-v1.c           |   4 +-
 kernel/cgroup/cgroup.c              |  54 +++---
 kernel/cgroup/dmem.c                |  12 +-
 kernel/cgroup/rdma.c                |   8 +-
 kernel/events/core.c                |  44 +++--
 kernel/events/uprobes.c             |  12 +-
 kernel/exit.c                       |   8 +-
 kernel/fail_function.c              |   4 +-
 kernel/gcov/clang.c                 |   4 +-
 kernel/irq_work.c                   |   4 +-
 kernel/kexec_core.c                 |   4 +-
 kernel/kprobes.c                    |  16 +-
 kernel/livepatch/core.c             |   4 +-
 kernel/livepatch/core.h             |   4 +-
 kernel/liveupdate/kho_block.c       |   4 +-
 kernel/liveupdate/luo_flb.c         |   4 +-
 kernel/locking/rwsem.c              |   2 +-
 kernel/locking/test-ww_mutex.c      |   2 +-
 kernel/module/main.c                |  11 +-
 kernel/padata.c                     |   4 +-
 kernel/power/snapshot.c             |   8 +-
 kernel/power/wakelock.c             |   4 +-
 kernel/printk/printk.c              |  11 +-
 kernel/ptrace.c                     |   4 +-
 kernel/rcu/rcutorture.c             |   3 +-
 kernel/rcu/tasks.h                  |   9 +-
 kernel/rcu/tree.c                   |   6 +-
 kernel/resource.c                   |   4 +-
 kernel/sched/core.c                 |   4 +-
 kernel/sched/ext.c                  |  22 +--
 kernel/sched/fair.c                 |  28 +--
 kernel/sched/topology.c             |   4 +-
 kernel/sched/wait.c                 |   4 +-
 kernel/seccomp.c                    |   4 +-
 kernel/signal.c                     |  11 +-
 kernel/smp.c                        |   4 +-
 kernel/taskstats.c                  |   8 +-
 kernel/time/clockevents.c           |   6 +-
 kernel/time/clocksource.c           |   4 +-
 kernel/time/posix-cpu-timers.c      |   4 +-
 kernel/time/posix-timers.c          |   3 +-
 kernel/torture.c                    |   3 +-
 kernel/trace/bpf_trace.c            |   4 +-
 kernel/trace/ftrace.c               |  49 +++--
 kernel/trace/ring_buffer.c          |  25 ++-
 kernel/trace/trace.c                |  12 +-
 kernel/trace/trace_dynevent.c       |   6 +-
 kernel/trace/trace_dynevent.h       |   5 +-
 kernel/trace/trace_events.c         |  35 ++--
 kernel/trace/trace_events_filter.c  |   4 +-
 kernel/trace/trace_events_hist.c    |   8 +-
 kernel/trace/trace_events_trigger.c |  17 +-
 kernel/trace/trace_events_user.c    |  16 +-
 kernel/trace/trace_stat.c           |   4 +-
 kernel/user-return-notifier.c       |   3 +-
 kernel/workqueue.c                  |  16 +-
 mm/backing-dev.c                    |   8 +-
 mm/balloon.c                        |   8 +-
 mm/cma.c                            |   4 +-
 mm/compaction.c                     |   4 +-
 mm/damon/core.c                     |   4 +-
 mm/damon/sysfs-schemes.c            |   4 +-
 mm/dmapool.c                        |   4 +-
 mm/huge_memory.c                    |   8 +-
 mm/hugetlb.c                        |  56 +++---
 mm/hugetlb_vmemmap.c                |  16 +-
 mm/khugepaged.c                     |  14 +-
 mm/kmemleak.c                       |   7 +-
 mm/ksm.c                            |  25 +--
 mm/list_lru.c                       |   4 +-
 mm/memcontrol-v1.c                  |   8 +-
 mm/memory-failure.c                 |  12 +-
 mm/memory-tiers.c                   |   4 +-
 mm/migrate.c                        |  23 ++-
 mm/mmu_notifier.c                   |   9 +-
 mm/page_alloc.c                     |   8 +-
 mm/page_reporting.c                 |   2 +-
 mm/percpu.c                         |  11 +-
 mm/pgtable-generic.c                |   4 +-
 mm/rmap.c                           |  10 +-
 mm/shmem.c                          |   9 +-
 mm/slab_common.c                    |  14 +-
 mm/slub.c                           |  33 ++--
 mm/swapfile.c                       |   4 +-
 mm/userfaultfd.c                    |  12 +-
 mm/vmalloc.c                        |  24 +--
 mm/vmscan.c                         |   7 +-
 mm/zsmalloc.c                       |   4 +-
 124 files changed, 875 insertions(+), 681 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 1/7] list: Add mutable iterator variants
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
@ 2026-06-22  4:05 ` Kaitao Cheng
  2026-06-22  8:42   ` David Laight
  2026-06-22  8:51   ` Christian König
  2026-06-22  4:05 ` [PATCH v3 2/7] llist: " Kaitao Cheng
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may
remove the current entry.  Their API exposes the temporary cursor at
every call site, even though most users only need it for the iterator
implementation and never reference it in the loop body.

Add *_mutable() variants for list and hlist iteration.  The new helpers
support both forms: callers may keep passing an explicit temporary cursor
when they need to inspect or reset it, or omit it and let the helper use
a unique internal cursor.

This makes call sites that only mutate the list through the current entry
less noisy, while keeping the existing *_safe() helpers available for
compatibility.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 231 insertions(+), 38 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index 09d979976b3b..1081def7cea9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -7,6 +7,7 @@
 #include <linux/stddef.h>
 #include <linux/poison.h>
 #include <linux/const.h>
+#include <linux/args.h>
 
 #include <asm/barrier.h>
 
@@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_for_each_prev(pos, head) \
 	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
 
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+/*
+ * list_for_each_safe is an old interface, use list_for_each_mutable instead.
  */
 #define list_for_each_safe(pos, n, head) \
 	for (pos = (head)->next, n = pos->next; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->next)
 
+#define __list_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->next)->next;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->next)
+
+#define __list_for_each_mutable1(pos, head)				\
+	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __list_for_each_mutable2(pos, next, head)			\
+	list_for_each_safe(pos, next, head)
+
 /**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * list_for_each_mutable - iterate over a list safe against entry removal
  * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_mutable(pos, ...)					\
+	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_prev_safe is an old interface, use list_for_each_prev_mutable instead.
  */
 #define list_for_each_prev_safe(pos, n, head) \
 	for (pos = (head)->prev, n = pos->prev; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->prev)
 
+#define __list_for_each_prev_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->prev)->prev;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->prev)
+
+#define __list_for_each_prev_mutable1(pos, head)			\
+	__list_for_each_prev_mutable_internal(pos, __UNIQUE_ID(prev), head)
+
+#define __list_for_each_prev_mutable2(pos, prev, head)			\
+	list_for_each_prev_safe(pos, prev, head)
+
+/**
+ * list_for_each_prev_mutable - iterate over a list backwards safe against entry removal
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @...:	either (head) or (prev, head)
+ *
+ * prev:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_prev_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_prev_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
 /**
  * list_count_nodes - count nodes in the list
  * @head:	the head for your list.
@@ -895,12 +940,8 @@ static inline size_t list_count_nodes(struct list_head *head)
 	for (; !list_entry_is_head(pos, head, member);			\
 	     pos = list_prev_entry(pos, member))
 
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+/*
+ * list_for_each_entry_safe is an old interface, use list_for_each_entry_mutable instead.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
 	for (pos = list_first_entry(head, typeof(*pos), member),	\
@@ -908,15 +949,36 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_first_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable2(pos, head, member)		\
+	__list_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable3(pos, next, head, member)		\
+	list_for_each_entry_safe(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * list_for_each_entry_mutable - iterate over a list safe against entry removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_entry_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_continue is an old interface,
+ * use list_for_each_entry_mutable_continue instead.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
 	for (pos = list_next_entry(pos, member), 				\
@@ -924,30 +986,79 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_continue_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_next_entry(pos, member), member);			\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_continue2(pos, head, member)	\
+	__list_for_each_entry_mutable_continue_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_continue3(pos, next, head, member) \
+	list_for_each_entry_safe_continue(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * list_for_each_entry_mutable_continue - continue list iteration safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_mutable_continue(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_continue,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_from is an old interface,
+ * use list_for_each_entry_mutable_from instead.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
 	for (n = list_next_entry(pos, member);					\
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_from_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos, member);		\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_from2(pos, head, member)		\
+	__list_for_each_entry_mutable_from_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_from3(pos, next, head, member)	\
+	list_for_each_entry_safe_from(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * list_for_each_entry_mutable_from - iterate over list from current point safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_mutable_from(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_from,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_reverse is an old interface,
+ * use list_for_each_entry_mutable_reverse instead.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
 	for (pos = list_last_entry(head, typeof(*pos), member),		\
@@ -955,6 +1066,37 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_prev_entry(n, member))
 
+#define __list_for_each_entry_mutable_reverse_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_prev_entry(pos =			\
+		list_last_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_prev_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_reverse2(pos, head, member)	\
+	__list_for_each_entry_mutable_reverse_internal(pos,		\
+		__UNIQUE_ID(prev), head, member)
+
+#define __list_for_each_entry_mutable_reverse3(pos, prev, head, member)	\
+	list_for_each_entry_safe_reverse(pos, prev, head, member)
+
+/**
+ * list_for_each_entry_mutable_reverse - iterate backwards over list safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (prev, head, member)
+ *
+ * prev:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_mutable_reverse(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_reverse,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
  * @pos:	the loop cursor used in the list_for_each_entry_safe loop
@@ -1189,6 +1331,31 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
 	     pos = n)
 
+#define __hlist_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->first) ? pos->next : NULL; \
+	     pos;							\
+	     pos = tmp, tmp = pos ? pos->next : NULL)
+
+#define __hlist_for_each_mutable1(pos, head)				\
+	__hlist_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __hlist_for_each_mutable2(pos, next, head)			\
+	hlist_for_each_safe(pos, next, head)
+
+/**
+ * hlist_for_each_mutable - iterate over a hlist safe against entry removal
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct hlist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your hlist.
+ */
+#define hlist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
 #define hlist_entry_safe(ptr, type, member) \
 	({ typeof(ptr) ____ptr = (ptr); \
 	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
@@ -1224,18 +1391,44 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (; pos;							\
 	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
 
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		a &struct hlist_node to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the hlist_node within the struct.
+/*
+ * hlist_for_each_entry_safe is an old interface, use hlist_for_each_entry_mutable instead.
  */
 #define hlist_for_each_entry_safe(pos, n, head, member) 		\
 	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
 	     pos && ({ n = pos->member.next; 1; });			\
 	     pos = hlist_entry_safe(n, typeof(*pos), member))
 
+#define __hlist_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (struct hlist_node *tmp = (pos =				\
+		hlist_entry_safe((head)->first, typeof(*pos), member)) ? \
+		pos->member.next : NULL;				\
+	     pos;							\
+	     pos = hlist_entry_safe((tmp), typeof(*pos), member),	\
+		tmp = pos ? pos->member.next : NULL)
+
+#define __hlist_for_each_entry_mutable2(pos, head, member)		\
+	__hlist_for_each_entry_mutable_internal(pos,			\
+		__UNIQUE_ID(next), head, member)
+
+#define __hlist_for_each_entry_mutable3(pos, next, head, member)	\
+	hlist_for_each_entry_safe(pos, next, head, member)
+
+/**
+ * hlist_for_each_entry_mutable - iterate over hlist safe against entry removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (next, head, member)
+ *
+ * next:	a &struct hlist_node to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your hlist.
+ * member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * hlist_count_nodes - count nodes in the hlist
  * @head:	the head for your hlist.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 2/7] llist: Add mutable iterator variants
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
  2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
@ 2026-06-22  4:05 ` Kaitao Cheng
  2026-06-22  4:15 ` [PATCH v3 3/7] mm: Use mutable list iterators Kaitao Cheng
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

llist_for_each_safe() and llist_for_each_entry_safe() require callers to
provide a temporary cursor even when the cursor is only needed by the
iterator itself.  This makes call sites noisier than necessary for the
common case where the loop body may remove the current entry but does
not otherwise inspect the saved next pointer.

Add llist_for_each_mutable() and llist_for_each_entry_mutable() variants
that support both forms.  Callers may omit the temporary cursor and let
the helper create an internal unique cursor, or keep passing an explicit
cursor when the loop needs to inspect or reset it.

Keep the existing safe helpers as compatibility wrappers so current users
continue to build unchanged while new code can use the shorter mutable
form.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/llist.h | 81 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 16 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index 8846b7709669..1c6f12411d5e 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -49,6 +49,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/args.h>
 #include <linux/container_of.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -143,12 +144,33 @@ static inline bool llist_on_list(const struct llist_node *node)
 #define llist_for_each(pos, node)			\
 	for ((pos) = (node); pos; (pos) = (pos)->next)
 
+/*
+ * llist_for_each_safe is an old interface, use llist_for_each_mutable instead.
+ */
+#define llist_for_each_safe(pos, n, node)			\
+	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+
+#define __llist_for_each_mutable_internal(pos, tmp, node)		\
+	for (typeof(pos) tmp = ((pos) = (node)) ? (pos)->next : NULL;	\
+	     (pos);							\
+	     (pos) = tmp, tmp = (pos) ? (pos)->next : NULL)
+
+#define __llist_for_each_mutable1(pos, node)				\
+	__llist_for_each_mutable_internal(pos, __UNIQUE_ID(next), node)
+
+#define __llist_for_each_mutable2(pos, next, node)			\
+	llist_for_each_safe(pos, next, node)
+
 /**
- * llist_for_each_safe - iterate over some deleted entries of a lock-less list
- *			 safe against removal of list entry
+ * llist_for_each_mutable - iterate over some deleted entries of a lock-less list
+ *			    safe against removal of list entry
  * @pos:	the &struct llist_node to use as a loop cursor
- * @n:		another &struct llist_node to use as temporary storage
- * @node:	the first entry of deleted list entries
+ * @...:	either (node) or (next, node)
+ *
+ * next:	another &struct llist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * node:	the first entry of deleted list entries
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being deleted from list, so start with an entry
@@ -159,8 +181,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_safe(pos, n, node)			\
-	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+#define llist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
 
 /**
  * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type
@@ -182,13 +205,41 @@ static inline bool llist_on_list(const struct llist_node *node)
 	     member_address_is_nonnull(pos, member);			\
 	     (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
+/*
+ * llist_for_each_entry_safe is an old interface, use llist_for_each_entry_mutable instead.
+ */
+#define llist_for_each_entry_safe(pos, n, node, member)			       \
+	for (pos = llist_entry((node), typeof(*pos), member);		       \
+	     member_address_is_nonnull(pos, member) &&			       \
+	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
+	     pos = n)
+
+#define __llist_for_each_entry_mutable_internal(pos, tmp, node, member)	\
+	for (typeof(pos) tmp = ((pos) = llist_entry((node), typeof(*pos), member), \
+		member_address_is_nonnull(pos, member) ?			\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL);	\
+	     member_address_is_nonnull(pos, member);				\
+	     (pos) = tmp, tmp = member_address_is_nonnull(pos, member) ?	\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL)
+
+#define __llist_for_each_entry_mutable2(pos, node, member)			\
+	__llist_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), node, member)
+
+#define __llist_for_each_entry_mutable3(pos, next, node, member)		\
+	llist_for_each_entry_safe(pos, next, node, member)
+
 /**
- * llist_for_each_entry_safe - iterate over some deleted entries of lock-less list of given type
- *			       safe against removal of list entry
+ * llist_for_each_entry_mutable - iterate over some deleted entries of
+ *				  lock-less list of given type safe against
+ *				  removal of list entry
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @node:	the first entry of deleted list entries.
- * @member:	the name of the llist_node with the struct.
+ * @...:	either (node, member) or (next, node, member)
+ *
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * node:	the first entry of deleted list entries.
+ * member:	the name of the llist_node with the struct.
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being removed from list, so start with an entry
@@ -199,11 +250,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_entry_safe(pos, n, node, member)			       \
-	for (pos = llist_entry((node), typeof(*pos), member);		       \
-	     member_address_is_nonnull(pos, member) &&			       \
-	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
-	     pos = n)
+#define llist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
 
 /**
  * llist_empty - tests whether a lock-less list is empty
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 3/7] mm: Use mutable list iterators
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
  2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
  2026-06-22  4:05 ` [PATCH v3 2/7] llist: " Kaitao Cheng
@ 2026-06-22  4:15 ` Kaitao Cheng
  2026-06-22  4:57   ` sashiko-bot
  2026-06-22  4:28 ` [PATCH v3 5/7] kernel: " Kaitao Cheng
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:15 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, SeongJae Park, Muchun Song,
	Oscar Salvador, Catalin Marinas, Dave Chinner, Shakeel Butt,
	Miaohe Lin, Dennis Zhou, Tejun Heo, Christoph Lameter,
	Hugh Dickins, Chris Li, Kairui Song, Uladzislau Rezki,
	Minchan Kim, Sergey Senozhatsky
  Cc: linux-mm, linux-kernel, virtualization, damon, cgroups,
	Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iterators expose a temporary cursor at every call site,
even when the cursor is only needed by the iterator itself.  The mutable
iterator variants keep the removal-safe traversal semantics while hiding
that temporary cursor from callers that do not need it.

Convert mm users of the list, hlist and llist safe iterators to the new
mutable helpers.  Drop the temporary cursor variables where the loop does
not inspect or reset them, and keep the explicit cursor at the few sites
that rely on it across lock drops or after the loop.

This is a mechanical cleanup with no intended change in traversal order
or list mutation behavior.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 mm/backing-dev.c         |  8 +++---
 mm/balloon.c             |  8 +++---
 mm/cma.c                 |  4 +--
 mm/compaction.c          |  4 +--
 mm/damon/core.c          |  4 +--
 mm/damon/sysfs-schemes.c |  4 +--
 mm/dmapool.c             |  4 +--
 mm/huge_memory.c         |  8 +++---
 mm/hugetlb.c             | 56 ++++++++++++++++++++--------------------
 mm/hugetlb_vmemmap.c     | 16 ++++++------
 mm/khugepaged.c          | 14 +++++-----
 mm/kmemleak.c            |  7 +++--
 mm/ksm.c                 | 25 +++++++-----------
 mm/list_lru.c            |  4 +--
 mm/memcontrol-v1.c       |  8 +++---
 mm/memory-failure.c      | 12 ++++-----
 mm/memory-tiers.c        |  4 +--
 mm/migrate.c             | 23 ++++++++---------
 mm/mmu_notifier.c        |  9 +++----
 mm/page_alloc.c          |  8 +++---
 mm/page_reporting.c      |  2 +-
 mm/percpu.c              | 11 ++++----
 mm/pgtable-generic.c     |  4 +--
 mm/rmap.c                | 10 +++----
 mm/shmem.c               |  9 ++++---
 mm/slab_common.c         | 14 +++++-----
 mm/slub.c                | 33 ++++++++++++-----------
 mm/swapfile.c            |  4 +--
 mm/userfaultfd.c         | 12 ++++-----
 mm/vmalloc.c             | 24 ++++++++---------
 mm/vmscan.c              |  7 +++--
 mm/zsmalloc.c            |  4 +--
 32 files changed, 175 insertions(+), 189 deletions(-)

diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index cecbcf9060a6..944b9cc7a424 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -932,10 +932,10 @@ static void cleanup_offline_cgwbs_workfn(struct work_struct *work)
 void wb_memcg_offline(struct mem_cgroup *memcg)
 {
 	struct list_head *memcg_cgwb_list = &memcg->cgwb_list;
-	struct bdi_writeback *wb, *next;
+	struct bdi_writeback *wb;
 
 	spin_lock_irq(&cgwb_lock);
-	list_for_each_entry_safe(wb, next, memcg_cgwb_list, memcg_node)
+	list_for_each_entry_mutable(wb, memcg_cgwb_list, memcg_node)
 		cgwb_kill(wb);
 	memcg_cgwb_list->next = NULL;	/* prevent new wb's */
 	spin_unlock_irq(&cgwb_lock);
@@ -951,11 +951,11 @@ void wb_memcg_offline(struct mem_cgroup *memcg)
  */
 void wb_blkcg_offline(struct cgroup_subsys_state *css)
 {
-	struct bdi_writeback *wb, *next;
+	struct bdi_writeback *wb;
 	struct list_head *list = blkcg_get_cgwb_list(css);
 
 	spin_lock_irq(&cgwb_lock);
-	list_for_each_entry_safe(wb, next, list, blkcg_node)
+	list_for_each_entry_mutable(wb, list, blkcg_node)
 		cgwb_kill(wb);
 	list->next = NULL;	/* prevent new wb's */
 	spin_unlock_irq(&cgwb_lock);
diff --git a/mm/balloon.c b/mm/balloon.c
index 96a8f1e20bc6..74a7c411b244 100644
--- a/mm/balloon.c
+++ b/mm/balloon.c
@@ -75,12 +75,12 @@ static void balloon_page_enqueue_one(struct balloon_dev_info *b_dev_info,
 size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info,
 				 struct list_head *pages)
 {
-	struct page *page, *tmp;
+	struct page *page;
 	unsigned long flags;
 	size_t n_pages = 0;
 
 	spin_lock_irqsave(&balloon_pages_lock, flags);
-	list_for_each_entry_safe(page, tmp, pages, lru) {
+	list_for_each_entry_mutable(page, pages, lru) {
 		list_del(&page->lru);
 		balloon_page_enqueue_one(b_dev_info, page);
 		n_pages++;
@@ -111,12 +111,12 @@ EXPORT_SYMBOL_GPL(balloon_page_list_enqueue);
 size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info,
 				 struct list_head *pages, size_t n_req_pages)
 {
-	struct page *page, *tmp;
+	struct page *page;
 	unsigned long flags;
 	size_t n_pages = 0;
 
 	spin_lock_irqsave(&balloon_pages_lock, flags);
-	list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
+	list_for_each_entry_mutable(page, &b_dev_info->pages, lru) {
 		if (n_pages == n_req_pages)
 			break;
 		list_del(&page->lru);
diff --git a/mm/cma.c b/mm/cma.c
index a13ce4999b39..2c6543fe530e 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -539,7 +539,7 @@ int __init cma_declare_contiguous_multi(phys_addr_t total_size,
 	struct cma_memrange *cmrp;
 	LIST_HEAD(ranges);
 	LIST_HEAD(final_ranges);
-	struct list_head *mp, *next;
+	struct list_head *mp;
 	int ret, nr = 1;
 	u64 i;
 	struct cma *cma;
@@ -648,7 +648,7 @@ int __init cma_declare_contiguous_multi(phys_addr_t total_size,
 	 * want to mimic a bottom-up memblock allocation.
 	 */
 	sizesum = 0;
-	list_for_each_safe(mp, next, &ranges) {
+	list_for_each_mutable(mp, &ranges) {
 		mlp = list_entry(mp, struct cma_init_memrange, list);
 		list_del(mp);
 		list_insert_sorted(&final_ranges, mlp, basecmp);
diff --git a/mm/compaction.c b/mm/compaction.c
index b776f35ad020..1734f7978983 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -94,9 +94,9 @@ static unsigned long release_free_list(struct list_head *freepages)
 	unsigned long high_pfn = 0;
 
 	for (order = 0; order < NR_PAGE_ORDERS; order++) {
-		struct page *page, *next;
+		struct page *page;
 
-		list_for_each_entry_safe(page, next, &freepages[order], lru) {
+		list_for_each_entry_mutable(page, &freepages[order], lru) {
 			unsigned long pfn = page_to_pfn(page);
 
 			list_del(&page->lru);
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 7e4b9affc5b0..bb1f4466f7af 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -3394,7 +3394,7 @@ static void damon_verify_ctx(struct damon_ctx *c)
  */
 static void kdamond_call(struct damon_ctx *ctx, bool cancel)
 {
-	struct damon_call_control *control, *next;
+	struct damon_call_control *control;
 	LIST_HEAD(controls);
 
 	damon_verify_ctx(ctx);
@@ -3403,7 +3403,7 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
 	list_splice_tail_init(&ctx->call_controls, &controls);
 	mutex_unlock(&ctx->call_controls_lock);
 
-	list_for_each_entry_safe(control, next, &controls, list) {
+	list_for_each_entry_mutable(control, &controls, list) {
 		if (!control->repeat || cancel)
 			list_del(&control->list);
 
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 329cfd0bbe9f..701b1947bad4 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -329,9 +329,9 @@ static ssize_t total_bytes_show(struct kobject *kobj,
 static void damon_sysfs_scheme_regions_rm_dirs(
 		struct damon_sysfs_scheme_regions *regions)
 {
-	struct damon_sysfs_scheme_region *r, *next;
+	struct damon_sysfs_scheme_region *r;
 
-	list_for_each_entry_safe(r, next, &regions->regions_list, list) {
+	list_for_each_entry_mutable(r, &regions->regions_list, list) {
 		damos_sysfs_region_rm_dirs(r);
 		list_del(&r->list);
 		kobject_put(&r->kobj);
diff --git a/mm/dmapool.c b/mm/dmapool.c
index 5d8af6e29127..226b505ace23 100644
--- a/mm/dmapool.c
+++ b/mm/dmapool.c
@@ -362,7 +362,7 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
  */
 void dma_pool_destroy(struct dma_pool *pool)
 {
-	struct dma_page *page, *tmp;
+	struct dma_page *page;
 	bool empty, busy = false;
 
 	if (unlikely(!pool))
@@ -382,7 +382,7 @@ void dma_pool_destroy(struct dma_pool *pool)
 		busy = true;
 	}
 
-	list_for_each_entry_safe(page, tmp, &pool->page_list, page_list) {
+	list_for_each_entry_mutable(page, &pool->page_list, page_list) {
 		if (!busy)
 			dma_free_coherent(pool->dev, pool->allocation,
 					  page->vaddr, page->dma);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2bccb0a53a0a..39d604f0876d 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -924,9 +924,9 @@ static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 
 static void __init hugepage_exit_sysfs(struct kobject *hugepage_kobj)
 {
-	struct thpsize *thpsize, *tmp;
+	struct thpsize *thpsize;
 
-	list_for_each_entry_safe(thpsize, tmp, &thpsize_list, node) {
+	list_for_each_entry_mutable(thpsize, &thpsize_list, node) {
 		list_del(&thpsize->node);
 		kobject_put(&thpsize->kobj);
 	}
@@ -4462,14 +4462,14 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
 		struct shrink_control *sc)
 {
 	LIST_HEAD(dispose);
-	struct folio *folio, *next;
+	struct folio *folio;
 	int split = 0;
 	unsigned long isolated;
 
 	isolated = list_lru_shrink_walk_irq(&deferred_split_lru, sc,
 					    deferred_split_isolate, &dispose);
 
-	list_for_each_entry_safe(folio, next, &dispose, _deferred_list) {
+	list_for_each_entry_mutable(folio, &dispose, _deferred_list) {
 		bool did_split = false;
 		bool underused = false;
 
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 571212b80835..765552a56086 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -598,7 +598,7 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
 	long add = 0;
 	struct list_head *head = &resv->regions;
 	long last_accounted_offset = f;
-	struct file_region *iter, *trg = NULL;
+	struct file_region *iter;
 	struct list_head *rg = NULL;
 
 	if (regions_needed)
@@ -608,7 +608,7 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
 	 * [last_accounted_offset, iter->from), at every iteration, with some
 	 * bounds checking.
 	 */
-	list_for_each_entry_safe(iter, trg, head, link) {
+	list_for_each_entry_mutable(iter, head, link) {
 		/* Skip irrelevant regions that start before our range. */
 		if (iter->from < f) {
 			/* If this region ends after the last accounted offset,
@@ -700,7 +700,7 @@ static int allocate_file_region_entries(struct resv_map *resv,
 	return 0;
 
 out_of_memory:
-	list_for_each_entry_safe(rg, trg, &allocated_regions, link) {
+	list_for_each_entry_mutable(rg, &allocated_regions, link) {
 		list_del(&rg->link);
 		kfree(rg);
 	}
@@ -853,13 +853,13 @@ static void region_abort(struct resv_map *resv, long f, long t,
 static long region_del(struct resv_map *resv, long f, long t)
 {
 	struct list_head *head = &resv->regions;
-	struct file_region *rg, *trg;
+	struct file_region *rg;
 	struct file_region *nrg = NULL;
 	long del = 0;
 
 retry:
 	spin_lock(&resv->lock);
-	list_for_each_entry_safe(rg, trg, head, link) {
+	list_for_each_entry_mutable(rg, head, link) {
 		/*
 		 * Skip regions before the range to be deleted.  file_region
 		 * ranges are normally of the form [from, to).  However, there
@@ -1109,13 +1109,13 @@ void resv_map_release(struct kref *ref)
 {
 	struct resv_map *resv_map = container_of(ref, struct resv_map, refs);
 	struct list_head *head = &resv_map->region_cache;
-	struct file_region *rg, *trg;
+	struct file_region *rg;
 
 	/* Clear out any active regions before we release the map. */
 	region_del(resv_map, 0, LONG_MAX);
 
 	/* ... and any entries left in the cache */
-	list_for_each_entry_safe(rg, trg, head, link) {
+	list_for_each_entry_mutable(rg, head, link) {
 		list_del(&rg->link);
 		kfree(rg);
 	}
@@ -1582,7 +1582,7 @@ static void bulk_vmemmap_restore_error(struct hstate *h,
 					struct list_head *folio_list,
 					struct list_head *non_hvo_folios)
 {
-	struct folio *folio, *t_folio;
+	struct folio *folio;
 
 	if (!list_empty(non_hvo_folios)) {
 		/*
@@ -1592,7 +1592,7 @@ static void bulk_vmemmap_restore_error(struct hstate *h,
 		 * hugetlb pages with vmemmap we will free up memory so that we
 		 * can allocate vmemmap for more hugetlb pages.
 		 */
-		list_for_each_entry_safe(folio, t_folio, non_hvo_folios, lru) {
+		list_for_each_entry_mutable(folio, non_hvo_folios, lru) {
 			list_del(&folio->lru);
 			spin_lock_irq(&hugetlb_lock);
 			__folio_clear_hugetlb(folio);
@@ -1611,7 +1611,7 @@ static void bulk_vmemmap_restore_error(struct hstate *h,
 		 * If are able to restore vmemmap and free one hugetlb page, we
 		 * quit processing the list to retry the bulk operation.
 		 */
-		list_for_each_entry_safe(folio, t_folio, folio_list, lru)
+		list_for_each_entry_mutable(folio, folio_list, lru)
 			if (hugetlb_vmemmap_restore_folio(h, folio)) {
 				list_del(&folio->lru);
 				spin_lock_irq(&hugetlb_lock);
@@ -1633,7 +1633,7 @@ static void update_and_free_pages_bulk(struct hstate *h,
 						struct list_head *folio_list)
 {
 	long ret;
-	struct folio *folio, *t_folio;
+	struct folio *folio;
 	LIST_HEAD(non_hvo_folios);
 
 	/*
@@ -1664,7 +1664,7 @@ static void update_and_free_pages_bulk(struct hstate *h,
 		spin_unlock_irq(&hugetlb_lock);
 	}
 
-	list_for_each_entry_safe(folio, t_folio, &non_hvo_folios, lru) {
+	list_for_each_entry_mutable(folio, &non_hvo_folios, lru) {
 		update_and_free_hugetlb_folio(h, folio, false);
 		cond_resched();
 	}
@@ -1875,14 +1875,14 @@ void prep_and_add_allocated_folios(struct hstate *h,
 				   struct list_head *folio_list)
 {
 	unsigned long flags;
-	struct folio *folio, *tmp_f;
+	struct folio *folio;
 
 	/* Send list for bulk vmemmap optimization processing */
 	hugetlb_vmemmap_optimize_folios(h, folio_list);
 
 	/* Add all new pool pages to free lists in one lock cycle */
 	spin_lock_irqsave(&hugetlb_lock, flags);
-	list_for_each_entry_safe(folio, tmp_f, folio_list, lru) {
+	list_for_each_entry_mutable(folio, folio_list, lru) {
 		account_new_hugetlb_folio(h, folio);
 		enqueue_hugetlb_folio(h, folio);
 	}
@@ -2246,7 +2246,7 @@ static int gather_surplus_pages(struct hstate *h, long delta)
 	__must_hold(&hugetlb_lock)
 {
 	LIST_HEAD(surplus_list);
-	struct folio *folio, *tmp;
+	struct folio *folio;
 	int ret;
 	long i;
 	long needed, allocated;
@@ -2319,7 +2319,7 @@ static int gather_surplus_pages(struct hstate *h, long delta)
 	ret = 0;
 
 	/* Free the needed pages to the hugetlb pool */
-	list_for_each_entry_safe(folio, tmp, &surplus_list, lru) {
+	list_for_each_entry_mutable(folio, &surplus_list, lru) {
 		if ((--needed) < 0)
 			break;
 		/* Add the page to the hugetlb allocator */
@@ -2332,7 +2332,7 @@ static int gather_surplus_pages(struct hstate *h, long delta)
 	 * Free unnecessary surplus pages to the buddy allocator.
 	 * Pages have no ref count, call free_huge_folio directly.
 	 */
-	list_for_each_entry_safe(folio, tmp, &surplus_list, lru)
+	list_for_each_entry_mutable(folio, &surplus_list, lru)
 		free_huge_folio(folio);
 	spin_lock_irq(&hugetlb_lock);
 
@@ -3197,12 +3197,12 @@ static void __init prep_and_add_bootmem_folios(struct hstate *h,
 					struct list_head *folio_list)
 {
 	unsigned long flags;
-	struct folio *folio, *tmp_f;
+	struct folio *folio;
 
 	/* Send list for bulk vmemmap optimization processing */
 	hugetlb_vmemmap_optimize_bootmem_folios(h, folio_list);
 
-	list_for_each_entry_safe(folio, tmp_f, folio_list, lru) {
+	list_for_each_entry_mutable(folio, folio_list, lru) {
 		if (!folio_test_hugetlb_vmemmap_optimized(folio)) {
 			/*
 			 * If HVO fails, initialize all tail struct pages
@@ -3281,10 +3281,10 @@ static void __init hugetlb_bootmem_free_invalid_page(int nid, struct page *page,
 static void __init gather_bootmem_prealloc_node(unsigned long nid)
 {
 	LIST_HEAD(folio_list);
-	struct huge_bootmem_page *m, *tm;
+	struct huge_bootmem_page *m;
 	struct hstate *h = NULL, *prev_h = NULL;
 
-	list_for_each_entry_safe(m, tm, &huge_boot_pages[nid], list) {
+	list_for_each_entry_mutable(m, &huge_boot_pages[nid], list) {
 		struct page *page = virt_to_page(m);
 		struct folio *folio = (void *)page;
 
@@ -3669,9 +3669,9 @@ static void try_to_free_low(struct hstate *h, unsigned long count,
 	 * Collect pages to be freed on a list, and free after dropping lock
 	 */
 	for_each_node_mask(i, *nodes_allowed) {
-		struct folio *folio, *next;
+		struct folio *folio;
 		struct list_head *freel = &h->hugepage_freelists[i];
-		list_for_each_entry_safe(folio, next, freel, lru) {
+		list_for_each_entry_mutable(folio, freel, lru) {
 			if (count >= h->nr_huge_pages)
 				goto out;
 			if (folio_test_highmem(folio))
@@ -3920,7 +3920,7 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,
 				       struct list_head *src_list)
 {
 	long rc;
-	struct folio *folio, *next;
+	struct folio *folio;
 	LIST_HEAD(dst_list);
 	LIST_HEAD(ret_list);
 
@@ -3937,7 +3937,7 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,
 	 */
 	mutex_lock(&dst->resize_lock);
 
-	list_for_each_entry_safe(folio, next, src_list, lru) {
+	list_for_each_entry_mutable(folio, src_list, lru) {
 		int i;
 		bool cma;
 
@@ -3995,9 +3995,9 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 
 	for_each_node_mask_to_free(src, nr_nodes, node, nodes_allowed) {
 		LIST_HEAD(list);
-		struct folio *folio, *next;
+		struct folio *folio;
 
-		list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lru) {
+		list_for_each_entry_mutable(folio, &src->hugepage_freelists[node], lru) {
 			if (folio_test_hwpoison(folio))
 				continue;
 
@@ -4014,7 +4014,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 
 		spin_lock_irq(&hugetlb_lock);
 
-		list_for_each_entry_safe(folio, next, &list, lru) {
+		list_for_each_entry_mutable(folio, &list, lru) {
 			list_del(&folio->lru);
 			add_hugetlb_folio(src, folio, false);
 
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index 133b46dfb09f..88552d60ae60 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -193,9 +193,9 @@ static inline void free_vmemmap_page(struct page *page)
 /* Free a list of the vmemmap pages */
 static void free_vmemmap_page_list(struct list_head *list)
 {
-	struct page *page, *next;
+	struct page *page;
 
-	list_for_each_entry_safe(page, next, list, lru)
+	list_for_each_entry_mutable(page, list, lru)
 		free_vmemmap_page(page);
 }
 
@@ -339,7 +339,7 @@ static int alloc_vmemmap_page_list(unsigned long start, unsigned long end,
 	gfp_t gfp_mask = GFP_KERNEL | __GFP_RETRY_MAYFAIL;
 	unsigned long nr_pages = (end - start) >> PAGE_SHIFT;
 	int nid = page_to_nid((struct page *)start);
-	struct page *page, *next;
+	struct page *page;
 	int i;
 
 	for (i = 0; i < nr_pages; i++) {
@@ -352,7 +352,7 @@ static int alloc_vmemmap_page_list(unsigned long start, unsigned long end,
 
 	return 0;
 out:
-	list_for_each_entry_safe(page, next, list, lru)
+	list_for_each_entry_mutable(page, list, lru)
 		__free_page(page);
 	return -ENOMEM;
 }
@@ -454,12 +454,12 @@ long hugetlb_vmemmap_restore_folios(const struct hstate *h,
 					struct list_head *folio_list,
 					struct list_head *non_hvo_folios)
 {
-	struct folio *folio, *t_folio;
+	struct folio *folio;
 	long restored = 0;
 	long ret = 0;
 	unsigned long flags = VMEMMAP_REMAP_NO_TLB_FLUSH;
 
-	list_for_each_entry_safe(folio, t_folio, folio_list, lru) {
+	list_for_each_entry_mutable(folio, folio_list, lru) {
 		if (folio_test_hugetlb_vmemmap_optimized(folio)) {
 			ret = __hugetlb_vmemmap_restore_folio(h, folio, flags);
 			if (ret)
@@ -800,7 +800,7 @@ static struct zone *pfn_to_zone(unsigned nid, unsigned long pfn)
 
 void __init hugetlb_vmemmap_init_late(int nid)
 {
-	struct huge_bootmem_page *m, *tm;
+	struct huge_bootmem_page *m;
 	unsigned long phys, nr_pages, start, end;
 	unsigned long pfn, nr_mmap;
 	struct zone *zone = NULL;
@@ -810,7 +810,7 @@ void __init hugetlb_vmemmap_init_late(int nid)
 	if (!READ_ONCE(vmemmap_optimize_enabled))
 		return;
 
-	list_for_each_entry_safe(m, tm, &huge_boot_pages[nid], list) {
+	list_for_each_entry_mutable(m, &huge_boot_pages[nid], list) {
 		if (!(m->flags & HUGE_BOOTMEM_HVO))
 			continue;
 
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 617bca76db49..66a1d72b5cb8 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -640,7 +640,7 @@ static void release_pte_folio(struct folio *folio)
 static void release_pte_pages(pte_t *pte, pte_t *_pte,
 		struct list_head *compound_pagelist)
 {
-	struct folio *folio, *tmp;
+	struct folio *folio;
 
 	while (--_pte >= pte) {
 		pte_t pteval = ptep_get(_pte);
@@ -658,7 +658,7 @@ static void release_pte_pages(pte_t *pte, pte_t *_pte,
 		release_pte_folio(folio);
 	}
 
-	list_for_each_entry_safe(folio, tmp, compound_pagelist, lru) {
+	list_for_each_entry_mutable(folio, compound_pagelist, lru) {
 		list_del(&folio->lru);
 		release_pte_folio(folio);
 	}
@@ -835,7 +835,7 @@ static void __collapse_huge_page_copy_succeeded(pte_t *pte,
 {
 	const unsigned long nr_pages = 1UL << order;
 	unsigned long end = address + (PAGE_SIZE * nr_pages);
-	struct folio *src, *tmp;
+	struct folio *src;
 	pte_t pteval;
 	pte_t *_pte;
 	unsigned int nr_ptes;
@@ -882,7 +882,7 @@ static void __collapse_huge_page_copy_succeeded(pte_t *pte,
 		}
 	}
 
-	list_for_each_entry_safe(src, tmp, compound_pagelist, lru) {
+	list_for_each_entry_mutable(src, compound_pagelist, lru) {
 		list_del(&src->lru);
 		node_stat_sub_folio(src, NR_ISOLATED_ANON +
 				folio_is_file_lru(src));
@@ -2244,7 +2244,7 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr,
 {
 	struct address_space *mapping = file->f_mapping;
 	struct page *dst;
-	struct folio *folio, *tmp, *new_folio;
+	struct folio *folio, *new_folio;
 	pgoff_t index = 0, end = start + HPAGE_PMD_NR;
 	LIST_HEAD(pagelist);
 	XA_STATE_ORDER(xas, &mapping->i_pages, start, HPAGE_PMD_ORDER);
@@ -2629,7 +2629,7 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr,
 	/*
 	 * The collapse has succeeded, so free the old folios.
 	 */
-	list_for_each_entry_safe(folio, tmp, &pagelist, lru) {
+	list_for_each_entry_mutable(folio, &pagelist, lru) {
 		list_del(&folio->lru);
 		lruvec_stat_mod_folio(folio, NR_FILE_PAGES,
 				      -folio_nr_pages(folio));
@@ -2654,7 +2654,7 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr,
 		shmem_uncharge(mapping->host, nr_none);
 	}
 
-	list_for_each_entry_safe(folio, tmp, &pagelist, lru) {
+	list_for_each_entry_mutable(folio, &pagelist, lru) {
 		list_del(&folio->lru);
 		folio_unlock(folio);
 		folio_putback_lru(folio);
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 7c7ba17ce7af..0c0265f7b19f 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -537,7 +537,6 @@ static void mem_pool_free(struct kmemleak_object *object)
  */
 static void free_object_rcu(struct rcu_head *rcu)
 {
-	struct hlist_node *tmp;
 	struct kmemleak_scan_area *area;
 	struct kmemleak_object *object =
 		container_of(rcu, struct kmemleak_object, rcu);
@@ -546,7 +545,7 @@ static void free_object_rcu(struct rcu_head *rcu)
 	 * Once use_count is 0 (guaranteed by put_object), there is no other
 	 * code accessing this object, hence no need for locking.
 	 */
-	hlist_for_each_entry_safe(area, tmp, &object->area_list, node) {
+	hlist_for_each_entry_mutable(area, &object->area_list, node) {
 		hlist_del(&area->node);
 		kmem_cache_free(scan_area_cache, area);
 	}
@@ -2324,14 +2323,14 @@ static const struct file_operations kmemleak_fops = {
 
 static void __kmemleak_do_cleanup(void)
 {
-	struct kmemleak_object *object, *tmp;
+	struct kmemleak_object *object;
 	unsigned int cnt = 0;
 
 	/*
 	 * Kmemleak has already been disabled, no need for RCU list traversal
 	 * or kmemleak_lock held.
 	 */
-	list_for_each_entry_safe(object, tmp, &object_list, object_list) {
+	list_for_each_entry_mutable(object, &object_list, object_list) {
 		__remove_object(object);
 		__delete_object(object);
 
diff --git a/mm/ksm.c b/mm/ksm.c
index 7d5b76478f0b..f42bc885f179 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1145,7 +1145,6 @@ static int remove_stable_node_chain(struct ksm_stable_node *stable_node,
 				    struct rb_root *root)
 {
 	struct ksm_stable_node *dup;
-	struct hlist_node *hlist_safe;
 
 	if (!is_stable_node_chain(stable_node)) {
 		VM_BUG_ON(is_stable_node_dup(stable_node));
@@ -1155,8 +1154,7 @@ static int remove_stable_node_chain(struct ksm_stable_node *stable_node,
 			return false;
 	}
 
-	hlist_for_each_entry_safe(dup, hlist_safe,
-				  &stable_node->hlist, hlist_dup) {
+	hlist_for_each_entry_mutable(dup, &stable_node->hlist, hlist_dup) {
 		VM_BUG_ON(!is_stable_node_dup(dup));
 		if (remove_stable_node(dup))
 			return true;
@@ -1168,7 +1166,7 @@ static int remove_stable_node_chain(struct ksm_stable_node *stable_node,
 
 static int remove_all_stable_nodes(void)
 {
-	struct ksm_stable_node *stable_node, *next;
+	struct ksm_stable_node *stable_node;
 	int nid;
 	int err = 0;
 
@@ -1184,7 +1182,7 @@ static int remove_all_stable_nodes(void)
 			cond_resched();
 		}
 	}
-	list_for_each_entry_safe(stable_node, next, &migrate_nodes, list) {
+	list_for_each_entry_mutable(stable_node, &migrate_nodes, list) {
 		if (remove_stable_node(stable_node))
 			err = -EBUSY;
 		cond_resched();
@@ -1665,7 +1663,6 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
 				     bool prune_stale_stable_nodes)
 {
 	struct ksm_stable_node *dup, *found = NULL, *stable_node = *_stable_node;
-	struct hlist_node *hlist_safe;
 	struct folio *folio, *tree_folio = NULL;
 	int found_rmap_hlist_len;
 
@@ -1677,8 +1674,7 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
 	else
 		stable_node->chain_prune_time = jiffies;
 
-	hlist_for_each_entry_safe(dup, hlist_safe,
-				  &stable_node->hlist, hlist_dup) {
+	hlist_for_each_entry_mutable(dup, &stable_node->hlist, hlist_dup) {
 		cond_resched();
 		/*
 		 * We must walk all stable_node_dup to prune the stale
@@ -2611,11 +2607,10 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
 		 * so prune them once before each full scan.
 		 */
 		if (!ksm_merge_across_nodes) {
-			struct ksm_stable_node *stable_node, *next;
+			struct ksm_stable_node *stable_node;
 			struct folio *folio;
 
-			list_for_each_entry_safe(stable_node, next,
-						 &migrate_nodes, list) {
+			list_for_each_entry_mutable(stable_node, &migrate_nodes, list) {
 				folio = ksm_get_folio(stable_node,
 						      KSM_GET_FOLIO_NOLOCK);
 				if (folio)
@@ -3323,7 +3318,6 @@ static bool stable_node_chain_remove_range(struct ksm_stable_node *stable_node,
 					   struct rb_root *root)
 {
 	struct ksm_stable_node *dup;
-	struct hlist_node *hlist_safe;
 
 	if (!is_stable_node_chain(stable_node)) {
 		VM_BUG_ON(is_stable_node_dup(stable_node));
@@ -3331,8 +3325,7 @@ static bool stable_node_chain_remove_range(struct ksm_stable_node *stable_node,
 						    end_pfn);
 	}
 
-	hlist_for_each_entry_safe(dup, hlist_safe,
-				  &stable_node->hlist, hlist_dup) {
+	hlist_for_each_entry_mutable(dup, &stable_node->hlist, hlist_dup) {
 		VM_BUG_ON(!is_stable_node_dup(dup));
 		stable_node_dup_remove_range(dup, start_pfn, end_pfn);
 	}
@@ -3346,7 +3339,7 @@ static bool stable_node_chain_remove_range(struct ksm_stable_node *stable_node,
 static void ksm_check_stable_tree(unsigned long start_pfn,
 				  unsigned long end_pfn)
 {
-	struct ksm_stable_node *stable_node, *next;
+	struct ksm_stable_node *stable_node;
 	struct rb_node *node;
 	int nid;
 
@@ -3364,7 +3357,7 @@ static void ksm_check_stable_tree(unsigned long start_pfn,
 			cond_resched();
 		}
 	}
-	list_for_each_entry_safe(stable_node, next, &migrate_nodes, list) {
+	list_for_each_entry_mutable(stable_node, &migrate_nodes, list) {
 		if (stable_node->kpfn >= start_pfn &&
 		    stable_node->kpfn < end_pfn)
 			remove_node_from_stable_tree(stable_node);
diff --git a/mm/list_lru.c b/mm/list_lru.c
index 36662d02ff96..ab9f48828a05 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -340,7 +340,7 @@ __list_lru_walk_one(struct list_lru *lru, int nid, struct mem_cgroup *memcg,
 {
 	struct list_lru_node *nlru = &lru->node[nid];
 	struct list_lru_one *l = NULL;
-	struct list_head *item, *n;
+	struct list_head *item;
 	unsigned long isolated = 0;
 
 restart:
@@ -348,7 +348,7 @@ __list_lru_walk_one(struct list_lru *lru, int nid, struct mem_cgroup *memcg,
 				   /*irq_flags=*/NULL, /*skip_empty=*/true);
 	if (!l)
 		return isolated;
-	list_for_each_safe(item, n, &l->list) {
+	list_for_each_mutable(item, &l->list) {
 		enum lru_status ret;
 
 		/*
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index 765069211567..2e32f84a109a 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -986,11 +986,11 @@ static int mem_cgroup_oom_register_event(struct mem_cgroup *memcg,
 static void mem_cgroup_oom_unregister_event(struct mem_cgroup *memcg,
 	struct eventfd_ctx *eventfd)
 {
-	struct mem_cgroup_eventfd_list *ev, *tmp;
+	struct mem_cgroup_eventfd_list *ev;
 
 	spin_lock(&memcg_oom_lock);
 
-	list_for_each_entry_safe(ev, tmp, &memcg->oom_notify, list) {
+	list_for_each_entry_mutable(ev, &memcg->oom_notify, list) {
 		if (ev->eventfd == eventfd) {
 			list_del(&ev->list);
 			kfree(ev);
@@ -1242,7 +1242,7 @@ void memcg1_memcg_init(struct mem_cgroup *memcg)
 
 void memcg1_css_offline(struct mem_cgroup *memcg)
 {
-	struct mem_cgroup_event *event, *tmp;
+	struct mem_cgroup_event *event;
 
 	/*
 	 * Unregister events and notify userspace.
@@ -1250,7 +1250,7 @@ void memcg1_css_offline(struct mem_cgroup *memcg)
 	 * directory to avoid race between userspace and kernelspace.
 	 */
 	spin_lock_irq(&memcg->event_list_lock);
-	list_for_each_entry_safe(event, tmp, &memcg->event_list, list) {
+	list_for_each_entry_mutable(event, &memcg->event_list, list) {
 		list_del_init(&event->list);
 		schedule_work(&event->remove);
 	}
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 51508a55c405..e14d99adf378 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -423,9 +423,9 @@ static void add_to_kill_anon_file(struct task_struct *tsk, const struct page *p,
 static bool task_in_to_kill_list(struct list_head *to_kill,
 				 struct task_struct *tsk)
 {
-	struct to_kill *tk, *next;
+	struct to_kill *tk;
 
-	list_for_each_entry_safe(tk, next, to_kill, nd) {
+	list_for_each_entry_mutable(tk, to_kill, nd) {
 		if (tk->tsk == tsk)
 			return true;
 	}
@@ -450,9 +450,9 @@ void add_to_kill_ksm(struct task_struct *tsk, const struct page *p,
 static void kill_procs(struct list_head *to_kill, bool forcekill,
 		unsigned long pfn, int flags)
 {
-	struct to_kill *tk, *next;
+	struct to_kill *tk;
 
-	list_for_each_entry_safe(tk, next, to_kill, nd) {
+	list_for_each_entry_mutable(tk, to_kill, nd) {
 		if (forcekill) {
 			if (tk->addr == -EFAULT) {
 				pr_err("%#lx: forcibly killing %s:%d because of failure to unmap corrupted page\n",
@@ -1860,11 +1860,11 @@ bool is_raw_hwpoison_page_in_hugepage(struct page *page)
 static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)
 {
 	struct llist_node *head;
-	struct raw_hwp_page *p, *next;
+	struct raw_hwp_page *p;
 	unsigned long count = 0;
 
 	head = llist_del_all(raw_hwp_list_head(folio));
-	llist_for_each_entry_safe(p, next, head, node) {
+	llist_for_each_entry_mutable(p, head, node) {
 		if (move_flag)
 			SetPageHWPoison(p->page);
 		else
diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c
index 54851d8a195b..4e0585925ae3 100644
--- a/mm/memory-tiers.c
+++ b/mm/memory-tiers.c
@@ -690,9 +690,9 @@ EXPORT_SYMBOL_GPL(mt_find_alloc_memory_type);
 
 void mt_put_memory_types(struct list_head *memory_types)
 {
-	struct memory_dev_type *mtype, *mtn;
+	struct memory_dev_type *mtype;
 
-	list_for_each_entry_safe(mtype, mtn, memory_types, list) {
+	list_for_each_entry_mutable(mtype, memory_types, list) {
 		list_del(&mtype->list);
 		put_memory_type(mtype);
 	}
diff --git a/mm/migrate.c b/mm/migrate.c
index d9b23909d716..acc7925d1d1b 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -257,9 +257,8 @@ static int migrate_movable_ops_page(struct page *dst, struct page *src,
 void putback_movable_pages(struct list_head *l)
 {
 	struct folio *folio;
-	struct folio *folio2;
 
-	list_for_each_entry_safe(folio, folio2, l, lru) {
+	list_for_each_entry_mutable(folio, l, lru) {
 		if (unlikely(folio_test_hugetlb(folio))) {
 			folio_putback_hugetlb(folio);
 			continue;
@@ -336,7 +335,7 @@ static bool try_to_map_unused_to_zeropage(struct page_vma_mapped_walk *pvmw,
 }
 
 struct rmap_walk_arg {
-	struct folio *folio;
+	struct folio *folio, *folio2;
 	bool map_unused_to_zeropage;
 };
 
@@ -1634,14 +1633,14 @@ static int migrate_hugetlbs(struct list_head *from, new_folio_t get_new_folio,
 	int nr_failed = 0;
 	int nr_retry_pages = 0;
 	int pass = 0;
-	struct folio *folio, *folio2;
+	struct folio *folio;
 	int rc, nr_pages;
 
 	for (pass = 0; pass < NR_MAX_MIGRATE_PAGES_RETRY && retry; pass++) {
 		retry = 0;
 		nr_retry_pages = 0;
 
-		list_for_each_entry_safe(folio, folio2, from, lru) {
+		list_for_each_entry_mutable(folio, from, lru) {
 			if (!folio_test_hugetlb(folio))
 				continue;
 
@@ -1722,14 +1721,14 @@ static void migrate_folios_move(struct list_head *src_folios,
 		int *retry, int *thp_retry, int *nr_failed,
 		int *nr_retry_pages)
 {
-	struct folio *folio, *folio2, *dst, *dst2;
+	struct folio *folio, *dst, *dst2;
 	bool is_thp;
 	int nr_pages;
 	int rc;
 
 	dst = list_first_entry(dst_folios, struct folio, lru);
 	dst2 = list_next_entry(dst, lru);
-	list_for_each_entry_safe(folio, folio2, src_folios, lru) {
+	list_for_each_entry_mutable(folio, src_folios, lru) {
 		is_thp = folio_test_large(folio) && folio_test_pmd_mappable(folio);
 		nr_pages = folio_nr_pages(folio);
 
@@ -1770,11 +1769,11 @@ static void migrate_folios_undo(struct list_head *src_folios,
 		free_folio_t put_new_folio, unsigned long private,
 		struct list_head *ret_folios)
 {
-	struct folio *folio, *folio2, *dst, *dst2;
+	struct folio *folio, *dst, *dst2;
 
 	dst = list_first_entry(dst_folios, struct folio, lru);
 	dst2 = list_next_entry(dst, lru);
-	list_for_each_entry_safe(folio, folio2, src_folios, lru) {
+	list_for_each_entry_mutable(folio, src_folios, lru) {
 		int old_folio_state = 0;
 		struct anon_vma *anon_vma = NULL;
 
@@ -1810,7 +1809,7 @@ static int migrate_pages_batch(struct list_head *from,
 	int pass = 0;
 	bool is_thp = false;
 	bool is_large = false;
-	struct folio *folio, *folio2, *dst = NULL;
+	struct folio *folio, *dst = NULL;
 	int rc, rc_saved = 0, nr_pages;
 	LIST_HEAD(unmap_folios);
 	LIST_HEAD(dst_folios);
@@ -1824,7 +1823,7 @@ static int migrate_pages_batch(struct list_head *from,
 		thp_retry = 0;
 		nr_retry_pages = 0;
 
-		list_for_each_entry_safe(folio, folio2, from, lru) {
+		list_for_each_entry_mutable(folio, from, lru) {
 			is_large = folio_test_large(folio);
 			is_thp = folio_test_pmd_mappable(folio);
 			nr_pages = folio_nr_pages(folio);
@@ -2109,7 +2108,7 @@ int migrate_pages(struct list_head *from, new_folio_t get_new_folio,
 
 again:
 	nr_pages = 0;
-	list_for_each_entry_safe(folio, folio2, from, lru) {
+	list_for_each_entry_mutable(folio, folio2, from, lru) {
 		/* Retried hugetlb folios will be kept in list  */
 		if (folio_test_hugetlb(folio)) {
 			list_move_tail(&folio->lru, &ret_folios);
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index 245b74f39f91..7d4ccf9853a3 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -131,7 +131,6 @@ mn_itree_inv_next(struct mmu_interval_notifier *interval_sub,
 static void mn_itree_inv_end(struct mmu_notifier_subscriptions *subscriptions)
 {
 	struct mmu_interval_notifier *interval_sub;
-	struct hlist_node *next;
 
 	spin_lock(&subscriptions->lock);
 	if (--subscriptions->active_invalidate_ranges ||
@@ -149,9 +148,7 @@ static void mn_itree_inv_end(struct mmu_notifier_subscriptions *subscriptions)
 	 * they are progressed. This arrangement for tree updates is used to
 	 * avoid using a blocking lock during invalidate_range_start.
 	 */
-	hlist_for_each_entry_safe(interval_sub, next,
-				  &subscriptions->deferred_list,
-				  deferred_item) {
+	hlist_for_each_entry_mutable(interval_sub, &subscriptions->deferred_list, deferred_item) {
 		if (RB_EMPTY_NODE(&interval_sub->interval_tree.rb))
 			interval_tree_insert(&interval_sub->interval_tree,
 					     &subscriptions->itree);
@@ -263,9 +260,9 @@ EXPORT_SYMBOL_GPL(mmu_interval_read_begin);
 static void mn_itree_finish_pass(struct llist_head *finish_passes)
 {
 	struct llist_node *first = llist_reverse_order(__llist_del_all(finish_passes));
-	struct mmu_interval_notifier_finish *f, *next;
+	struct mmu_interval_notifier_finish *f;
 
-	llist_for_each_entry_safe(f, next, first, link)
+	llist_for_each_entry_mutable(f, first, link)
 		f->notifier->ops->invalidate_finish(f);
 }
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ee902a468c2f..6d29df3e2973 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1559,10 +1559,10 @@ static void free_one_page(struct zone *zone, struct page *page,
 	llhead = &zone->trylock_free_pages;
 	if (unlikely(!llist_empty(llhead) && !(fpi_flags & FPI_TRYLOCK))) {
 		struct llist_node *llnode;
-		struct page *p, *tmp;
+		struct page *p;
 
 		llnode = llist_del_all(llhead);
-		llist_for_each_entry_safe(p, tmp, llnode, pcp_llist) {
+		llist_for_each_entry_mutable(p, llnode, pcp_llist) {
 			unsigned int p_order = p->private;
 
 			split_large_buddy(zone, p, page_to_pfn(p), p_order, fpi_flags);
@@ -7022,10 +7022,10 @@ static void split_free_frozen_pages(struct list_head *list, gfp_t gfp_mask)
 	int order;
 
 	for (order = 0; order < NR_PAGE_ORDERS; order++) {
-		struct page *page, *next;
+		struct page *page;
 		int nr_pages = 1 << order;
 
-		list_for_each_entry_safe(page, next, &list[order], lru) {
+		list_for_each_entry_mutable(page, &list[order], lru) {
 			int i;
 
 			post_alloc_hook(page, order, gfp_mask);
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index 7418f2e500bb..849266216c9f 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -180,7 +180,7 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
 	budget = DIV_ROUND_UP(area->nr_free, PAGE_REPORTING_CAPACITY * 16);
 
 	/* loop through free list adding unreported pages to sg list */
-	list_for_each_entry_safe(page, next, list, lru) {
+	list_for_each_entry_mutable(page, next, list, lru) {
 		/* We are going to skip over the reported pages. */
 		if (PageReported(page))
 			continue;
diff --git a/mm/percpu.c b/mm/percpu.c
index b0676b8054ed..ae932e0e1ae6 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1741,7 +1741,7 @@ void __percpu *pcpu_alloc_noprof(size_t size, size_t align, bool reserved,
 	bool do_warn;
 	struct obj_cgroup *objcg = NULL;
 	static atomic_t warn_limit = ATOMIC_INIT(10);
-	struct pcpu_chunk *chunk, *next;
+	struct pcpu_chunk *chunk;
 	const char *err;
 	int slot, off, cpu, ret;
 	unsigned long flags;
@@ -1814,8 +1814,7 @@ void __percpu *pcpu_alloc_noprof(size_t size, size_t align, bool reserved,
 restart:
 	/* search through normal chunks */
 	for (slot = pcpu_size_to_slot(size); slot <= pcpu_free_slot; slot++) {
-		list_for_each_entry_safe(chunk, next, &pcpu_chunk_lists[slot],
-					 list) {
+		list_for_each_entry_mutable(chunk, &pcpu_chunk_lists[slot], list) {
 			off = pcpu_find_block_fit(chunk, bits, bit_align,
 						  is_atomic);
 			if (off < 0) {
@@ -1952,7 +1951,7 @@ static void pcpu_balance_free(bool empty_only)
 {
 	LIST_HEAD(to_free);
 	struct list_head *free_head = &pcpu_chunk_lists[pcpu_free_slot];
-	struct pcpu_chunk *chunk, *next;
+	struct pcpu_chunk *chunk;
 
 	lockdep_assert_held(&pcpu_lock);
 
@@ -1960,7 +1959,7 @@ static void pcpu_balance_free(bool empty_only)
 	 * There's no reason to keep around multiple unused chunks and VM
 	 * areas can be scarce.  Destroy all free chunks except for one.
 	 */
-	list_for_each_entry_safe(chunk, next, free_head, list) {
+	list_for_each_entry_mutable(chunk, free_head, list) {
 		WARN_ON(chunk->immutable);
 
 		/* spare the first one */
@@ -1975,7 +1974,7 @@ static void pcpu_balance_free(bool empty_only)
 		return;
 
 	spin_unlock_irq(&pcpu_lock);
-	list_for_each_entry_safe(chunk, next, &to_free, list) {
+	list_for_each_entry_mutable(chunk, &to_free, list) {
 		unsigned int rs, re;
 
 		for_each_set_bitrange(rs, re, chunk->populated, chunk->nr_pages) {
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index b91b1a98029c..723b4bdb447d 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -426,7 +426,7 @@ static struct {
 
 static void kernel_pgtable_work_func(struct work_struct *work)
 {
-	struct ptdesc *pt, *next;
+	struct ptdesc *pt;
 	LIST_HEAD(page_list);
 
 	spin_lock(&kernel_pgtable_work.lock);
@@ -434,7 +434,7 @@ static void kernel_pgtable_work_func(struct work_struct *work)
 	spin_unlock(&kernel_pgtable_work.lock);
 
 	iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL);
-	list_for_each_entry_safe(pt, next, &page_list, pt_list)
+	list_for_each_entry_mutable(pt, &page_list, pt_list)
 		__pagetable_free(pt);
 }
 
diff --git a/mm/rmap.c b/mm/rmap.c
index 1c77d5dc06e9..37164f446d2d 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -451,9 +451,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
  */
 static void cleanup_partial_anon_vmas(struct vm_area_struct *vma)
 {
-	struct anon_vma_chain *avc, *next;
+	struct anon_vma_chain *avc;
 
-	list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
+	list_for_each_entry_mutable(avc, &vma->anon_vma_chain, same_vma) {
 		list_del(&avc->same_vma);
 		anon_vma_chain_free(avc);
 	}
@@ -478,7 +478,7 @@ static void cleanup_partial_anon_vmas(struct vm_area_struct *vma)
  */
 void unlink_anon_vmas(struct vm_area_struct *vma)
 {
-	struct anon_vma_chain *avc, *next;
+	struct anon_vma_chain *avc;
 	struct anon_vma *active_anon_vma = vma->anon_vma;
 
 	/* Always hold mmap lock, read-lock on unmap possibly. */
@@ -496,7 +496,7 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
 	 * Unlink each anon_vma chained to the VMA.  This list is ordered
 	 * from newest to oldest, ensuring the root anon_vma gets freed last.
 	 */
-	list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
+	list_for_each_entry_mutable(avc, &vma->anon_vma_chain, same_vma) {
 		struct anon_vma *anon_vma = avc->anon_vma;
 
 		anon_vma_interval_tree_remove(avc, &anon_vma->rb_root);
@@ -528,7 +528,7 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
 	 * anon_vmas, destroy them. Could not do before due to __put_anon_vma()
 	 * needing to write-acquire the anon_vma->root->rwsem.
 	 */
-	list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
+	list_for_each_entry_mutable(avc, &vma->anon_vma_chain, same_vma) {
 		struct anon_vma *anon_vma = avc->anon_vma;
 
 		VM_WARN_ON(anon_vma->num_children);
diff --git a/mm/shmem.c b/mm/shmem.c
index b51f83c970bb..9f03e46bfde2 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -727,7 +727,8 @@ static const char *shmem_format_huge(int huge)
 static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
 		struct shrink_control *sc, unsigned long nr_to_free)
 {
-	LIST_HEAD(list), *pos, *next;
+	LIST_HEAD(list);
+	struct list_head *pos;
 	struct inode *inode;
 	struct shmem_inode_info *info;
 	struct folio *folio;
@@ -738,7 +739,7 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
 		return SHRINK_STOP;
 
 	spin_lock(&sbinfo->shrinklist_lock);
-	list_for_each_safe(pos, next, &sbinfo->shrinklist) {
+	list_for_each_mutable(pos, &sbinfo->shrinklist) {
 		info = list_entry(pos, struct shmem_inode_info, shrinklist);
 
 		/* pin the inode */
@@ -758,7 +759,7 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
 	}
 	spin_unlock(&sbinfo->shrinklist_lock);
 
-	list_for_each_safe(pos, next, &list) {
+	list_for_each_mutable(pos, &list) {
 		pgoff_t next, end;
 		loff_t i_size;
 		int ret;
@@ -1547,7 +1548,7 @@ int shmem_unuse(unsigned int type)
 
 	spin_lock(&shmem_swaplist_lock);
 start_over:
-	list_for_each_entry_safe(info, next, &shmem_swaplist, swaplist) {
+	list_for_each_entry_mutable(info, next, &shmem_swaplist, swaplist) {
 		if (!info->swapped) {
 			list_del_init(&info->swaplist);
 			continue;
diff --git a/mm/slab_common.c b/mm/slab_common.c
index b6426d7ceec9..489e8e0800b6 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -1465,7 +1465,7 @@ static int
 drain_page_cache(struct kfree_rcu_cpu *krcp)
 {
 	unsigned long flags;
-	struct llist_node *page_list, *pos, *n;
+	struct llist_node *page_list, *pos;
 	int freed = 0;
 
 	if (!rcu_min_cached_objs)
@@ -1476,7 +1476,7 @@ drain_page_cache(struct kfree_rcu_cpu *krcp)
 	WRITE_ONCE(krcp->nr_bkv_objs, 0);
 	raw_spin_unlock_irqrestore(&krcp->lock, flags);
 
-	llist_for_each_safe(pos, n, page_list) {
+	llist_for_each_mutable(pos, page_list) {
 		free_page((unsigned long)pos);
 		freed++;
 	}
@@ -1550,7 +1550,7 @@ kvfree_rcu_list(struct rcu_head *head)
 static void kfree_rcu_work(struct work_struct *work)
 {
 	unsigned long flags;
-	struct kvfree_rcu_bulk_data *bnode, *n;
+	struct kvfree_rcu_bulk_data *bnode;
 	struct list_head bulk_head[FREE_N_CHANNELS];
 	struct rcu_head *head;
 	struct kfree_rcu_cpu *krcp;
@@ -1576,7 +1576,7 @@ static void kfree_rcu_work(struct work_struct *work)
 	// Handle the first two channels.
 	for (i = 0; i < FREE_N_CHANNELS; i++) {
 		// Start from the tail page, so a GP is likely passed for it.
-		list_for_each_entry_safe(bnode, n, &bulk_head[i], list)
+		list_for_each_entry_mutable(bnode, &bulk_head[i], list)
 			kvfree_rcu_bulk(krcp, bnode, i);
 	}
 
@@ -1674,7 +1674,7 @@ static void
 kvfree_rcu_drain_ready(struct kfree_rcu_cpu *krcp)
 {
 	struct list_head bulk_ready[FREE_N_CHANNELS];
-	struct kvfree_rcu_bulk_data *bnode, *n;
+	struct kvfree_rcu_bulk_data *bnode;
 	struct rcu_head *head_ready = NULL;
 	unsigned long flags;
 	int i;
@@ -1683,7 +1683,7 @@ kvfree_rcu_drain_ready(struct kfree_rcu_cpu *krcp)
 	for (i = 0; i < FREE_N_CHANNELS; i++) {
 		INIT_LIST_HEAD(&bulk_ready[i]);
 
-		list_for_each_entry_safe_reverse(bnode, n, &krcp->bulk_head[i], list) {
+		list_for_each_entry_mutable_reverse(bnode, &krcp->bulk_head[i], list) {
 			if (!poll_state_synchronize_rcu_full(&bnode->gp_snap))
 				break;
 
@@ -1700,7 +1700,7 @@ kvfree_rcu_drain_ready(struct kfree_rcu_cpu *krcp)
 	raw_spin_unlock_irqrestore(&krcp->lock, flags);
 
 	for (i = 0; i < FREE_N_CHANNELS; i++) {
-		list_for_each_entry_safe(bnode, n, &bulk_ready[i], list)
+		list_for_each_entry_mutable(bnode, &bulk_ready[i], list)
 			kvfree_rcu_bulk(krcp, bnode, i);
 	}
 
diff --git a/mm/slub.c b/mm/slub.c
index 9ec774dc7009..6f4a79e32d75 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3253,7 +3253,7 @@ static void barn_shrink(struct kmem_cache *s, struct node_barn *barn)
 {
 	LIST_HEAD(empty_list);
 	LIST_HEAD(full_list);
-	struct slab_sheaf *sheaf, *sheaf2;
+	struct slab_sheaf *sheaf;
 	unsigned long flags;
 
 	spin_lock_irqsave(&barn->lock, flags);
@@ -3265,12 +3265,12 @@ static void barn_shrink(struct kmem_cache *s, struct node_barn *barn)
 
 	spin_unlock_irqrestore(&barn->lock, flags);
 
-	list_for_each_entry_safe(sheaf, sheaf2, &full_list, barn_list) {
+	list_for_each_entry_mutable(sheaf, &full_list, barn_list) {
 		sheaf_flush_unused(s, sheaf);
 		free_empty_sheaf(s, sheaf);
 	}
 
-	list_for_each_entry_safe(sheaf, sheaf2, &empty_list, barn_list)
+	list_for_each_entry_mutable(sheaf, &empty_list, barn_list)
 		free_empty_sheaf(s, sheaf);
 }
 
@@ -3757,7 +3757,7 @@ static bool get_partial_node_bulk(struct kmem_cache *s,
 				  struct partial_bulk_context *pc,
 				  bool allow_spin)
 {
-	struct slab *slab, *slab2;
+	struct slab *slab;
 	struct slab *first = NULL, *last = NULL;
 	unsigned int total_free = 0;
 	unsigned long flags;
@@ -3773,7 +3773,7 @@ static bool get_partial_node_bulk(struct kmem_cache *s,
 	else if (!spin_trylock_irqsave(&n->list_lock, flags))
 		return false;
 
-	list_for_each_entry_safe(slab, slab2, &n->partial, slab_list) {
+	list_for_each_entry_mutable(slab, &n->partial, slab_list) {
 		struct freelist_counters flc;
 		unsigned int slab_free;
 
@@ -3828,7 +3828,7 @@ static void *get_from_partial_node(struct kmem_cache *s,
 				   gfp_t gfp_flags,
 				   const struct slab_alloc_context *ac)
 {
-	struct slab *slab, *slab2;
+	struct slab *slab;
 	unsigned long flags;
 	void *object = NULL;
 
@@ -3845,7 +3845,7 @@ static void *get_from_partial_node(struct kmem_cache *s,
 		spin_lock_irqsave(&n->list_lock, flags);
 	else if (!spin_trylock_irqsave(&n->list_lock, flags))
 		return NULL;
-	list_for_each_entry_safe(slab, slab2, &n->partial, slab_list) {
+	list_for_each_entry_mutable(slab, &n->partial, slab_list) {
 
 		struct freelist_counters old, new;
 
@@ -6345,13 +6345,13 @@ static void free_deferred_objects(struct irq_work *work)
 {
 	struct defer_free *df = container_of(work, struct defer_free, work);
 	struct llist_head *objs = &df->objects;
-	struct llist_node *llnode, *pos, *t;
+	struct llist_node *llnode, *pos;
 
 	if (llist_empty(objs))
 		return;
 
 	llnode = llist_del_all(objs);
-	llist_for_each_safe(pos, t, llnode) {
+	llist_for_each_mutable(pos, llnode) {
 		struct kmem_cache *s;
 		struct slab *slab;
 		void *x = pos;
@@ -7185,7 +7185,7 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi
 		      bool allow_spin)
 {
 	struct partial_bulk_context pc;
-	struct slab *slab, *slab2;
+	struct slab *slab;
 	unsigned int refilled = 0;
 	unsigned long flags;
 	void *object;
@@ -7197,7 +7197,7 @@ __refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int mi
 	if (!get_partial_node_bulk(s, n, &pc, allow_spin))
 		return 0;
 
-	list_for_each_entry_safe(slab, slab2, &pc.slabs, slab_list) {
+	list_for_each_entry_mutable(slab, &pc.slabs, slab_list) {
 
 		unsigned int count;
 
@@ -8031,11 +8031,11 @@ static void list_slab_objects(struct kmem_cache *s, struct slab *slab)
 static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 {
 	LIST_HEAD(discard);
-	struct slab *slab, *h;
+	struct slab *slab;
 
 	BUG_ON(irqs_disabled());
 	spin_lock_irq(&n->list_lock);
-	list_for_each_entry_safe(slab, h, &n->partial, slab_list) {
+	list_for_each_entry_mutable(slab, &n->partial, slab_list) {
 		if (!slab->inuse) {
 			remove_partial(n, slab);
 			list_add(&slab->slab_list, &discard);
@@ -8045,7 +8045,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 	}
 	spin_unlock_irq(&n->list_lock);
 
-	list_for_each_entry_safe(slab, h, &discard, slab_list)
+	list_for_each_entry_mutable(slab, &discard, slab_list)
 		discard_slab(s, slab);
 }
 
@@ -8286,7 +8286,6 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
 	int i;
 	struct kmem_cache_node *n;
 	struct slab *slab;
-	struct slab *t;
 	struct list_head discard;
 	struct list_head promote[SHRINK_PROMOTE_MAX];
 	unsigned long flags;
@@ -8312,7 +8311,7 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
 		 * Note that concurrent frees may occur while we hold the
 		 * list_lock. slab->inuse here is the upper limit.
 		 */
-		list_for_each_entry_safe(slab, t, &n->partial, slab_list) {
+		list_for_each_entry_mutable(slab, &n->partial, slab_list) {
 			int free = slab->objects - slab->inuse;
 
 			/* Do not reread slab->inuse */
@@ -8339,7 +8338,7 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
 		spin_unlock_irqrestore(&n->list_lock, flags);
 
 		/* Release empty slabs */
-		list_for_each_entry_safe(slab, t, &discard, slab_list)
+		list_for_each_entry_mutable(slab, &discard, slab_list)
 			free_slab(s, slab);
 
 		if (node_nr_slabs(n))
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 78b49b0658ad..e050b3894d6f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2825,14 +2825,14 @@ static int try_to_unuse(unsigned int type)
  */
 static void drain_mmlist(void)
 {
-	struct list_head *p, *next;
+	struct list_head *p;
 	unsigned int type;
 
 	for (type = 0; type < nr_swapfiles; type++)
 		if (swap_usage_in_pages(swap_info[type]))
 			return;
 	spin_lock(&mmlist_lock);
-	list_for_each_safe(p, next, &init_mm.mmlist)
+	list_for_each_mutable(p, &init_mm.mmlist)
 		list_del_init(p);
 	spin_unlock(&mmlist_lock);
 }
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index b8d2d87ce8d7..78ef5f7e3f67 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -3010,9 +3010,9 @@ static void dup_fctx(struct userfaultfd_fork_ctx *fctx)
 
 void dup_userfaultfd_complete(struct list_head *fcs)
 {
-	struct userfaultfd_fork_ctx *fctx, *n;
+	struct userfaultfd_fork_ctx *fctx;
 
-	list_for_each_entry_safe(fctx, n, fcs, list) {
+	list_for_each_entry_mutable(fctx, fcs, list) {
 		dup_fctx(fctx);
 		list_del(&fctx->list);
 		kfree(fctx);
@@ -3021,7 +3021,7 @@ void dup_userfaultfd_complete(struct list_head *fcs)
 
 void dup_userfaultfd_fail(struct list_head *fcs)
 {
-	struct userfaultfd_fork_ctx *fctx, *n;
+	struct userfaultfd_fork_ctx *fctx;
 
 	/*
 	 * An error has occurred on fork, we will tear memory down, but have
@@ -3033,7 +3033,7 @@ void dup_userfaultfd_fail(struct list_head *fcs)
 	 *
 	 * mm tear down will take care of cleaning up VMA contexts.
 	 */
-	list_for_each_entry_safe(fctx, n, fcs, list) {
+	list_for_each_entry_mutable(fctx, fcs, list) {
 		struct userfaultfd_ctx *octx = fctx->orig;
 		struct userfaultfd_ctx *ctx = fctx->new;
 
@@ -3170,10 +3170,10 @@ int userfaultfd_unmap_prep(struct vm_area_struct *vma, unsigned long start,
 
 void userfaultfd_unmap_complete(struct mm_struct *mm, struct list_head *uf)
 {
-	struct userfaultfd_unmap_ctx *ctx, *n;
+	struct userfaultfd_unmap_ctx *ctx;
 	struct userfaultfd_wait_queue ewq;
 
-	list_for_each_entry_safe(ctx, n, uf, list) {
+	list_for_each_entry_mutable(ctx, uf, list) {
 		msg_init(&ewq.msg);
 
 		ewq.msg.event = UFFD_EVENT_UNMAP;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 1afca3568b9b..2b510e7651df 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2202,13 +2202,13 @@ static void purge_fragmented_blocks_allcpus(void);
 static void
 reclaim_list_global(struct list_head *head)
 {
-	struct vmap_area *va, *n;
+	struct vmap_area *va;
 
 	if (list_empty(head))
 		return;
 
 	spin_lock(&free_vmap_area_lock);
-	list_for_each_entry_safe(va, n, head, list)
+	list_for_each_entry_mutable(va, head, list)
 		merge_or_add_vmap_area_augment(va,
 			&free_vmap_area_root, &free_vmap_area_list);
 	spin_unlock(&free_vmap_area_lock);
@@ -2219,7 +2219,7 @@ decay_va_pool_node(struct vmap_node *vn, bool full_decay)
 {
 	LIST_HEAD(decay_list);
 	struct rb_root decay_root = RB_ROOT;
-	struct vmap_area *va, *nva;
+	struct vmap_area *va;
 	unsigned long n_decay, pool_len;
 	int i;
 
@@ -2242,7 +2242,7 @@ decay_va_pool_node(struct vmap_node *vn, bool full_decay)
 			n_decay >>= 2;
 		pool_len -= n_decay;
 
-		list_for_each_entry_safe(va, nva, &tmp_list, list) {
+		list_for_each_entry_mutable(va, &tmp_list, list) {
 			if (!n_decay--)
 				break;
 
@@ -2299,7 +2299,7 @@ static void purge_vmap_node(struct work_struct *work)
 	struct vmap_node *vn = container_of(work,
 		struct vmap_node, purge_work);
 	unsigned long nr_purged_pages = 0;
-	struct vmap_area *va, *n_va;
+	struct vmap_area *va;
 	LIST_HEAD(local_list);
 
 	if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
@@ -2307,7 +2307,7 @@ static void purge_vmap_node(struct work_struct *work)
 
 	vn->nr_purged = 0;
 
-	list_for_each_entry_safe(va, n_va, &vn->purge_list, list) {
+	list_for_each_entry_mutable(va, &vn->purge_list, list) {
 		unsigned long nr = va_size(va) >> PAGE_SHIFT;
 		unsigned int vn_id = decode_vn_id(va->flags);
 
@@ -2803,9 +2803,9 @@ static bool purge_fragmented_block(struct vmap_block *vb,
 
 static void free_purged_blocks(struct list_head *purge_list)
 {
-	struct vmap_block *vb, *n_vb;
+	struct vmap_block *vb;
 
-	list_for_each_entry_safe(vb, n_vb, purge_list, purge) {
+	list_for_each_entry_mutable(vb, purge_list, purge) {
 		list_del(&vb->purge);
 		free_vmap_block(vb);
 	}
@@ -3386,9 +3386,9 @@ static void vm_reset_perms(struct vm_struct *area)
 static void delayed_vfree_work(struct work_struct *w)
 {
 	struct vfree_deferred *p = container_of(w, struct vfree_deferred, wq);
-	struct llist_node *t, *llnode;
+	struct llist_node *llnode;
 
-	llist_for_each_safe(llnode, t, llist_del_all(&p->list))
+	llist_for_each_mutable(llnode, llist_del_all(&p->list))
 		vfree(llnode);
 }
 
@@ -3775,14 +3775,14 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
 static LLIST_HEAD(pending_vm_area_cleanup);
 static void cleanup_vm_area_work(struct work_struct *work)
 {
-	struct vm_struct *area, *tmp;
+	struct vm_struct *area;
 	struct llist_node *head;
 
 	head = llist_del_all(&pending_vm_area_cleanup);
 	if (!head)
 		return;
 
-	llist_for_each_entry_safe(area, tmp, head, llnode) {
+	llist_for_each_entry_mutable(area, head, llnode) {
 		if (!area->pages)
 			free_vm_area(area);
 		else
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 35c3bb15ae96..d7c4ded7a8fe 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1598,11 +1598,11 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,
 	};
 	struct reclaim_stat stat;
 	unsigned int nr_reclaimed;
-	struct folio *folio, *next;
+	struct folio *folio;
 	LIST_HEAD(clean_folios);
 	unsigned int noreclaim_flag;
 
-	list_for_each_entry_safe(folio, next, folio_list, lru) {
+	list_for_each_entry_mutable(folio, folio_list, lru) {
 		/* TODO: these pages should not even appear in this list. */
 		if (page_has_movable_ops(&folio->page))
 			continue;
@@ -4805,7 +4805,6 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
 	LIST_HEAD(list);
 	LIST_HEAD(clean);
 	struct folio *folio;
-	struct folio *next;
 	enum node_stat_item item;
 	struct reclaim_stat stat;
 	struct lru_gen_mm_walk *walk;
@@ -4841,7 +4840,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
 			type_scanned, reclaimed, &stat, sc->priority,
 			type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON);
 
-	list_for_each_entry_safe_reverse(folio, next, &list, lru) {
+	list_for_each_entry_mutable_reverse(folio, &list, lru) {
 		DEFINE_MIN_SEQ(lruvec);
 
 		if (!folio_evictable(folio)) {
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index 83f5820c45f9..2ac86c758e0b 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -1806,7 +1806,7 @@ static void async_free_zspage(struct work_struct *work)
 {
 	int i;
 	struct size_class *class;
-	struct zspage *zspage, *tmp;
+	struct zspage *zspage;
 	LIST_HEAD(free_pages);
 	struct zs_pool *pool = container_of(work, struct zs_pool,
 					free_work);
@@ -1822,7 +1822,7 @@ static void async_free_zspage(struct work_struct *work)
 		spin_unlock(&class->lock);
 	}
 
-	list_for_each_entry_safe(zspage, tmp, &free_pages, list) {
+	list_for_each_entry_mutable(zspage, &free_pages, list) {
 		list_del(&zspage->list);
 		lock_zspage(zspage);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 5/7] kernel: Use mutable list iterators
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (2 preceding siblings ...)
  2026-06-22  4:15 ` [PATCH v3 3/7] mm: Use mutable list iterators Kaitao Cheng
@ 2026-06-22  4:28 ` Kaitao Cheng
  2026-06-22  5:22     ` bot+bpf-ci
  2026-06-22 19:03   ` Eduard Zingerman
  2026-06-22  4:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator Kaitao Cheng
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:28 UTC (permalink / raw)
  To: Paul Moore, Eric Paris, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	David S. Miller, Jakub Kicinski, Jesper Dangaard Brouer,
	John Fastabend, Tejun Heo, Johannes Weiner, Michal Koutný,
	Maarten Lankhorst, Maxime Ripard, Natalie Vock, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Masami Hiramatsu, Oleg Nesterov, Peter Oberparleiter,
	Andrew Morton, Baoquan He, Mike Rapoport, Pasha Tatashin,
	Pratyush Yadav, Naveen N Rao, Josh Poimboeuf, Jiri Kosina,
	Miroslav Benes, Petr Mladek, Will Deacon, Boqun Feng,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Steffen Klassert, Daniel Jordan, Rafael J. Wysocki,
	Davidlohr Bueso, Paul E. McKenney, Josh Triplett,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Uladzislau Rezki, Juri Lelli, Vincent Guittot, Kees Cook,
	Balbir Singh, Anna-Maria Behnsen, Thomas Gleixner, John Stultz,
	KP Singh, Matt Bobrowski, Nathan Chancellor, Martin KaFai Lau,
	Song Liu, Mark Rutland, Mathieu Desnoyers, Dietmar Eggemann,
	David Vernet, Steven Rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iteration helpers require callers to provide a temporary
cursor even when the cursor is only used internally by the loop. This
leaves many functions with otherwise unused variables whose only purpose
is to satisfy the old iterator interface.

Use the mutable list iteration helpers for those cases. The mutable
helpers keep the same removal-safe traversal semantics, while allowing
the temporary cursor to be internal to the macro when the caller does
not need to observe it.

Convert list, hlist and llist users under kernel/ where the temporary
cursor is not used outside the iteration. Keep the explicit cursor form
where the next entry is still needed by the surrounding code.

No functional change intended.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 kernel/audit_tree.c                 |  4 +--
 kernel/audit_watch.c                | 16 ++++-----
 kernel/auditfilter.c                |  4 +--
 kernel/auditsc.c                    |  4 +--
 kernel/bpf/arena.c                  | 10 +++---
 kernel/bpf/arraymap.c               |  8 ++---
 kernel/bpf/bpf_local_storage.c      |  3 +-
 kernel/bpf/bpf_lru_list.c           | 25 ++++++-------
 kernel/bpf/btf.c                    | 18 +++++-----
 kernel/bpf/cgroup.c                 |  7 ++--
 kernel/bpf/cpumap.c                 |  4 +--
 kernel/bpf/devmap.c                 | 10 +++---
 kernel/bpf/helpers.c                |  8 ++---
 kernel/bpf/local_storage.c          |  4 +--
 kernel/bpf/memalloc.c               | 16 ++++-----
 kernel/bpf/offload.c                |  8 ++---
 kernel/bpf/states.c                 |  4 +--
 kernel/bpf/stream.c                 |  4 +--
 kernel/bpf/verifier.c               |  6 ++--
 kernel/cgroup/cgroup-v1.c           |  4 +--
 kernel/cgroup/cgroup.c              | 54 ++++++++++++++---------------
 kernel/cgroup/dmem.c                | 12 +++----
 kernel/cgroup/rdma.c                |  8 ++---
 kernel/events/core.c                | 44 +++++++++++------------
 kernel/events/uprobes.c             | 12 +++----
 kernel/exit.c                       |  8 ++---
 kernel/fail_function.c              |  4 +--
 kernel/gcov/clang.c                 |  4 +--
 kernel/irq_work.c                   |  4 +--
 kernel/kexec_core.c                 |  4 +--
 kernel/kprobes.c                    | 16 ++++-----
 kernel/livepatch/core.c             |  4 +--
 kernel/livepatch/core.h             |  4 +--
 kernel/liveupdate/kho_block.c       |  4 +--
 kernel/liveupdate/luo_flb.c         |  4 +--
 kernel/locking/rwsem.c              |  2 +-
 kernel/locking/test-ww_mutex.c      |  2 +-
 kernel/module/main.c                | 11 +++---
 kernel/padata.c                     |  4 +--
 kernel/power/snapshot.c             |  8 ++---
 kernel/power/wakelock.c             |  4 +--
 kernel/printk/printk.c              | 11 +++---
 kernel/ptrace.c                     |  4 +--
 kernel/rcu/rcutorture.c             |  3 +-
 kernel/rcu/tasks.h                  |  9 +++--
 kernel/rcu/tree.c                   |  6 ++--
 kernel/resource.c                   |  4 +--
 kernel/sched/core.c                 |  4 +--
 kernel/sched/ext.c                  | 22 ++++++------
 kernel/sched/fair.c                 | 28 +++++++--------
 kernel/sched/topology.c             |  4 +--
 kernel/sched/wait.c                 |  4 +--
 kernel/seccomp.c                    |  4 +--
 kernel/signal.c                     | 11 +++---
 kernel/smp.c                        |  4 +--
 kernel/taskstats.c                  |  8 ++---
 kernel/time/clockevents.c           |  6 ++--
 kernel/time/clocksource.c           |  4 +--
 kernel/time/posix-cpu-timers.c      |  4 +--
 kernel/time/posix-timers.c          |  3 +-
 kernel/torture.c                    |  3 +-
 kernel/trace/bpf_trace.c            |  4 +--
 kernel/trace/ftrace.c               | 49 +++++++++++---------------
 kernel/trace/ring_buffer.c          | 25 +++++++------
 kernel/trace/trace.c                | 12 +++----
 kernel/trace/trace_dynevent.c       |  6 ++--
 kernel/trace/trace_dynevent.h       |  5 ++-
 kernel/trace/trace_events.c         | 35 +++++++++----------
 kernel/trace/trace_events_filter.c  |  4 +--
 kernel/trace/trace_events_hist.c    |  8 ++---
 kernel/trace/trace_events_trigger.c | 17 ++++-----
 kernel/trace/trace_events_user.c    | 16 ++++-----
 kernel/trace/trace_stat.c           |  4 +--
 kernel/user-return-notifier.c       |  3 +-
 kernel/workqueue.c                  | 16 ++++-----
 75 files changed, 353 insertions(+), 381 deletions(-)

diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 1ed19b775912..9652b0595ad4 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -543,10 +543,10 @@ static void audit_tree_log_remove_rule(struct audit_context *context,
 
 static void kill_rules(struct audit_context *context, struct audit_tree *tree)
 {
-	struct audit_krule *rule, *next;
+	struct audit_krule *rule;
 	struct audit_entry *entry;
 
-	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
+	list_for_each_entry_mutable(rule, &tree->rules, rlist) {
 		entry = container_of(rule, struct audit_entry, rule);
 
 		list_del_init(&rule->rlist);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 06dd0ebe73e2..f56812c8186f 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -247,14 +247,14 @@ static void audit_update_watch(struct audit_parent *parent,
 			       u64 ino, unsigned int invalidating,
 			       struct audit_watch_ctx *ctx)
 {
-	struct audit_watch *owatch, *nwatch, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *owatch, *nwatch;
+	struct audit_krule *r;
 	struct audit_entry *oentry, *nentry;
 
 	mutex_lock(&audit_filter_mutex);
 	/* Run all of the watches on this parent looking for the one that
 	 * matches the given dname */
-	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+	list_for_each_entry_mutable(owatch, &parent->watches, wlist) {
 		if (audit_compare_dname_path(dname, owatch->path,
 					     AUDIT_NAME_FULL))
 			continue;
@@ -275,7 +275,7 @@ static void audit_update_watch(struct audit_parent *parent,
 		nwatch->dev = dev;
 		nwatch->ino = ino;
 
-		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+		list_for_each_entry_mutable(r, &owatch->rules, rlist) {
 
 			oentry = container_of(r, struct audit_entry, rule);
 			list_del(&oentry->rule.rlist);
@@ -322,13 +322,13 @@ static void audit_update_watch(struct audit_parent *parent,
 /* Remove all watches & rules associated with a parent that is going away. */
 static void audit_remove_parent_watches(struct audit_parent *parent)
 {
-	struct audit_watch *w, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *w;
+	struct audit_krule *r;
 	struct audit_entry *e;
 
 	mutex_lock(&audit_filter_mutex);
-	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
-		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+	list_for_each_entry_mutable(w, &parent->watches, wlist) {
+		list_for_each_entry_mutable(r, &w->rules, rlist) {
 			e = container_of(r, struct audit_entry, rule);
 			audit_watch_log_rule_change(r, w, "remove_rule");
 			if (e->rule.exe)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4401119b5275..6a4936870903 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1445,14 +1445,14 @@ static int update_lsm_rule(struct audit_krule *r)
  * updated rule. */
 int audit_update_lsm_rules(void)
 {
-	struct audit_krule *r, *n;
+	struct audit_krule *r;
 	int i, err = 0;
 
 	/* audit_filter_mutex synchronizes the writers */
 	mutex_lock(&audit_filter_mutex);
 
 	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
-		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
+		list_for_each_entry_mutable(r, &audit_rules_list[i], list) {
 			int res = update_lsm_rule(r);
 			if (!err)
 				err = res;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6610e667c728..df9c6c9e9e49 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -929,9 +929,9 @@ static inline void audit_free_module(struct audit_context *context)
 }
 static inline void audit_free_names(struct audit_context *context)
 {
-	struct audit_names *n, *next;
+	struct audit_names *n;
 
-	list_for_each_entry_safe(n, next, &context->names_list, list) {
+	list_for_each_entry_mutable(n, &context->names_list, list) {
 		list_del(&n->list);
 		if (n->name)
 			putname(n->name);
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 80b7b8a69446..597c3cd428eb 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -842,7 +842,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 	long kaddr, pgoff;
 	struct page *page;
 	struct llist_head free_pages;
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	struct arena_free_span *s;
 	struct clear_range_data cdata;
 	unsigned long flags;
@@ -889,7 +889,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 		/* bulk zap if multiple pages being freed */
 		zap_pages(arena, full_uaddr, page_cnt);
 
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		if (page_cnt == 1 && page_ref_count(page) > 1) /* maybe mapped by user space */
 			/* Optimization for the common case of page_cnt==1:
@@ -963,7 +963,7 @@ static void arena_free_worker(struct work_struct *work)
 {
 	struct bpf_arena *arena = container_of(work, struct bpf_arena, free_work);
 	struct mem_cgroup *new_memcg, *old_memcg;
-	struct llist_node *list, *pos, *t;
+	struct llist_node *list, *pos;
 	struct arena_free_span *s;
 	u64 arena_vm_start, user_vm_start;
 	struct llist_head free_pages;
@@ -1002,7 +1002,7 @@ static void arena_free_worker(struct work_struct *work)
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
 
 	/* Iterate the list again without holding spinlock to do the tlb flush and zap_pages */
-	llist_for_each_safe(pos, t, list) {
+	llist_for_each_mutable(pos, list) {
 		s = llist_entry(pos, struct arena_free_span, node);
 		page_cnt = s->page_cnt;
 		full_uaddr = clear_lo32(user_vm_start) + s->uaddr;
@@ -1018,7 +1018,7 @@ static void arena_free_worker(struct work_struct *work)
 	}
 
 	/* free all pages collected by apply_to_existing_page_range() in the first loop */
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		__free_page(page);
 	}
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 248b4818178c..1150179a90f7 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1083,12 +1083,12 @@ static int prog_array_map_poke_track(struct bpf_map *map,
 static void prog_array_map_poke_untrack(struct bpf_map *map,
 					struct bpf_prog_aux *prog_aux)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
 	mutex_lock(&aux->poke_mutex);
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		if (elem->aux == prog_aux) {
 			list_del_init(&elem->list);
 			kfree(elem);
@@ -1196,11 +1196,11 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
 
 static void prog_array_map_free(struct bpf_map *map)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		list_del_init(&elem->list);
 		kfree(elem);
 	}
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 6fc6a4b672b5..5f01ba032b12 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -161,14 +161,13 @@ void bpf_selem_free(struct bpf_local_storage_elem *selem,
 static void bpf_selem_free_list(struct hlist_head *list, bool reuse_now)
 {
 	struct bpf_local_storage_elem *selem;
-	struct hlist_node *n;
 
 	/* The "_safe" iteration is needed.
 	 * The loop is not removing the selem from the list
 	 * but bpf_selem_free will use the selem->rcu_head
 	 * which is union-ized with the selem->free_node.
 	 */
-	hlist_for_each_entry_safe(selem, n, list, free_node)
+	hlist_for_each_entry_mutable(selem, list, free_node)
 		bpf_selem_free(selem, reuse_now);
 }
 
diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c
index 5ed7cb4b98c0..4b7306ade684 100644
--- a/kernel/bpf/bpf_lru_list.c
+++ b/kernel/bpf/bpf_lru_list.c
@@ -126,11 +126,11 @@ static void __bpf_lru_list_rotate_active(struct bpf_lru *lru,
 					 struct bpf_lru_list *l)
 {
 	struct list_head *active = &l->lists[BPF_LRU_LIST_T_ACTIVE];
-	struct bpf_lru_node *node, *tmp_node, *first_node;
+	struct bpf_lru_node *node, *first_node;
 	unsigned int i = 0;
 
 	first_node = list_first_entry(active, struct bpf_lru_node, list);
-	list_for_each_entry_safe_reverse(node, tmp_node, active, list) {
+	list_for_each_entry_mutable_reverse(node, active, list) {
 		if (bpf_lru_node_is_ref(node))
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
 		else
@@ -196,11 +196,11 @@ __bpf_lru_list_shrink_inactive(struct bpf_lru *lru,
 			       enum bpf_lru_list_type tgt_free_type)
 {
 	struct list_head *inactive = &l->lists[BPF_LRU_LIST_T_INACTIVE];
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nshrinked = 0;
 	unsigned int i = 0;
 
-	list_for_each_entry_safe_reverse(node, tmp_node, inactive, list) {
+	list_for_each_entry_mutable_reverse(node, inactive, list) {
 		if (bpf_lru_node_is_ref(node) &&
 		    !READ_ONCE(node->pending_free)) {
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
@@ -247,7 +247,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 					  enum bpf_lru_list_type tgt_free_type)
 
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	struct list_head *force_shrink_list;
 	unsigned int nshrinked;
 
@@ -262,8 +262,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 	else
 		force_shrink_list = &l->lists[BPF_LRU_LIST_T_ACTIVE];
 
-	list_for_each_entry_safe_reverse(node, tmp_node, force_shrink_list,
-					 list) {
+	list_for_each_entry_mutable_reverse(node, force_shrink_list, list) {
 		if (READ_ONCE(node->pending_free) ||
 		    lru->del_from_htab(lru->del_arg, node)) {
 			__bpf_lru_node_move_to_free(l, node, free_list,
@@ -279,10 +278,9 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 static void __local_list_flush(struct bpf_lru_list *l,
 			       struct bpf_lru_locallist *loc_l)
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 
-	list_for_each_entry_safe_reverse(node, tmp_node,
-					 &loc_l->pending_list, list) {
+	list_for_each_entry_mutable_reverse(node, &loc_l->pending_list, list) {
 		if (READ_ONCE(node->pending_free))
 			__bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_FREE);
 		else if (bpf_lru_node_is_ref(node))
@@ -313,7 +311,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 					   struct bpf_lru_locallist *loc_l)
 {
 	struct bpf_lru_list *l = &lru->common_lru.lru_list;
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nfree = 0;
 	LIST_HEAD(tmp_free);
 
@@ -324,8 +322,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 
 	__bpf_lru_list_rotate(lru, l);
 
-	list_for_each_entry_safe(node, tmp_node, &l->lists[BPF_LRU_LIST_T_FREE],
-				 list) {
+	list_for_each_entry_mutable(node, &l->lists[BPF_LRU_LIST_T_FREE], list) {
 		__bpf_lru_node_move_to_free(l, node, &tmp_free,
 					    BPF_LRU_LOCAL_LIST_T_FREE);
 		if (++nfree == lru->target_free)
@@ -343,7 +340,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 	 * Transfer the harvested nodes from the temporary list_head into
 	 * the lockless per-CPU free llist.
 	 */
-	list_for_each_entry_safe(node, tmp_node, &tmp_free, list) {
+	list_for_each_entry_mutable(node, &tmp_free, list) {
 		list_del(&node->list);
 		llist_add(&node->llist, &loc_l->free_llist);
 	}
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15ae7c43f594..983928bd774b 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8439,7 +8439,7 @@ static void purge_cand_cache(struct btf *btf);
 static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 			     void *module)
 {
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 	struct module *mod = module;
 	struct btf *btf;
 	int err = 0;
@@ -8512,7 +8512,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_LIVE:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8523,7 +8523,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_GOING:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8567,10 +8567,10 @@ struct module *btf_try_get_module(const struct btf *btf)
 {
 	struct module *res = NULL;
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf != btf)
 			continue;
 
@@ -8596,7 +8596,7 @@ struct module *btf_try_get_module(const struct btf *btf)
 static struct btf *btf_get_module_btf(const struct module *module)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	struct btf *btf = NULL;
 
@@ -8609,7 +8609,7 @@ static struct btf *btf_get_module_btf(const struct module *module)
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->module != module)
 			continue;
 
@@ -8773,7 +8773,7 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
 static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	s32 id;
 
@@ -8789,7 +8789,7 @@ static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	guard(mutex)(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf == btf)
 			continue;
 		id = btf_find_by_name_kind(btf_mod->btf, func_name, kind);
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 83ce66296ac1..a3bd18ab9246 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -328,7 +328,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 					       bpf.release_work);
 	struct bpf_prog_array *old_array;
 	struct list_head *storages = &cgrp->bpf.storages;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	unsigned int atype;
 
@@ -337,9 +337,8 @@ static void cgroup_bpf_release(struct work_struct *work)
 	for (atype = 0; atype < ARRAY_SIZE(cgrp->bpf.progs); atype++) {
 		struct hlist_head *progs = &cgrp->bpf.progs[atype];
 		struct bpf_prog_list *pl;
-		struct hlist_node *pltmp;
 
-		hlist_for_each_entry_safe(pl, pltmp, progs, node) {
+		hlist_for_each_entry_mutable(pl, progs, node) {
 			hlist_del(&pl->node);
 			if (pl->prog) {
 				if (pl->prog->expected_attach_type == BPF_LSM_CGROUP)
@@ -360,7 +359,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 		bpf_prog_array_free(old_array);
 	}
 
-	list_for_each_entry_safe(storage, stmp, storages, list_cg) {
+	list_for_each_entry_mutable(storage, storages, list_cg) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 5e59ab896f05..fa3a1b3559e2 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -821,9 +821,9 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,
 
 void __cpu_map_flush(struct list_head *flush_list)
 {
-	struct xdp_bulk_queue *bq, *tmp;
+	struct xdp_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->obj->bulkq->bq_lock);
 		bq_flush_to_queue(bq);
 		local_unlock_nested_bh(&bq->obj->bulkq->bq_lock);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index dc7b859e8bbf..d85e4f955061 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -219,11 +219,10 @@ static void dev_map_free(struct bpf_map *map)
 		for (i = 0; i < dtab->n_buckets; i++) {
 			struct bpf_dtab_netdev *dev;
 			struct hlist_head *head;
-			struct hlist_node *next;
 
 			head = dev_map_index_hash(dtab, i);
 
-			hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+			hlist_for_each_entry_mutable(dev, head, index_hlist) {
 				hlist_del_rcu(&dev->index_hlist);
 				if (dev->xdp_prog)
 					bpf_prog_put(dev->xdp_prog);
@@ -426,9 +425,9 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
  */
 void __dev_flush(struct list_head *flush_list)
 {
-	struct xdp_dev_bulk_queue *bq, *tmp;
+	struct xdp_dev_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->dev->xdp_bulkq->bq_lock);
 		bq_xmit_all(bq, XDP_XMIT_FLUSH);
 		bq->dev_rx = NULL;
@@ -1124,11 +1123,10 @@ static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab,
 	for (i = 0; i < dtab->n_buckets; i++) {
 		struct bpf_dtab_netdev *dev;
 		struct hlist_head *head;
-		struct hlist_node *next;
 
 		head = dev_map_index_hash(dtab, i);
 
-		hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+		hlist_for_each_entry_mutable(dev, head, index_hlist) {
 			if (netdev != dev->dev)
 				continue;
 
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index c18f1e16edee..cfaf97dd970a 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1662,7 +1662,7 @@ static void bpf_async_process_op(struct bpf_async_cb *cb, u32 op,
 static void bpf_async_irq_worker(struct irq_work *work)
 {
 	struct bpf_async_cb *cb = container_of(work, struct bpf_async_cb, worker);
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 
 	list = llist_del_all(&cb->async_cmds);
 	if (!list)
@@ -1670,7 +1670,7 @@ static void bpf_async_irq_worker(struct irq_work *work)
 
 	list = llist_reverse_order(list);
 	this_cpu_write(async_cb_running, cb);
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		struct bpf_async_cmd *cmd;
 
 		cmd = container_of(pos, struct bpf_async_cmd, node);
@@ -2247,7 +2247,7 @@ EXPORT_SYMBOL_GPL(bpf_base_func_proto);
 void bpf_list_head_free(const struct btf_field *field, void *list_head,
 			struct bpf_spin_lock *spin_lock)
 {
-	struct list_head *head = list_head, drain, *pos, *n;
+	struct list_head *head = list_head, drain, *pos;
 
 	BUILD_BUG_ON(sizeof(struct list_head) > sizeof(struct bpf_list_head));
 	BUILD_BUG_ON(__alignof__(struct list_head) > __alignof__(struct bpf_list_head));
@@ -2262,7 +2262,7 @@ void bpf_list_head_free(const struct btf_field *field, void *list_head,
 	__bpf_spin_lock_irqsave(spin_lock);
 	if (!head->next || list_empty(head))
 		goto unlock;
-	list_for_each_safe(pos, n, head) {
+	list_for_each_mutable(pos, head) {
 		struct bpf_list_node_kern *node;
 
 		node = container_of(pos, struct bpf_list_node_kern, list_head);
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index 23267213a17f..2595c5a4d171 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -342,11 +342,11 @@ static void cgroup_storage_map_free(struct bpf_map *_map)
 {
 	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 	struct list_head *storages = &map->list;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	cgroup_lock();
 
-	list_for_each_entry_safe(storage, stmp, storages, list_map) {
+	list_for_each_entry_mutable(storage, storages, list_map) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
index e9662db7198f..09adb1d0e101 100644
--- a/kernel/bpf/memalloc.c
+++ b/kernel/bpf/memalloc.c
@@ -264,10 +264,10 @@ static void free_one(void *obj, bool percpu)
 
 static int free_all(struct bpf_mem_cache *c, struct llist_node *llnode, bool percpu)
 {
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	int cnt = 0;
 
-	llist_for_each_safe(pos, t, llnode) {
+	llist_for_each_mutable(pos, llnode) {
 		if (c->dtor)
 			c->dtor((void *)pos + LLIST_NODE_SZ, c->dtor_ctx);
 		free_one(pos, percpu);
@@ -296,7 +296,7 @@ static void enque_to_free(struct bpf_mem_cache *c, void *obj)
 
 static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 
 	if (atomic_xchg(&c->call_rcu_ttrace_in_progress, 1)) {
 		if (unlikely(READ_ONCE(c->draining))) {
@@ -307,7 +307,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 	}
 
 	WARN_ON_ONCE(!llist_empty(&c->waiting_for_gp_ttrace));
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_by_rcu_ttrace))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_by_rcu_ttrace))
 		llist_add(llnode, &c->waiting_for_gp_ttrace);
 
 	if (unlikely(READ_ONCE(c->draining))) {
@@ -326,7 +326,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 static void free_bulk(struct bpf_mem_cache *c)
 {
 	struct bpf_mem_cache *tgt = c->tgt;
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 	int cnt;
 
@@ -346,7 +346,7 @@ static void free_bulk(struct bpf_mem_cache *c)
 	} while (cnt > (c->high_watermark + c->low_watermark) / 2);
 
 	/* and drain free_llist_extra */
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra))
 		enque_to_free(tgt, llnode);
 	do_call_rcu_ttrace(tgt);
 }
@@ -374,13 +374,13 @@ static void __free_by_rcu(struct rcu_head *head)
 
 static void check_free_by_rcu(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 
 	/* drain free_llist_extra_rcu */
 	if (unlikely(!llist_empty(&c->free_llist_extra_rcu))) {
 		inc_active(c, &flags);
-		llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra_rcu))
+		llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra_rcu))
 			if (__llist_add(llnode, &c->free_by_rcu))
 				c->free_by_rcu_tail = llnode;
 		dec_active(c, &flags);
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 0d6f5569588c..32a21613fe79 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -137,8 +137,8 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 						struct net_device *netdev)
 {
 	struct bpf_offload_netdev *ondev, *altdev = NULL;
-	struct bpf_offloaded_map *offmap, *mtmp;
-	struct bpf_prog_offload *offload, *ptmp;
+	struct bpf_offloaded_map *offmap;
+	struct bpf_prog_offload *offload;
 
 	ASSERT_RTNL();
 
@@ -165,9 +165,9 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 			offmap->netdev = altdev->netdev;
 		list_splice_init(&ondev->maps, &altdev->maps);
 	} else {
-		list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
+		list_for_each_entry_mutable(offload, &ondev->progs, offloads)
 			__bpf_prog_offload_destroy(offload->prog);
-		list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
+		list_for_each_entry_mutable(offmap, &ondev->maps, offloads)
 			__bpf_map_offload_destroy(offmap);
 	}
 
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ec7942049c06 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -1241,7 +1241,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 	struct bpf_verifier_state *cur = env->cur_state, *new;
 	bool force_new_state, add_new_state, loop;
 	int n, err, states_cnt = 0;
-	struct list_head *pos, *tmp, *head;
+	struct list_head *pos, *head;
 
 	force_new_state = env->test_state_freq || bpf_is_force_checkpoint(env, insn_idx) ||
 			  /* Avoid accumulating infinitely long jmp history */
@@ -1267,7 +1267,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 
 	loop = false;
 	head = bpf_explored_state(env, insn_idx);
-	list_for_each_safe(pos, tmp, head) {
+	list_for_each_mutable(pos, head) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		states_cnt++;
 		if (sl->state.insn_idx != insn_idx)
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index be9ce98e9469..3d722cfd1d07 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -96,9 +96,9 @@ static void bpf_stream_free_elem(struct bpf_stream_elem *elem)
 
 static void bpf_stream_free_list(struct llist_node *list)
 {
-	struct bpf_stream_elem *elem, *tmp;
+	struct bpf_stream_elem *elem;
 
-	llist_for_each_entry_safe(elem, tmp, list, node)
+	llist_for_each_entry_mutable(elem, list, node)
 		bpf_stream_free_elem(elem);
 }
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281..7cd5d10b390a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18285,7 +18285,7 @@ static void sanitize_dead_code(struct bpf_verifier_env *env)
 static void free_states(struct bpf_verifier_env *env)
 {
 	struct bpf_verifier_state_list *sl;
-	struct list_head *head, *pos, *tmp;
+	struct list_head *head, *pos;
 	struct bpf_scc_info *info;
 	int i, j;
 
@@ -18293,7 +18293,7 @@ static void free_states(struct bpf_verifier_env *env)
 	env->cur_state = NULL;
 	while (!pop_stack(env, NULL, NULL, false));
 
-	list_for_each_safe(pos, tmp, &env->free_list) {
+	list_for_each_mutable(pos, &env->free_list) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		bpf_free_verifier_state(&sl->state, false);
 		kfree(sl);
@@ -18316,7 +18316,7 @@ static void free_states(struct bpf_verifier_env *env)
 	for (i = 0; i < state_htab_size(env); i++) {
 		head = &env->explored_states[i];
 
-		list_for_each_safe(pos, tmp, head) {
+		list_for_each_mutable(pos, head) {
 			sl = container_of(pos, struct bpf_verifier_state_list, node);
 			bpf_free_verifier_state(&sl->state, false);
 			kfree(sl);
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index a4337c9b5287..1c777b28861f 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -205,10 +205,10 @@ struct cgroup_pidlist {
  */
 void cgroup1_pidlist_destroy_all(struct cgroup *cgrp)
 {
-	struct cgroup_pidlist *l, *tmp_l;
+	struct cgroup_pidlist *l;
 
 	mutex_lock(&cgrp->pidlist_mutex);
-	list_for_each_entry_safe(l, tmp_l, &cgrp->pidlists, links)
+	list_for_each_entry_mutable(l, &cgrp->pidlists, links)
 		mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, 0);
 	mutex_unlock(&cgrp->pidlist_mutex);
 
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 38f8d9df8fbc..2b619c1553ee 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -872,9 +872,9 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
 static void css_set_skip_task_iters(struct css_set *cset,
 				    struct task_struct *task)
 {
-	struct css_task_iter *it, *pos;
+	struct css_task_iter *it;
 
-	list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node)
+	list_for_each_entry_mutable(it, &cset->task_iters, iters_node)
 		css_task_iter_skip(it, task);
 }
 
@@ -951,7 +951,7 @@ static unsigned long css_set_hash(struct cgroup_subsys_state **css)
 
 void put_css_set_locked(struct css_set *cset)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	struct cgroup_subsys *ss;
 	int ssid;
 
@@ -970,7 +970,7 @@ void put_css_set_locked(struct css_set *cset)
 	hash_del(&cset->hlist);
 	css_set_count--;
 
-	list_for_each_entry_safe(link, tmp_link, &cset->cgrp_links, cgrp_link) {
+	list_for_each_entry_mutable(link, &cset->cgrp_links, cgrp_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		if (cgroup_parent(link->cgrp))
@@ -1129,9 +1129,9 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset,
 
 static void free_cgrp_cset_links(struct list_head *links_to_free)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 
-	list_for_each_entry_safe(link, tmp_link, links_to_free, cset_link) {
+	list_for_each_entry_mutable(link, links_to_free, cset_link) {
 		list_del(&link->cset_link);
 		kfree(link);
 	}
@@ -1372,7 +1372,7 @@ void cgroup_free_root(struct cgroup_root *root)
 static void cgroup_destroy_root(struct cgroup_root *root)
 {
 	struct cgroup *cgrp = &root->cgrp;
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	int ret;
 
 	trace_cgroup_destroy_root(root);
@@ -1395,7 +1395,7 @@ static void cgroup_destroy_root(struct cgroup_root *root)
 	 */
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(link, tmp_link, &cgrp->cset_links, cset_link) {
+	list_for_each_entry_mutable(link, &cgrp->cset_links, cset_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		kfree(link);
@@ -1887,7 +1887,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		struct cgroup_root *src_root = ss->root;
 		struct cgroup *scgrp = &src_root->cgrp;
 		struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);
-		struct css_set *cset, *cset_pos;
+		struct css_set *cset;
 		struct css_task_iter *it;
 
 		WARN_ON(!css || cgroup_css(dcgrp, ss));
@@ -1912,8 +1912,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		spin_lock_irq(&css_set_lock);
 		css->cgroup = dcgrp;
 		WARN_ON(!list_empty(&dcgrp->e_csets[ss->id]));
-		list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id],
-					 e_cset_node[ss->id]) {
+		list_for_each_entry_mutable(cset, &scgrp->e_csets[ss->id],
+					    e_cset_node[ss->id]) {
 			list_move_tail(&cset->e_cset_node[ss->id],
 				       &dcgrp->e_csets[ss->id]);
 			/*
@@ -2689,8 +2689,8 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 {
 	struct cgroup_taskset *tset = &mgctx->tset;
 	struct cgroup_subsys *ss;
-	struct task_struct *task, *tmp_task;
-	struct css_set *cset, *tmp_cset;
+	struct task_struct *task;
+	struct css_set *cset;
 	int ssid, failed_ssid, ret;
 
 	/* check that we can legitimately attach to the cgroup */
@@ -2714,7 +2714,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 	 */
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(cset, &tset->src_csets, mg_node) {
-		list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list) {
+		list_for_each_entry_mutable(task, &cset->mg_tasks, cg_list) {
 			struct css_set *from_cset = task_css_set(task);
 			struct css_set *to_cset = cset->mg_dst_cset;
 
@@ -2767,7 +2767,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 out_release_tset:
 	spin_lock_irq(&css_set_lock);
 	list_splice_init(&tset->dst_csets, &tset->src_csets);
-	list_for_each_entry_safe(cset, tmp_cset, &tset->src_csets, mg_node) {
+	list_for_each_entry_mutable(cset, &tset->src_csets, mg_node) {
 		list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
 		list_del_init(&cset->mg_node);
 	}
@@ -2825,14 +2825,14 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *cset, *tmp_cset;
+	struct css_set *cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2840,8 +2840,8 @@ void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 		put_css_set_locked(cset);
 	}
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
-				 mg_dst_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_dst_csets,
+				    mg_dst_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2917,13 +2917,13 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
  */
 int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *src_cset, *tmp_cset;
+	struct css_set *src_cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	/* look up the dst cset for each src cset and link it to src */
-	list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(src_cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		struct css_set *dst_cset;
 		struct cgroup_subsys *ss;
 		int ssid;
@@ -3225,10 +3225,10 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
 			    mg_src_preload_node) {
-		struct task_struct *task, *ntask;
+		struct task_struct *task;
 
 		/* all tasks in src_csets need to be migrated */
-		list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list)
+		list_for_each_entry_mutable(task, &src_cset->tasks, cg_list)
 			cgroup_migrate_add_task(task, &mgctx);
 	}
 	spin_unlock_irq(&css_set_lock);
@@ -7106,10 +7106,10 @@ static DEFINE_PER_CPU(struct irq_work, cgrp_dead_tasks_iwork);
 static void cgrp_dead_tasks_iwork_fn(struct irq_work *iwork)
 {
 	struct llist_node *lnode;
-	struct task_struct *task, *next;
+	struct task_struct *task;
 
 	lnode = llist_del_all(this_cpu_ptr(&cgrp_dead_tasks));
-	llist_for_each_entry_safe(task, next, lnode, cg_dead_lnode) {
+	llist_for_each_entry_mutable(task, lnode, cg_dead_lnode) {
 		do_cgroup_task_dead(task);
 		put_task_struct(task);
 	}
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 4753a67d0f0f..1daa8fb49fbe 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -203,10 +203,10 @@ static void dmemcs_offline(struct cgroup_subsys_state *css)
 static void dmemcs_free(struct cgroup_subsys_state *css)
 {
 	struct dmemcg_state *dmemcs = css_to_dmemcs(css);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	spin_lock(&dmemcg_lock);
-	list_for_each_entry_safe(pool, next, &dmemcs->pools, css_node) {
+	list_for_each_entry_mutable(pool, &dmemcs->pools, css_node) {
 		/*
 		 *The pool is dead and all references are 0,
 		 * no need for RCU protection with list_del_rcu or freeing.
@@ -444,9 +444,9 @@ get_cg_pool_locked(struct dmemcg_state *dmemcs, struct dmem_cgroup_region *regio
 static void dmemcg_free_rcu(struct rcu_head *rcu)
 {
 	struct dmem_cgroup_region *region = container_of(rcu, typeof(*region), rcu);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node)
+	list_for_each_entry_mutable(pool, &region->pools, region_node)
 		free_cg_pool(pool);
 	kfree(region->name);
 	kfree(region);
@@ -467,7 +467,7 @@ static void dmemcg_free_region(struct kref *ref)
  */
 void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 {
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	if (!region)
 		return;
@@ -477,7 +477,7 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 	/* Remove from global region list */
 	list_del_rcu(&region->region_node);
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node) {
+	list_for_each_entry_mutable(pool, &region->pools, region_node) {
 		list_del_rcu(&pool->css_node);
 		list_del(&pool->region_node);
 		dmemcg_pool_put(pool);
diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c
index 5e82a03b3270..5527375c16e1 100644
--- a/kernel/cgroup/rdma.c
+++ b/kernel/cgroup/rdma.c
@@ -444,7 +444,7 @@ EXPORT_SYMBOL(rdmacg_register_device);
  */
 void rdmacg_unregister_device(struct rdmacg_device *device)
 {
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/*
 	 * Synchronize with any active resource settings,
@@ -457,7 +457,7 @@ void rdmacg_unregister_device(struct rdmacg_device *device)
 	 * Now that this device is off the cgroup list, its safe to free
 	 * all the rpool resources.
 	 */
-	list_for_each_entry_safe(rpool, tmp, &device->rpools, dev_node)
+	list_for_each_entry_mutable(rpool, &device->rpools, dev_node)
 		free_cg_rpool_locked(rpool);
 
 	mutex_unlock(&rdmacg_mutex);
@@ -747,11 +747,11 @@ rdmacg_css_alloc(struct cgroup_subsys_state *parent)
 static void rdmacg_css_free(struct cgroup_subsys_state *css)
 {
 	struct rdma_cgroup *cg = css_rdmacg(css);
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/* Clean up rpools kept alive by non-zero peak values */
 	mutex_lock(&rdmacg_mutex);
-	list_for_each_entry_safe(rpool, tmp, &cg->rpools, cg_node)
+	list_for_each_entry_mutable(rpool, &cg->rpools, cg_node)
 		free_cg_rpool_locked(rpool);
 	mutex_unlock(&rdmacg_mutex);
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 00e6dcb931d9..dd93436f8f2d 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2346,7 +2346,7 @@ static inline struct list_head *get_event_list(struct perf_event *event)
 static void perf_group_detach(struct perf_event *event)
 {
 	struct perf_event *leader = event->group_leader;
-	struct perf_event *sibling, *tmp;
+	struct perf_event *sibling;
 	struct perf_event_context *ctx = event->ctx;
 
 	lockdep_assert_held(&ctx->lock);
@@ -2376,7 +2376,7 @@ static void perf_group_detach(struct perf_event *event)
 	 * upgrade the siblings to singleton events by adding them
 	 * to whatever list we are on.
 	 */
-	list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) {
+	list_for_each_entry_mutable(sibling, &event->sibling_list, sibling_list) {
 
 		/*
 		 * Events that have PERF_EV_CAP_SIBLING require being part of
@@ -2405,8 +2405,8 @@ static void perf_group_detach(struct perf_event *event)
 	}
 
 out:
-	for_each_sibling_event(tmp, leader)
-		perf_event__header_size(tmp);
+	for_each_sibling_event(sibling, leader)
+		perf_event__header_size(sibling);
 
 	perf_event__header_size(leader);
 }
@@ -3528,7 +3528,7 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 				enum event_type_t event_type)
 {
 	struct perf_event_context *ctx = pmu_ctx->ctx;
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 	struct pmu *pmu = pmu_ctx->pmu;
 
 	if (ctx->task && !(ctx->is_active & EVENT_ALL)) {
@@ -3543,16 +3543,14 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 
 	perf_pmu_disable(pmu);
 	if (event_type & EVENT_PINNED) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->pinned_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->pinned_active,
+					    active_list)
 			group_sched_out(event, ctx);
 	}
 
 	if (event_type & EVENT_FLEXIBLE) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->flexible_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->flexible_active,
+					    active_list)
 			group_sched_out(event, ctx);
 		/*
 		 * Since we cleared EVENT_FLEXIBLE, also clear
@@ -4738,7 +4736,7 @@ static void perf_event_exit_event(struct perf_event *event,
 static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 {
 	struct perf_event_context *clone_ctx = NULL;
-	struct perf_event *event, *next;
+	struct perf_event *event;
 	unsigned long flags;
 	bool modified = false;
 
@@ -4747,7 +4745,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 	if (WARN_ON_ONCE(ctx->task != current))
 		goto unlock;
 
-	list_for_each_entry_safe(event, next, &ctx->event_list, event_entry) {
+	list_for_each_entry_mutable(event, &ctx->event_list, event_entry) {
 		if (!event->attr.remove_on_exec)
 			continue;
 
@@ -11833,9 +11831,9 @@ perf_addr_filter_new(struct perf_event *event, struct list_head *filters)
 
 static void free_filters_list(struct list_head *filters)
 {
-	struct perf_addr_filter *filter, *iter;
+	struct perf_addr_filter *filter;
 
-	list_for_each_entry_safe(filter, iter, filters, entry) {
+	list_for_each_entry_mutable(filter, filters, entry) {
 		path_put(&filter->path);
 		list_del(&filter->entry);
 		kfree(filter);
@@ -14436,7 +14434,7 @@ static void __perf_pmu_install_event(struct pmu *pmu,
 static void __perf_pmu_install(struct perf_event_context *ctx,
 			       int cpu, struct pmu *pmu, struct list_head *events)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	/*
 	 * Re-instate events in 2 passes.
@@ -14446,7 +14444,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * leader will enable its siblings, even if those are still on the old
 	 * context.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		if (event->group_leader == event)
 			continue;
 
@@ -14458,7 +14456,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * Once all the siblings are setup properly, install the group leaders
 	 * to make it go.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		list_del(&event->migrate_entry);
 		__perf_pmu_install_event(pmu, ctx, cpu, event);
 	}
@@ -14592,7 +14590,7 @@ perf_event_exit_event(struct perf_event *event,
 static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 {
 	struct perf_event_context *ctx, *clone_ctx = NULL;
-	struct perf_event *child_event, *next;
+	struct perf_event *child_event;
 
 	ctx = perf_pin_task_context(task);
 	if (!ctx)
@@ -14642,7 +14640,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 	if (exit)
 		perf_event_task(task, ctx, 0);
 
-	list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+	list_for_each_entry_mutable(child_event, &ctx->event_list, event_entry)
 		perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
 
 	mutex_unlock(&ctx->mutex);
@@ -14675,13 +14673,13 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
  */
 void perf_event_exit_task(struct task_struct *task)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	WARN_ON_ONCE(task != current);
 
 	mutex_lock(&task->perf_event_mutex);
-	list_for_each_entry_safe(event, tmp, &task->perf_event_list,
-				 owner_entry) {
+	list_for_each_entry_mutable(event, &task->perf_event_list,
+				    owner_entry) {
 		list_del_init(&event->owner_entry);
 
 		/*
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 4084e926e284..61aa48e3b5a6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -258,13 +258,13 @@ static void delayed_uprobe_delete(struct delayed_uprobe *du)
 
 static void delayed_uprobe_remove(struct uprobe *uprobe, struct mm_struct *mm)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 
 	if (!uprobe && !mm)
 		return;
 
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (uprobe && du->uprobe != uprobe)
@@ -1562,13 +1562,13 @@ static void build_probe_list(struct inode *inode,
 /* @vma contains reference counter, not the probed instruction. */
 static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 	unsigned long vaddr;
 	int ret = 0, err = 0;
 
 	mutex_lock(&delayed_uprobe_lock);
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (du->mm != vma->vm_mm ||
@@ -1597,7 +1597,7 @@ static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
 	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
+	struct uprobe *uprobe;
 	struct inode *inode;
 
 	if (no_uprobe_events())
@@ -1622,7 +1622,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
 	 * removed. But in this case filter_chain() must return false, all
 	 * consumers have gone away.
 	 */
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+	list_for_each_entry_mutable(uprobe, &tmp_list, pending_list) {
 		if (!fatal_signal_pending(current) &&
 		    filter_chain(uprobe, vma->vm_mm)) {
 			unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
diff --git a/kernel/exit.c b/kernel/exit.c
index 1056422bc101..62ef6553253a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -630,7 +630,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 {
 	struct pid_namespace *pid_ns = task_active_pid_ns(father);
 	struct task_struct *reaper = pid_ns->child_reaper;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	if (likely(reaper != father))
 		return reaper;
@@ -644,7 +644,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
@@ -766,7 +766,7 @@ static void forget_original_parent(struct task_struct *father,
 static void exit_notify(struct task_struct *tsk, int group_dead)
 {
 	bool autoreap;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 	LIST_HEAD(dead);
 
 	write_lock_irq(&tasklist_lock);
@@ -800,7 +800,7 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 		wake_up_process(tsk->signal->group_exec_task);
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, &dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, &dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
diff --git a/kernel/fail_function.c b/kernel/fail_function.c
index 2eaf55005f49..357c810c4908 100644
--- a/kernel/fail_function.c
+++ b/kernel/fail_function.c
@@ -226,9 +226,9 @@ static void fei_attr_remove(struct fei_attr *attr)
 
 static void fei_attr_remove_all(void)
 {
-	struct fei_attr *attr, *n;
+	struct fei_attr *attr;
 
-	list_for_each_entry_safe(attr, n, &fei_attr_list, list) {
+	list_for_each_entry_mutable(attr, &fei_attr_list, list) {
 		fei_attr_remove(attr);
 	}
 }
diff --git a/kernel/gcov/clang.c b/kernel/gcov/clang.c
index fd98ced0e51d..e9a86a04d793 100644
--- a/kernel/gcov/clang.c
+++ b/kernel/gcov/clang.c
@@ -347,9 +347,9 @@ struct gcov_info *gcov_info_dup(struct gcov_info *info)
  */
 void gcov_info_free(struct gcov_info *info)
 {
-	struct gcov_fn_info *fn, *tmp;
+	struct gcov_fn_info *fn;
 
-	list_for_each_entry_safe(fn, tmp, &info->functions, head) {
+	list_for_each_entry_mutable(fn, &info->functions, head) {
 		kvfree(fn->counters);
 		list_del(&fn->head);
 		kfree(fn);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index f7e2dc2c30c6..ce454e12cd86 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -234,7 +234,7 @@ void irq_work_single(void *arg)
 
 static void irq_work_run_list(struct llist_head *list)
 {
-	struct irq_work *work, *tmp;
+	struct irq_work *work;
 	struct llist_node *llnode;
 
 	/*
@@ -248,7 +248,7 @@ static void irq_work_run_list(struct llist_head *list)
 		return;
 
 	llnode = llist_del_all(list);
-	llist_for_each_entry_safe(work, tmp, llnode, node.llist)
+	llist_for_each_entry_mutable(work, llnode, node.llist)
 		irq_work_single(work);
 }
 
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index dc770b9a6d05..d50d15d4709f 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -318,9 +318,9 @@ static void kimage_free_pages(struct page *page)
 
 void kimage_free_page_list(struct list_head *list)
 {
-	struct page *page, *next;
+	struct page *page;
 
-	list_for_each_entry_safe(page, next, list, lru) {
+	list_for_each_entry_mutable(page, list, lru) {
 		list_del(&page->lru);
 		kimage_free_pages(page);
 	}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index bfc89083daa9..8e8fd6833d1c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -228,12 +228,12 @@ static bool collect_one_slot(struct kprobe_insn_page *kip, int idx)
 
 static int collect_garbage_slots(struct kprobe_insn_cache *c)
 {
-	struct kprobe_insn_page *kip, *next;
+	struct kprobe_insn_page *kip;
 
 	/* Ensure no-one is interrupted on the garbages */
 	synchronize_rcu();
 
-	list_for_each_entry_safe(kip, next, &c->pages, list) {
+	list_for_each_entry_mutable(kip, &c->pages, list) {
 		int i;
 
 		if (kip->ngarbage == 0)
@@ -563,7 +563,7 @@ static void do_optimize_kprobes(void)
  */
 static void do_unoptimize_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
 	lockdep_assert_held(&text_mutex);
 	/* See comment in do_optimize_kprobes() */
@@ -573,7 +573,7 @@ static void do_unoptimize_kprobes(void)
 		arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
 
 	/* Loop on 'freeing_list' for disarming and removing from kprobe hash list */
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		/* Switching from detour code to origin */
 		op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
 		/* Disarm probes if marked disabled and not gone */
@@ -594,9 +594,9 @@ static void do_unoptimize_kprobes(void)
 /* Reclaim all kprobes on the 'freeing_list' */
 static void do_free_cleaned_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		list_del_init(&op->list);
 		if (WARN_ON_ONCE(!kprobe_unused(&op->kp))) {
 			/*
@@ -2598,9 +2598,9 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
 /* Remove all symbols in given area from kprobe blacklist */
 static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
 {
-	struct kprobe_blacklist_entry *ent, *n;
+	struct kprobe_blacklist_entry *ent;
 
-	list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
+	list_for_each_entry_mutable(ent, &kprobe_blacklist, list) {
 		if (ent->start_addr < start || ent->start_addr >= end)
 			continue;
 		list_del(&ent->list);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28d15ba58a26..6e433519bfff 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -788,9 +788,9 @@ void klp_free_patch_async(struct klp_patch *patch)
 
 void klp_free_replaced_patches_async(struct klp_patch *new_patch)
 {
-	struct klp_patch *old_patch, *tmp_patch;
+	struct klp_patch *old_patch;
 
-	klp_for_each_patch_safe(old_patch, tmp_patch) {
+	klp_for_each_patch_safe(old_patch) {
 		if (old_patch == new_patch)
 			return;
 		klp_free_patch_async(old_patch);
diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h
index 38209c7361b6..274c8108062f 100644
--- a/kernel/livepatch/core.h
+++ b/kernel/livepatch/core.h
@@ -7,8 +7,8 @@
 extern struct mutex klp_mutex;
 extern struct list_head klp_patches;
 
-#define klp_for_each_patch_safe(patch, tmp_patch)		\
-	list_for_each_entry_safe(patch, tmp_patch, &klp_patches, list)
+#define klp_for_each_patch_safe(patch)		\
+	list_for_each_entry_mutable(patch, &klp_patches, list)
 
 #define klp_for_each_patch(patch)	\
 	list_for_each_entry(patch, &klp_patches, list)
diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c
index 0d2a342ef422..40e42a47751c 100644
--- a/kernel/liveupdate/kho_block.c
+++ b/kernel/liveupdate/kho_block.c
@@ -298,9 +298,9 @@ int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa)
  */
 void kho_block_set_destroy(struct kho_block_set *bs)
 {
-	struct kho_block *block, *tmp;
+	struct kho_block *block;
 
-	list_for_each_entry_safe(block, tmp, &bs->blocks, list) {
+	list_for_each_entry_mutable(block, &bs->blocks, list) {
 		list_del(&block->list);
 		kho_block_free_ser(bs, block->ser);
 		kfree(block);
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 5c27134ce7ba..cf5d577e25e4 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -359,13 +359,13 @@ static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
 void luo_flb_unregister_all(struct liveupdate_file_handler *fh)
 {
 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
-	struct luo_flb_link *iter, *tmp;
+	struct luo_flb_link *iter;
 
 	if (!liveupdate_enabled())
 		return;
 
 	lockdep_assert_held_write(&luo_register_rwlock);
-	list_for_each_entry_safe(iter, tmp, flb_list, list)
+	list_for_each_entry_mutable(iter, flb_list, list)
 		luo_flb_unregister_one(fh, iter->flb);
 }
 
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index b9c180ac1eee..8db6caf31e41 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -567,7 +567,7 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
 		atomic_long_add(adjustment, &sem->count);
 
 	/* 2nd pass */
-	list_for_each_entry_safe(waiter, next, &wlist, list) {
+	list_for_each_entry_mutable(waiter, &wlist, list) {
 		struct task_struct *tsk;
 
 		tsk = waiter->task;
diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c
index 838d631544ed..f290061a8b48 100644
--- a/kernel/locking/test-ww_mutex.c
+++ b/kernel/locking/test-ww_mutex.c
@@ -546,7 +546,7 @@ static void stress_reorder_work(struct work_struct *work)
 	} while (!time_after(jiffies, stress->timeout));
 
 out:
-	list_for_each_entry_safe(ll, ln, &locks, link)
+	list_for_each_entry_mutable(ll, &locks, link)
 		kfree(ll);
 	kfree(order);
 }
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..471448804053 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -725,10 +725,10 @@ static int ref_module(struct module *a, struct module *b)
 /* Clear the unload stuff of the module. */
 static void module_unload_free(struct module *mod)
 {
-	struct module_use *use, *tmp;
+	struct module_use *use;
 
 	mutex_lock(&module_mutex);
-	list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
+	list_for_each_entry_mutable(use, &mod->target_list, target_list) {
 		struct module *i = use->target;
 		pr_debug("%s unusing %s\n", mod->name, i->name);
 		module_put(i);
@@ -3041,14 +3041,14 @@ struct mod_initfree {
 
 static void do_free_init(struct work_struct *w)
 {
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 	struct mod_initfree *initfree;
 
 	list = llist_del_all(&init_free_list);
 
 	synchronize_rcu();
 
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		initfree = container_of(pos, struct mod_initfree, node);
 		execmem_free(initfree->init_text);
 		execmem_free(initfree->init_data);
@@ -3701,11 +3701,10 @@ static int idempotent_complete(struct idempotent *u, int ret)
 	const void *cookie = u->cookie;
 	int hash = hash_ptr(cookie, IDEM_HASH_BITS);
 	struct hlist_head *head = idem_hash + hash;
-	struct hlist_node *next;
 	struct idempotent *pos;
 
 	spin_lock(&idem_lock);
-	hlist_for_each_entry_safe(pos, next, head, entry) {
+	hlist_for_each_entry_mutable(pos, head, entry) {
 		if (pos->cookie != cookie)
 			continue;
 		hlist_del_init(&pos->entry);
diff --git a/kernel/padata.c b/kernel/padata.c
index 0d3ea1b68b1f..270f7b0eca0a 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -134,13 +134,13 @@ static void padata_work_free(struct padata_work *pw)
 
 static void __init padata_works_free(struct list_head *works)
 {
-	struct padata_work *cur, *next;
+	struct padata_work *cur;
 
 	if (list_empty(works))
 		return;
 
 	spin_lock_bh(&padata_works_lock);
-	list_for_each_entry_safe(cur, next, works, pw_list) {
+	list_for_each_entry_mutable(cur, works, pw_list) {
 		list_del(&cur->pw_list);
 		padata_work_free(cur);
 	}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index d933b5b2c05d..c4802f2a2e35 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -610,9 +610,9 @@ struct mem_extent {
  */
 static void free_mem_extents(struct list_head *list)
 {
-	struct mem_extent *ext, *aux;
+	struct mem_extent *ext;
 
-	list_for_each_entry_safe(ext, aux, list, hook) {
+	list_for_each_entry_mutable(ext, list, hook) {
 		list_del(&ext->hook);
 		kfree(ext);
 	}
@@ -633,7 +633,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 	for_each_populated_zone(zone) {
 		unsigned long zone_start, zone_end;
-		struct mem_extent *ext, *cur, *aux;
+		struct mem_extent *ext, *cur;
 
 		zone_start = zone->zone_start_pfn;
 		zone_end = zone_end_pfn(zone);
@@ -665,7 +665,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 		/* More merging may be possible */
 		cur = ext;
-		list_for_each_entry_safe_continue(cur, aux, list, hook) {
+		list_for_each_entry_mutable_continue(cur, list, hook) {
 			if (zone_end < cur->start)
 				break;
 			if (zone_end < cur->end)
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index fd763da06a87..c8718aacfa5a 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -102,13 +102,13 @@ static inline void wakelocks_lru_most_recent(struct wakelock *wl)
 
 static void __wakelocks_gc(struct work_struct *work)
 {
-	struct wakelock *wl, *aux;
+	struct wakelock *wl;
 	ktime_t now;
 
 	mutex_lock(&wakelocks_lock);
 
 	now = ktime_get();
-	list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+	list_for_each_entry_mutable_reverse(wl, &wakelocks_lru_list, lru) {
 		u64 idle_time_ns;
 		bool active;
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823..3f524c6bdf6e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3787,7 +3787,6 @@ static struct syscore printk_syscore = {
  */
 static void printk_kthreads_check_locked(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 
 	lockdep_assert_console_list_lock_held();
@@ -3805,7 +3804,7 @@ static void printk_kthreads_check_locked(void)
 			 * are any nbcon consoles, they will set up their own
 			 * kthread.
 			 */
-			hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+			hlist_for_each_entry_mutable(con, &console_list, node) {
 				if (con->flags & CON_NBCON)
 					continue;
 
@@ -3833,7 +3832,7 @@ static void printk_kthreads_check_locked(void)
 	if (printk_kthreads_running)
 		return;
 
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_NBCON))
 			continue;
 
@@ -4209,9 +4208,8 @@ void register_console(struct console *newcon)
 	if (bootcon_registered &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
 	    !keep_bootcon) {
-		struct hlist_node *tmp;
 
-		hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+		hlist_for_each_entry_mutable(con, &console_list, node) {
 			if (con->flags & CON_BOOT)
 				unregister_console_locked(con);
 		}
@@ -4426,12 +4424,11 @@ void __init console_init(void)
  */
 static int __init printk_late_init(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 	int ret;
 
 	console_list_lock();
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_BOOT))
 			continue;
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17..8032b653af83 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -619,9 +619,9 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
  */
 void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
 {
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
-	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
+	list_for_each_entry_mutable(p, &tracer->ptraced, ptrace_entry) {
 		if (unlikely(p->ptrace & PT_EXITKILL))
 			send_sig_info(SIGKILL, SEND_SIG_PRIV, p);
 
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 882a158ada7b..9eb0007411a9 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -537,11 +537,10 @@ static void
 rcu_torture_pipe_update(struct rcu_torture *old_rp)
 {
 	struct rcu_torture *rp;
-	struct rcu_torture *rp1;
 
 	if (old_rp)
 		list_add(&old_rp->rtort_free, &rcu_torture_removed);
-	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+	list_for_each_entry_mutable(rp, &rcu_torture_removed, rtort_free) {
 		if (rcu_torture_pipe_update_one(rp)) {
 			list_del(&rp->rtort_free);
 			rcu_torture_free(rp);
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index f4da5fad70f5..e79380d93c85 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -1052,12 +1052,11 @@ static void rcu_tasks_postscan(struct list_head *hop)
 	for_each_possible_cpu(cpu) {
 		unsigned long j = jiffies + 1;
 		struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rcu_tasks.rtpcpu, cpu);
-		struct task_struct *t;
-		struct task_struct *t1;
+		struct task_struct *t, *t1;
 		struct list_head tmp;
 
 		raw_spin_lock_irq_rcu_node(rtpcp);
-		list_for_each_entry_safe(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
+		list_for_each_entry_mutable(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
 			if (list_empty(&t->rcu_tasks_holdout_list))
 				rcu_tasks_pertask(t, hop);
 
@@ -1120,9 +1119,9 @@ static void check_holdout_task(struct task_struct *t,
 static void check_all_holdout_tasks(struct list_head *hop,
 				    bool needreport, bool *firstreport)
 {
-	struct task_struct *t, *t1;
+	struct task_struct *t;
 
-	list_for_each_entry_safe(t, t1, hop, rcu_tasks_holdout_list) {
+	list_for_each_entry_mutable(t, hop, rcu_tasks_holdout_list) {
 		check_holdout_task(t, needreport, firstreport);
 		cond_resched();
 	}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 03a43d3d2616..7c7792d62ac5 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1664,7 +1664,7 @@ static void rcu_sr_normal_complete(struct llist_node *node)
 
 static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 {
-	struct llist_node *done, *rcu, *next, *head;
+	struct llist_node *done, *rcu, *head;
 
 	/*
 	 * This work execution can potentially execute
@@ -1694,7 +1694,7 @@ static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 	 * nodes is removed, in next round of cleanup
 	 * work execution.
 	 */
-	llist_for_each_safe(rcu, next, head) {
+	llist_for_each_mutable(rcu, head) {
 		if (!rcu_sr_is_wait_head(rcu)) {
 			rcu_sr_normal_complete(rcu);
 			continue;
@@ -1726,7 +1726,7 @@ static void rcu_sr_normal_gp_cleanup(void)
 	/*
 	 * Process (a) and (d) cases. See an illustration.
 	 */
-	llist_for_each_safe(rcu, next, wait_tail->next) {
+	llist_for_each_mutable(rcu, next, wait_tail->next) {
 		if (rcu_sr_is_wait_head(rcu))
 			break;
 
diff --git a/kernel/resource.c b/kernel/resource.c
index e60539a55541..19b89b09e291 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1951,9 +1951,9 @@ EXPORT_SYMBOL(resource_list_create_entry);
 
 void resource_list_free(struct list_head *head)
 {
-	struct resource_entry *entry, *tmp;
+	struct resource_entry *entry;
 
-	list_for_each_entry_safe(entry, tmp, head, node)
+	list_for_each_entry_mutable(entry, head, node)
 		resource_list_destroy_entry(entry);
 }
 EXPORT_SYMBOL(resource_list_free);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e97e98c33be5..873e26f2a032 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3892,7 +3892,7 @@ void sched_ttwu_pending(void *arg)
 {
 	struct llist_node *llist = arg;
 	struct rq *rq = this_rq();
-	struct task_struct *p, *t;
+	struct task_struct *p;
 	struct rq_flags rf;
 
 	if (!llist)
@@ -3901,7 +3901,7 @@ void sched_ttwu_pending(void *arg)
 	rq_lock_irqsave(rq, &rf);
 	update_rq_clock(rq);
 
-	llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
+	llist_for_each_entry_mutable(p, llist, wake_entry.llist) {
 		if (WARN_ON_ONCE(p->on_cpu))
 			smp_cond_load_acquire(&p->on_cpu, !VAL);
 
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 0db6fa2daea3..2119f2629fd1 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -4121,7 +4121,7 @@ static void process_ddsp_deferred_locals(struct rq *rq)
 	 * Now that @rq can be unlocked, execute the deferred enqueueing of
 	 * tasks directly dispatched to the local DSQs of other CPUs. See
 	 * direct_dispatch(). Keep popping from the head instead of using
-	 * list_for_each_entry_safe() as dispatch_local_dsq() may unlock @rq
+	 * list_for_each_entry_mutable() as dispatch_local_dsq() may unlock @rq
 	 * temporarily.
 	 */
 	while ((p = list_first_entry_or_null(&rq->scx.ddsp_deferred_locals,
@@ -4186,7 +4186,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 {
 	LIST_HEAD(tasks);
 	u32 nr_enqueued = 0;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	lockdep_assert_rq_held(rq);
 
@@ -4200,8 +4200,8 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 	 * @rq->scx.local_dsq. Move all candidate tasks off to a private list
 	 * first to avoid processing the same tasks repeatedly.
 	 */
-	list_for_each_entry_safe(p, n, &rq->scx.local_dsq.list,
-				 scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &rq->scx.local_dsq.list,
+				    scx.dsq_list.node) {
 		struct scx_sched *task_sch = scx_task_sched(p);
 		u32 reason;
 
@@ -4234,7 +4234,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 		list_add_tail(&p->scx.dsq_list.node, &tasks);
 	}
 
-	list_for_each_entry_safe(p, n, &tasks, scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &tasks, scx.dsq_list.node) {
 		list_del_init(&p->scx.dsq_list.node);
 
 		do_enqueue_task(rq, p, SCX_ENQ_REENQ, -1);
@@ -4786,9 +4786,9 @@ static void free_dsq_rcufn(struct rcu_head *rcu)
 static void free_dsq_irq_workfn(struct irq_work *irq_work)
 {
 	struct llist_node *to_free = llist_del_all(&dsqs_to_free);
-	struct scx_dispatch_q *dsq, *tmp_dsq;
+	struct scx_dispatch_q *dsq;
 
-	llist_for_each_entry_safe(dsq, tmp_dsq, to_free, free_node)
+	llist_for_each_entry_mutable(dsq, to_free, free_node)
 		call_rcu(&dsq->rcu, free_dsq_rcufn);
 }
 
@@ -5684,7 +5684,7 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 	 */
 	for_each_possible_cpu(cpu) {
 		struct rq *rq = cpu_rq(cpu);
-		struct task_struct *p, *n;
+		struct task_struct *p;
 
 		raw_spin_rq_lock(rq);
 		raw_spin_lock(&scx_sched_lock);
@@ -5711,14 +5711,14 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 		}
 
 		/*
-		 * The use of list_for_each_entry_safe_reverse() is required
+		 * The use of list_for_each_entry_mutable_reverse() is required
 		 * because each task is going to be removed from and added back
 		 * to the runnable_list during iteration. Because they're added
 		 * to the tail of the list, safe reverse iteration can still
 		 * visit all nodes.
 		 */
-		list_for_each_entry_safe_reverse(p, n, &rq->scx.runnable_list,
-						 scx.runnable_node) {
+		list_for_each_entry_mutable_reverse(p, &rq->scx.runnable_list,
+						    scx.runnable_node) {
 			if (!scx_is_descendant(scx_task_sched(p), sch))
 				continue;
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..0f21a168fd9a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -408,9 +408,9 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 }
 
 /* Iterate through all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)			\
-	list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list,	\
-				 leaf_cfs_rq_list)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)			\
+	list_for_each_entry_mutable(cfs_rq, &(rq)->leaf_cfs_rq_list,	\
+				    leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
 static inline struct cfs_rq *
@@ -494,8 +494,8 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 {
 }
 
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)	\
-		for (cfs_rq = &rq->cfs, pos = NULL; cfs_rq; cfs_rq = pos)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)	\
+		for (cfs_rq = &(rq)->cfs; cfs_rq; cfs_rq = NULL)
 
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
@@ -6724,7 +6724,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 {
 	struct rq *rq = data;
 	struct cfs_rq *cfs_rq = tg_cfs_rq(tg, cpu_of(rq));
-	struct task_struct *p, *tmp;
+	struct task_struct *p;
 	LIST_HEAD(throttled_tasks);
 
 	/*
@@ -6765,7 +6765,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 	list_splice_init(&cfs_rq->throttled_limbo_list, &throttled_tasks);
 
 	/* Re-enqueue the tasks that have been throttled at this level. */
-	list_for_each_entry_safe(p, tmp, &throttled_tasks, throttle_node) {
+	list_for_each_entry_mutable(p, &throttled_tasks, throttle_node) {
 		/*
 		 * Back to being throttled! Break out and put the remaining
 		 * tasks back onto the limbo_list to prevent running them
@@ -6966,7 +6966,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
 
 static void __cfsb_csd_unthrottle(void *arg)
 {
-	struct cfs_rq *cursor, *tmp;
+	struct cfs_rq *cursor;
 	struct rq *rq = arg;
 
 	guard(rq_lock)(rq);
@@ -6988,8 +6988,8 @@ static void __cfsb_csd_unthrottle(void *arg)
 	 */
 	guard(rcu)();
 
-	list_for_each_entry_safe(cursor, tmp, &rq->cfsb_csd_list,
-				 throttled_csd_list) {
+	list_for_each_entry_mutable(cursor, &rq->cfsb_csd_list,
+				    throttled_csd_list) {
 		list_del_init(&cursor->throttled_csd_list);
 
 		if (cfs_rq_throttled(cursor))
@@ -11118,14 +11118,14 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
 
 static bool __update_blocked_fair(struct rq *rq, bool *done)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 	bool decayed = false;
 
 	/*
 	 * Iterates the task_group tree in a bottom up fashion, see
 	 * list_add_leaf_cfs_rq() for details.
 	 */
-	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq) {
 		struct sched_entity *se;
 
 		if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
@@ -15401,10 +15401,10 @@ DEFINE_SCHED_CLASS(fair) = {
 
 void print_cfs_stats(struct seq_file *m, int cpu)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 
 	rcu_read_lock();
-	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq, pos)
+	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq)
 		print_cfs_rq(m, cpu, cfs_rq);
 	rcu_read_unlock();
 }
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 622e2e01974c..062887738bff 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -1753,7 +1753,7 @@ static inline void asym_cpu_capacity_update_data(int cpu)
  */
 static void asym_cpu_capacity_scan(void)
 {
-	struct asym_cap_data *entry, *next;
+	struct asym_cap_data *entry;
 	int cpu;
 
 	list_for_each_entry(entry, &asym_cap_list, link)
@@ -1762,7 +1762,7 @@ static void asym_cpu_capacity_scan(void)
 	for_each_cpu_and(cpu, cpu_possible_mask, housekeeping_cpumask(HK_TYPE_DOMAIN))
 		asym_cpu_capacity_update_data(cpu);
 
-	list_for_each_entry_safe(entry, next, &asym_cap_list, link) {
+	list_for_each_entry_mutable(entry, &asym_cap_list, link) {
 		if (cpumask_empty(cpu_capacity_span(entry))) {
 			list_del_rcu(&entry->link);
 			call_rcu(&entry->rcu, free_asym_cap_entry);
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 20f27e2cf7ae..3411f9ac2073 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -92,7 +92,7 @@ EXPORT_SYMBOL(remove_wait_queue);
 static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 			int nr_exclusive, int wake_flags, void *key)
 {
-	wait_queue_entry_t *curr, *next;
+	wait_queue_entry_t *curr;
 
 	lockdep_assert_held(&wq_head->lock);
 
@@ -101,7 +101,7 @@ static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 	if (&curr->entry == &wq_head->head)
 		return nr_exclusive;
 
-	list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {
+	list_for_each_entry_mutable_from(curr, &wq_head->head, entry) {
 		unsigned flags = curr->flags;
 		int ret;
 
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 066909393c38..7212e47703f9 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1168,7 +1168,7 @@ static int seccomp_do_user_notification(int this_syscall,
 	u32 flags = 0;
 	long ret = 0;
 	struct seccomp_knotif n = {};
-	struct seccomp_kaddfd *addfd, *tmp;
+	struct seccomp_kaddfd *addfd;
 
 	mutex_lock(&match->notify_lock);
 	err = -ENOSYS;
@@ -1225,7 +1225,7 @@ static int seccomp_do_user_notification(int this_syscall,
 
 interrupted:
 	/* If there were any pending addfd calls, clear them out */
-	list_for_each_entry_safe(addfd, tmp, &n.addfd, list) {
+	list_for_each_entry_mutable(addfd, &n.addfd, list) {
 		/* The process went away before we got a chance to handle it */
 		addfd->ret = -ESRCH;
 		list_del_init(&addfd->list);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9c2b32c4d755..072231bebf52 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -748,7 +748,7 @@ static void sigqueue_free_ignored(struct task_struct *tsk, struct sigqueue *q)
 /* Remove signals in mask from the pending set and queue. */
 static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct sigpending *s)
 {
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 	sigset_t m;
 
 	lockdep_assert_held(&p->sighand->siglock);
@@ -758,7 +758,7 @@ static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct si
 		return;
 
 	sigandnsets(&s->signal, &s->signal, mask);
-	list_for_each_entry_safe(q, n, &s->list, list) {
+	list_for_each_entry_mutable(q, &s->list, list) {
 		if (sigismember(mask, q->info.si_signo)) {
 			list_del_init(&q->list);
 			sigqueue_free_ignored(p, q);
@@ -1899,12 +1899,12 @@ EXPORT_SYMBOL(kill_pid);
 static void __flush_itimer_signals(struct sigpending *pending)
 {
 	sigset_t signal, retain;
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 
 	signal = pending->signal;
 	sigemptyset(&retain);
 
-	list_for_each_entry_safe(q, n, &pending->list, list) {
+	list_for_each_entry_mutable(q, &pending->list, list) {
 		int sig = q->info.si_signo;
 
 		if (likely(q->info.si_code != SI_TIMER)) {
@@ -2101,7 +2101,6 @@ static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueu
 static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 {
 	struct hlist_head *head = &tsk->signal->ignored_posix_timers;
-	struct hlist_node *tmp;
 	struct k_itimer *tmr;
 
 	if (likely(hlist_empty(head)))
@@ -2114,7 +2113,7 @@ static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 	 * rearmed or not. This cannot be decided here w/o dropping sighand
 	 * lock and creating a loop retry horror show.
 	 */
-	hlist_for_each_entry_safe(tmr, tmp , head, ignored_list) {
+	hlist_for_each_entry_mutable(tmr, head, ignored_list) {
 		struct task_struct *target;
 
 		/*
diff --git a/kernel/smp.c b/kernel/smp.c
index a0bb56bd8dda..305187e50b58 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -544,7 +544,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * First; run all SYNC callbacks, people are waiting for us.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		/* Do we wait until *after* callback? */
 		if (CSD_TYPE(csd) == CSD_TYPE_SYNC) {
 			smp_call_func_t func = csd->func;
@@ -572,7 +572,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * Second; run all !SYNC callbacks.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		int type = CSD_TYPE(csd);
 
 		if (type != CSD_TYPE_TTWU) {
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 2cd0172d0516..08932d4776d1 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -111,7 +111,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 					struct listener_list *listeners)
 {
 	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
-	struct listener *s, *tmp;
+	struct listener *s;
 	struct sk_buff *skb_next, *skb_cur = skb;
 	void *reply = genlmsg_data(genlhdr);
 	int delcount = 0;
@@ -145,7 +145,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 
 	/* Delete invalidated entries */
 	down_write(&listeners->sem);
-	list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+	list_for_each_entry_mutable(s, &listeners->list, list) {
 		if (!s->valid) {
 			list_del(&s->list);
 			kfree(s);
@@ -299,7 +299,7 @@ static void fill_tgid_exit(struct task_struct *tsk)
 static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 {
 	struct listener_list *listeners;
-	struct listener *s, *tmp, *s2;
+	struct listener *s, *s2;
 	unsigned int cpu;
 	int ret = 0;
 
@@ -343,7 +343,7 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 	for_each_cpu(cpu, mask) {
 		listeners = &per_cpu(listener_array, cpu);
 		down_write(&listeners->sem);
-		list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+		list_for_each_entry_mutable(s, &listeners->list, list) {
 			if (s->pid == pid) {
 				list_del(&s->list);
 				kfree(s);
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 0014d163f989..a13eeab8d83f 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -678,7 +678,7 @@ void clockevents_resume(void)
  */
 void tick_offline_cpu(unsigned int cpu)
 {
-	struct clock_event_device *dev, *tmp;
+	struct clock_event_device *dev;
 
 	raw_spin_lock(&clockevents_lock);
 
@@ -689,13 +689,13 @@ void tick_offline_cpu(unsigned int cpu)
 	 * Unregister the clock event devices which were
 	 * released above.
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevents_released, list)
+	list_for_each_entry_mutable(dev, &clockevents_released, list)
 		list_del(&dev->list);
 
 	/*
 	 * Now check whether the CPU has left unused per cpu devices
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
+	list_for_each_entry_mutable(dev, &clockevent_devices, list) {
 		if (cpumask_test_cpu(cpu, dev->cpumask) &&
 		    cpumask_weight(dev->cpumask) == 1 &&
 		    !tick_is_broadcast_device(dev)) {
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index e48c4d379a7c..ac857d7ce4bb 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -776,12 +776,12 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs)
 
 static int __clocksource_watchdog_kthread(void)
 {
-	struct clocksource *cs, *tmp;
+	struct clocksource *cs;
 	unsigned long flags;
 	int select = 0;
 
 	spin_lock_irqsave(&watchdog_lock, flags);
-	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
+	list_for_each_entry_mutable(cs, &watchdog_list, wd_list) {
 		if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
 			list_del_init(&cs->wd_list);
 			clocksource_change_rating(cs, 0);
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 5e633d8750d1..1f2c5533d598 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1296,7 +1296,7 @@ static inline bool posix_cpu_timers_enable_work(struct task_struct *tsk,
 
 static void handle_posix_cpu_timers(struct task_struct *tsk)
 {
-	struct k_itimer *timer, *next;
+	struct k_itimer *timer;
 	unsigned long flags, start;
 	LIST_HEAD(firing);
 
@@ -1369,7 +1369,7 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
 	 * each timer's lock before clearing its firing flag, so no
 	 * timer call will interfere.
 	 */
-	list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
+	list_for_each_entry_mutable(timer, &firing, it.cpu.elist) {
 		bool cpu_firing;
 
 		/*
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 436ba794cc0b..d89307c4adb0 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1085,7 +1085,6 @@ SYSCALL_DEFINE1(timer_delete, timer_t, timer_id)
 void exit_itimers(struct task_struct *tsk)
 {
 	struct hlist_head timers;
-	struct hlist_node *next;
 	struct k_itimer *timer;
 
 	/* Clear restore mode for exec() */
@@ -1099,7 +1098,7 @@ void exit_itimers(struct task_struct *tsk)
 		hlist_move_list(&tsk->signal->posix_timers, &timers);
 
 	/* The timers are not longer accessible via tsk::signal */
-	hlist_for_each_entry_safe(timer, next, &timers, list) {
+	hlist_for_each_entry_mutable(timer, &timers, list) {
 		scoped_guard (spinlock_irq, &timer->it_lock)
 			posix_timer_delete(timer);
 		posix_timer_unhash_and_free(timer);
diff --git a/kernel/torture.c b/kernel/torture.c
index 77cb3589b19f..047dcde729dd 100644
--- a/kernel/torture.c
+++ b/kernel/torture.c
@@ -510,10 +510,9 @@ EXPORT_SYMBOL_GPL(torture_shuffle_task_register);
 static void torture_shuffle_task_unregister_all(void)
 {
 	struct shuffle_task *stp;
-	struct shuffle_task *p;
 
 	mutex_lock(&shuffle_task_mutex);
-	list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) {
+	list_for_each_entry_mutable(stp, &shuffle_task_list, st_l) {
 		list_del(&stp->st_l);
 		kfree(stp);
 	}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 82f8feea6931..7f6d8b287adb 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2276,7 +2276,7 @@ subsys_initcall(send_signal_irq_work_init);
 static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 			    void *module)
 {
-	struct bpf_trace_module *btm, *tmp;
+	struct bpf_trace_module *btm;
 	struct module *mod = module;
 	int ret = 0;
 
@@ -2297,7 +2297,7 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 		}
 		break;
 	case MODULE_STATE_GOING:
-		list_for_each_entry_safe(btm, tmp, &bpf_trace_modules, list) {
+		list_for_each_entry_mutable(btm, &bpf_trace_modules, list) {
 			if (btm->module == module) {
 				list_del(&btm->list);
 				kfree(btm);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f93e34dd2328..422665c687ff 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1252,7 +1252,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 {
 	struct ftrace_func_entry *entry;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int size;
 	int i;
 
@@ -1261,7 +1260,7 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			remove_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1270,7 +1269,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 static void ftrace_hash_clear(struct ftrace_hash *hash)
 {
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	struct ftrace_func_entry *entry;
 	int size = 1 << hash->size_bits;
 	int i;
@@ -1280,7 +1278,7 @@ static void ftrace_hash_clear(struct ftrace_hash *hash)
 
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			free_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1296,14 +1294,14 @@ static void free_ftrace_mod(struct ftrace_mod_load *ftrace_mod)
 
 static void clear_ftrace_mod_list(struct list_head *head)
 {
-	struct ftrace_mod_load *p, *n;
+	struct ftrace_mod_load *p;
 
 	/* stack tracer isn't supported yet */
 	if (!head)
 		return;
 
 	mutex_lock(&ftrace_lock);
-	list_for_each_entry_safe(p, n, head, list)
+	list_for_each_entry_mutable(p, head, list)
 		free_ftrace_mod(p);
 	mutex_unlock(&ftrace_lock);
 }
@@ -1451,7 +1449,6 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	struct ftrace_func_entry *entry;
 	struct ftrace_hash *new_hash;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int bits = 0;
 	int i;
 
@@ -1474,7 +1471,7 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	size = 1 << src->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &src->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist) {
+		hlist_for_each_entry_mutable(entry, hhd, hlist) {
 			remove_hash_entry(src, entry);
 			add_ftrace_hash_entry(new_hash, entry);
 		}
@@ -3327,7 +3324,6 @@ static int append_hash(struct ftrace_hash **hash, struct ftrace_hash *new_hash,
 static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_hash)
 {
 	struct ftrace_func_entry *entry;
-	struct hlist_node *tmp;
 	int size;
 	int i;
 
@@ -3337,7 +3333,7 @@ static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_ha
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 			if (!__ftrace_lookup_ip(notrace_hash, entry->ip))
 				continue;
 			remove_hash_entry(hash, entry);
@@ -5084,7 +5080,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
 static int cache_mod(struct trace_array *tr,
 		     const char *func, char *module, int enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct list_head *head = enable ? &tr->mod_trace : &tr->mod_notrace;
 
 	guard(mutex)(&ftrace_lock);
@@ -5096,7 +5092,7 @@ static int cache_mod(struct trace_array *tr,
 		func++;
 
 		/* Look to remove this hash */
-		list_for_each_entry_safe(ftrace_mod, n, head, list) {
+		list_for_each_entry_mutable(ftrace_mod, head, list) {
 			if (strcmp(ftrace_mod->module, module) != 0)
 				continue;
 
@@ -5124,7 +5120,7 @@ static int cache_mod(struct trace_array *tr,
 static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 			     char *mod, bool enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct ftrace_hash **orig_hash, *new_hash;
 	LIST_HEAD(process_mods);
 	char *func;
@@ -5143,7 +5139,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_lock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, head, list) {
+	list_for_each_entry_mutable(ftrace_mod, head, list) {
 
 		if (strcmp(ftrace_mod->module, mod) != 0)
 			continue;
@@ -5165,7 +5161,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, &process_mods, list) {
+	list_for_each_entry_mutable(ftrace_mod, &process_mods, list) {
 
 		func = ftrace_mod->func;
 
@@ -5616,7 +5612,6 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 	struct ftrace_hash **orig_hash;
 	struct ftrace_hash *old_hash;
 	struct ftrace_hash *hash = NULL;
-	struct hlist_node *tmp;
 	struct hlist_head hhd;
 	char str[KSYM_SYMBOL_LEN];
 	int count = 0;
@@ -5677,7 +5672,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 
 			if (func_g.search) {
 				kallsyms_lookup(entry->ip, NULL, NULL,
@@ -5715,7 +5710,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 				       &old_hash_ops);
 	synchronize_rcu();
 
-	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
+	hlist_for_each_entry_mutable(entry, &hhd, hlist) {
 		hlist_del(&entry->hlist);
 		if (probe_ops->free)
 			probe_ops->free(probe_ops, tr, entry->ip, probe->data);
@@ -5738,9 +5733,9 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 void clear_ftrace_function_probes(struct trace_array *tr)
 {
-	struct ftrace_func_probe *probe, *n;
+	struct ftrace_func_probe *probe;
 
-	list_for_each_entry_safe(probe, n, &tr->func_probes, list)
+	list_for_each_entry_mutable(probe, &tr->func_probes, list)
 		unregister_ftrace_function_probe_func(NULL, tr, probe->probe_ops);
 }
 
@@ -5771,11 +5766,11 @@ __init int register_ftrace_command(struct ftrace_func_command *cmd)
  */
 __init int unregister_ftrace_command(struct ftrace_func_command *cmd)
 {
-	struct ftrace_func_command *p, *n;
+	struct ftrace_func_command *p;
 
 	guard(mutex)(&ftrace_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &ftrace_commands, list) {
+	list_for_each_entry_mutable(p, &ftrace_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -7876,10 +7871,9 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 {
 	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
 	struct ftrace_mod_func *mod_func;
-	struct ftrace_mod_func *n;
 
 	/* All the contents of mod_map are now not visible to readers */
-	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
+	list_for_each_entry_mutable(mod_func, &mod_map->funcs, list) {
 		kfree(mod_func->name);
 		list_del(&mod_func->list);
 		kfree(mod_func);
@@ -7891,7 +7885,6 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 void ftrace_release_mod(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
-	struct ftrace_mod_map *n;
 	struct dyn_ftrace *rec;
 	struct ftrace_page **last_pg;
 	struct ftrace_page *tmp_page = NULL;
@@ -7903,7 +7896,7 @@ void ftrace_release_mod(struct module *mod)
 	 * To avoid the UAF problem after the module is unloaded, the
 	 * 'mod_map' resource needs to be released unconditionally.
 	 */
-	list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) {
+	list_for_each_entry_mutable(mod_map, &ftrace_mod_maps, list) {
 		if (mod_map->mod == mod) {
 			list_del_rcu(&mod_map->list);
 			call_rcu(&mod_map->rcu, ftrace_free_mod_map);
@@ -8290,7 +8283,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	struct dyn_ftrace *rec;
 	struct dyn_ftrace key;
 	struct ftrace_mod_map *mod_map = NULL;
-	struct ftrace_init_func *func, *func_next;
+	struct ftrace_init_func *func;
 	LIST_HEAD(clear_hash);
 
 	key.ip = start;
@@ -8341,7 +8334,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	}
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(func, func_next, &clear_hash, list) {
+	list_for_each_entry_mutable(func, &clear_hash, list) {
 		clear_func_from_hashes(func);
 		kfree(func);
 	}
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 56a328e94395..24b2deb1f7a6 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2362,7 +2362,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 {
 	struct trace_buffer *buffer = cpu_buffer->buffer;
 	struct ring_buffer_cpu_meta *meta = NULL;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	bool user_thread = current->mm != NULL;
 	struct ring_buffer_desc *desc = NULL;
 	long i;
@@ -2450,7 +2450,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 	return 0;
 
 free_pages:
-	list_for_each_entry_safe(bpage, tmp, pages, list) {
+	list_for_each_entry_mutable(bpage, pages, list) {
 		list_del_init(&bpage->list);
 		free_buffer_page(bpage);
 	}
@@ -2609,7 +2609,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
 static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct list_head *head = cpu_buffer->pages;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 
 	irq_work_sync(&cpu_buffer->irq_work.work);
 
@@ -2621,7 +2621,7 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 	if (head) {
 		rb_head_page_deactivate(cpu_buffer);
 
-		list_for_each_entry_safe(bpage, tmp, head, list) {
+		list_for_each_entry_mutable(bpage, head, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3163,9 +3163,9 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)
 
 	/* free pages if they weren't inserted */
 	if (!success) {
-		struct buffer_page *bpage, *tmp;
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					 list) {
+		struct buffer_page *bpage;
+
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3395,7 +3395,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 
  out_err:
 	for_each_buffer_cpu(buffer, cpu) {
-		struct buffer_page *bpage, *tmp;
+		struct buffer_page *bpage;
 
 		cpu_buffer = buffer->buffers[cpu];
 		cpu_buffer->nr_pages_to_update = 0;
@@ -3403,8 +3403,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 		if (list_empty(&cpu_buffer->new_pages))
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 
@@ -7316,7 +7315,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_subbuf_order_get);
 int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	int old_order, old_size;
 	int nr_pages;
 	int psize;
@@ -7436,7 +7435,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 		/* Free old sub buffers */
-		list_for_each_entry_safe(bpage, tmp, &old_pages, list) {
+		list_for_each_entry_mutable(bpage, &old_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -7461,7 +7460,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		if (!cpu_buffer->nr_pages_to_update)
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages, list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 1146b83b711a..f1049850e986 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1380,7 +1380,7 @@ static int do_run_tracer_selftest(struct tracer *type)
 
 static __init int init_trace_selftests(void)
 {
-	struct trace_selftests *p, *n;
+	struct trace_selftests *p;
 	struct tracer *t, **last;
 	int ret;
 
@@ -1394,7 +1394,7 @@ static __init int init_trace_selftests(void)
 	pr_info("Running postponed tracer tests:\n");
 
 	tracing_selftest_running = true;
-	list_for_each_entry_safe(p, n, &postponed_selftests, list) {
+	list_for_each_entry_mutable(p, &postponed_selftests, list) {
 		/* This loop can take minutes when sanitizers are enabled, so
 		 * lets make sure we allow RCU processing.
 		 */
@@ -1434,11 +1434,11 @@ static void __init apply_trace_boot_options(void);
 
 static void free_tracers(struct trace_array *tr)
 {
-	struct tracers *t, *n;
+	struct tracers *t;
 
 	lockdep_assert_held(&trace_types_lock);
 
-	list_for_each_entry_safe(t, n, &tr->tracers, list) {
+	list_for_each_entry_mutable(t, &tr->tracers, list) {
 		list_del(&t->list);
 		kfree(t->flags);
 		kfree(t);
@@ -6906,11 +6906,11 @@ void tracing_log_err(struct trace_array *tr,
 
 static void clear_tracing_err_log(struct trace_array *tr)
 {
-	struct tracing_log_err *err, *next;
+	struct tracing_log_err *err;
 
 	guard(mutex)(&tracing_err_log_lock);
 
-	list_for_each_entry_safe(err, next, &tr->err_log, list) {
+	list_for_each_entry_mutable(err, &tr->err_log, list) {
 		list_del(&err->list);
 		free_tracing_log_err(err);
 	}
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index c4dfbc293bae..9e076106bee7 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 		return -EINVAL;
 
 	mutex_lock(&event_mutex);
-	for_each_dyn_event_safe(pos, n) {
+	for_each_dyn_event_safe(pos) {
 		if (type && type != pos->ops)
 			continue;
 		if (!pos->ops->match(system, event,
@@ -207,7 +207,7 @@ static const struct seq_operations dyn_event_seq_op = {
  */
 int dyn_events_release_all(struct dyn_event_operations *type)
 {
-	struct dyn_event *ev, *tmp;
+	struct dyn_event *ev;
 	int ret = 0;
 
 	mutex_lock(&event_mutex);
@@ -219,7 +219,7 @@ int dyn_events_release_all(struct dyn_event_operations *type)
 			goto out;
 		}
 	}
-	for_each_dyn_event_safe(ev, tmp) {
+	for_each_dyn_event_safe(ev) {
 		if (type && ev->ops != type)
 			continue;
 		ret = ev->ops->free(ev);
diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
index beee3f8d7544..a4dc0812284f 100644
--- a/kernel/trace/trace_dynevent.h
+++ b/kernel/trace/trace_dynevent.h
@@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
 /*
  * for_each_dyn_event	-	iterate over the dyn_event list safely
  * @pos:	the struct dyn_event * to use as a loop cursor
- * @n:		the struct dyn_event * to use as temporary storage
  */
-#define for_each_dyn_event_safe(pos, n)	\
-	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
+#define for_each_dyn_event_safe(pos)	\
+	list_for_each_entry_mutable(pos, &dyn_event_list, list)
 
 extern void dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen,
 			      enum dynevent_type type,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c46e623e7e0d..a34fb3e688d5 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -75,8 +75,7 @@ static int system_refcount_dec(struct event_subsystem *system)
 
 #define do_for_each_event_file_safe(tr, file)			\
 	list_for_each_entry(tr, &ftrace_trace_arrays, list) {	\
-		struct trace_event_file *___n;				\
-		list_for_each_entry_safe(file, ___n, &tr->events, list)
+		list_for_each_entry_mutable(file, &tr->events, list)
 
 #define while_for_each_event_file()		\
 	}
@@ -219,11 +218,11 @@ static int trace_define_common_fields(void)
 
 static void trace_destroy_fields(struct trace_event_call *call)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head;
 
 	head = trace_get_fields(call);
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kmem_cache_free(field_cachep, field);
 	}
@@ -928,9 +927,9 @@ static void free_event_mod(struct event_mod_load *event_mod)
 
 static void clear_mod_events(struct trace_array *tr)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		free_event_mod(event_mod);
 	}
 }
@@ -938,10 +937,10 @@ static void clear_mod_events(struct trace_array *tr)
 static int remove_cache_mod(struct trace_array *tr, const char *mod,
 			    const char *match, const char *system, const char *event)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 	int ret = -EINVAL;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod) != 0)
 			continue;
 
@@ -3557,7 +3556,7 @@ static void update_event_fields(struct trace_event_call *call,
 /* Update all events for replacing eval and sanitizing */
 void trace_event_update_all(struct trace_eval_map **map, int len)
 {
-	struct trace_event_call *call, *p;
+	struct trace_event_call *call;
 	const char *last_system = NULL;
 	bool first = false;
 	bool updated;
@@ -3565,7 +3564,7 @@ void trace_event_update_all(struct trace_eval_map **map, int len)
 	int i;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
 			first = true;
@@ -3892,9 +3891,9 @@ EXPORT_SYMBOL_GPL(trace_remove_event_call);
 #ifdef CONFIG_MODULES
 static void update_mod_cache(struct trace_array *tr, struct module *mod)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod->name) != 0)
 			continue;
 
@@ -3940,18 +3939,18 @@ static void trace_module_add_events(struct module *mod)
 
 static void trace_module_remove_events(struct module *mod)
 {
-	struct trace_event_call *call, *p;
-	struct module_string *modstr, *m;
+	struct trace_event_call *call;
+	struct module_string *modstr;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
 			continue;
 		if (call->module == mod)
 			__trace_remove_event_call(call);
 	}
 	/* Check for any strings allocated for this module */
-	list_for_each_entry_safe(modstr, m, &module_strings, next) {
+	list_for_each_entry_mutable(modstr, &module_strings, next) {
 		if (modstr->module != mod)
 			continue;
 		list_del(&modstr->next);
@@ -4483,9 +4482,9 @@ void __trace_early_add_events(struct trace_array *tr)
 static void
 __trace_remove_event_dirs(struct trace_array *tr)
 {
-	struct trace_event_file *file, *next;
+	struct trace_event_file *file;
 
-	list_for_each_entry_safe(file, next, &tr->events, list)
+	list_for_each_entry_mutable(file, &tr->events, list)
 		remove_event_file_dir(file);
 }
 
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 609325f57942..d82128084a87 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1352,9 +1352,9 @@ struct filter_head {
 
 static void free_filter_list(struct filter_head *filter_list)
 {
-	struct filter_list *filter_item, *tmp;
+	struct filter_list *filter_item;
 
-	list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) {
+	list_for_each_entry_mutable(filter_item, &filter_list->list, list) {
 		__free_filter(filter_item->filter);
 		list_del(&filter_item->list);
 		kfree(filter_item);
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 82ce492ab268..ff6016acab20 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -6765,7 +6765,7 @@ static bool hist_file_check_refs(struct trace_event_file *file)
 
 static void hist_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 	struct hist_trigger_data *hist_data;
 	struct synth_event *se;
 	const char *se_name;
@@ -6775,7 +6775,7 @@ static void hist_unreg_all(struct trace_event_file *file)
 	if (hist_file_check_refs(file))
 		return;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
 			hist_data = test->private_data;
 			list_del_rcu(&test->list);
@@ -7002,9 +7002,9 @@ hist_enable_trigger(struct event_trigger_data *data,
 
 static void hist_enable_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
 			list_del_rcu(&test->list);
 			update_cond_flag(file);
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 655db2e82513..8654cd83f64d 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -40,7 +40,7 @@ static void trigger_create_kthread_locked(void)
 
 static void trigger_data_free_queued_locked(void)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	lockdep_assert_held(&trigger_data_kthread_mutex);
@@ -51,14 +51,14 @@ static void trigger_data_free_queued_locked(void)
 
 	tracepoint_synchronize_unregister();
 
-	llist_for_each_entry_safe(data, tmp, llnodes, llist)
+	llist_for_each_entry_mutable(data, llnodes, llist)
 		kfree(data);
 }
 
 /* Bulk garbage collection of event_trigger_data elements */
 static int trigger_kthread_fn(void *ignore)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	/* Once this task starts, it lives forever */
@@ -74,7 +74,7 @@ static int trigger_kthread_fn(void *ignore)
 		/* make sure current triggers exit before free */
 		tracepoint_synchronize_unregister();
 
-		llist_for_each_entry_safe(data, tmp, llnodes, llist)
+		llist_for_each_entry_mutable(data, llnodes, llist)
 			kfree(data);
 	}
 
@@ -477,11 +477,11 @@ __init int register_event_command(struct event_command *cmd)
  */
 __init int unregister_event_command(struct event_command *cmd)
 {
-	struct event_command *p, *n;
+	struct event_command *p;
 
 	guard(mutex)(&trigger_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &trigger_commands, list) {
+	list_for_each_entry_mutable(p, &trigger_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -632,8 +632,9 @@ clear_event_triggers(struct trace_array *tr)
 	struct trace_event_file *file;
 
 	list_for_each_entry(file, &tr->events, list) {
-		struct event_trigger_data *data, *n;
-		list_for_each_entry_safe(data, n, &file->triggers, list) {
+		struct event_trigger_data *data;
+
+		list_for_each_entry_mutable(data, &file->triggers, list) {
 			trace_event_trigger_enable_disable(file, 0);
 			list_del_rcu(&data->list);
 			if (data->cmd_ops->free)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index c4ba484f7b38..090d645eebf0 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -761,9 +761,9 @@ static struct user_event_mm *current_user_event_mm(void)
 
 static void user_event_mm_destroy(struct user_event_mm *mm)
 {
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link)
 		user_event_enabler_destroy(enabler, false);
 
 	mmdrop(mm->mm);
@@ -1085,10 +1085,10 @@ static int user_field_size(const char *type)
 
 static void user_event_destroy_validators(struct user_event *user)
 {
-	struct user_event_validator *validator, *next;
+	struct user_event_validator *validator;
 	struct list_head *head = &user->validators;
 
-	list_for_each_entry_safe(validator, next, head, user_event_link) {
+	list_for_each_entry_mutable(validator, head, user_event_link) {
 		list_del(&validator->user_event_link);
 		kfree(validator);
 	}
@@ -1096,10 +1096,10 @@ static void user_event_destroy_validators(struct user_event *user)
 
 static void user_event_destroy_fields(struct user_event *user)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head = &user->fields;
 
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kfree(field);
 	}
@@ -2611,7 +2611,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 {
 	struct user_unreg __user *ureg = (struct user_unreg __user *)uarg;
 	struct user_event_mm *mm = current->user_event_mm;
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 	struct user_unreg reg;
 	unsigned long flags;
 	long ret;
@@ -2636,7 +2636,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 	 */
 	mutex_lock(&event_mutex);
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link) {
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link) {
 		if (enabler->addr == reg.disable_addr &&
 		    ENABLE_BIT(enabler) == reg.disable_bit) {
 			set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 856ece13b7dc..3240b1ff7418 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -344,10 +344,10 @@ int register_stat_tracer(struct tracer_stat *trace)
 
 void unregister_stat_tracer(struct tracer_stat *trace)
 {
-	struct stat_session *node, *tmp;
+	struct stat_session *node;
 
 	mutex_lock(&all_stat_sessions_mutex);
-	list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
+	list_for_each_entry_mutable(node, &all_stat_sessions, session_list) {
 		if (node->ts == trace) {
 			list_del(&node->session_list);
 			destroy_session(node);
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
index 870ecd7c63ed..9f1dcd72b756 100644
--- a/kernel/user-return-notifier.c
+++ b/kernel/user-return-notifier.c
@@ -35,11 +35,10 @@ EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
 void fire_user_return_notifiers(void)
 {
 	struct user_return_notifier *urn;
-	struct hlist_node *tmp2;
 	struct hlist_head *head;
 
 	head = &get_cpu_var(return_notifier_list);
-	hlist_for_each_entry_safe(urn, tmp2, head, link)
+	hlist_for_each_entry_mutable(urn, head, link)
 		urn->on_user_return(urn);
 	put_cpu_var(return_notifier_list);
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 78f25afb4a9d..8fbdf1664c38 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1167,7 +1167,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
 	 * Linked worklist will always end before the end of the list,
 	 * use NULL for list head.
 	 */
-	list_for_each_entry_safe_from(work, n, NULL, entry) {
+	list_for_each_entry_mutable_from(work, n, NULL, entry) {
 		list_move_tail(&work->entry, head);
 		if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
 			break;
@@ -1193,7 +1193,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
  *
  * If @nextp is not NULL, it's updated to point to the next work of the last
  * scheduled work. This allows assign_work() to be nested inside
- * list_for_each_entry_safe().
+ * list_for_each_entry_mutable().
  *
  * Returns %true if @work was successfully assigned to @worker. %false if @work
  * was punted to another worker already executing it.
@@ -2912,9 +2912,9 @@ static void detach_dying_workers(struct list_head *cull_list)
 
 static void reap_dying_workers(struct list_head *cull_list)
 {
-	struct worker *worker, *tmp;
+	struct worker *worker;
 
-	list_for_each_entry_safe(worker, tmp, cull_list, entry) {
+	list_for_each_entry_mutable(worker, cull_list, entry) {
 		list_del_init(&worker->entry);
 		kthread_stop_put(worker->task);
 		kfree(worker);
@@ -3550,7 +3550,7 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu
 		work = list_next_entry(cursor, entry);
 
 	/* find the next work item to rescue */
-	list_for_each_entry_safe_from(work, n, &pool->worklist, entry) {
+	list_for_each_entry_mutable_from(work, n, &pool->worklist, entry) {
 		if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) {
 			pwq->stats[PWQ_STAT_RESCUED]++;
 			/* put the cursor for next search */
@@ -4157,7 +4157,7 @@ void __flush_workqueue(struct workqueue_struct *wq)
 		struct wq_flusher *next, *tmp;
 
 		/* complete all the flushers sharing the current flush color */
-		list_for_each_entry_safe(next, tmp, &wq->flusher_queue, list) {
+		list_for_each_entry_mutable(next, &wq->flusher_queue, list) {
 			if (next->flush_color != wq->flush_color)
 				break;
 			list_del_init(&next->list);
@@ -7080,7 +7080,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 	LIST_HEAD(ctxs);
 	int ret = 0;
 	struct workqueue_struct *wq;
-	struct apply_wqattrs_ctx *ctx, *n;
+	struct apply_wqattrs_ctx *ctx;
 
 	lockdep_assert_held(&wq_pool_mutex);
 
@@ -7097,7 +7097,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 		list_add_tail(&ctx->list, &ctxs);
 	}
 
-	list_for_each_entry_safe(ctx, n, &ctxs, list) {
+	list_for_each_entry_mutable(ctx, &ctxs, list) {
 		if (!ret)
 			apply_wqattrs_commit(ctx);
 		apply_wqattrs_cleanup(ctx);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 6/7] initramfs: Use mutable list iterator
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (3 preceding siblings ...)
  2026-06-22  4:28 ` [PATCH v3 5/7] kernel: " Kaitao Cheng
@ 2026-06-22  4:39 ` Kaitao Cheng
  2026-06-22  4:41 ` [PATCH v3 7/7] io_uring: Use mutable list iterators Kaitao Cheng
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:39 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-fsdevel, linux-kernel, Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iterator in dir_utime() requires a temporary cursor even
though the loop body only deletes and frees the current entry.  The
mutable iterator keeps the same removal-safe traversal semantics while
hiding the internal cursor from the call site.

Switch dir_utime() to list_for_each_entry_mutable() and drop the unused
temporary cursor variable.  No functional change is intended.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 init/initramfs.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/init/initramfs.c b/init/initramfs.c
index 20a18fcda48e..e226d7eb1257 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -167,8 +167,9 @@ static void __init dir_add(const char *name, size_t nlen, time64_t mtime)
 
 static void __init dir_utime(void)
 {
-	struct dir_entry *de, *tmp;
-	list_for_each_entry_safe(de, tmp, &dir_list, list) {
+	struct dir_entry *de;
+
+	list_for_each_entry_mutable(de, &dir_list, list) {
 		list_del(&de->list);
 		do_utime(de->name, de->mtime);
 		kfree(de);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 7/7] io_uring: Use mutable list iterators
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (4 preceding siblings ...)
  2026-06-22  4:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator Kaitao Cheng
@ 2026-06-22  4:41 ` Kaitao Cheng
  2026-06-22  4:42 ` [PATCH v3 4/7] block: " Kaitao Cheng
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:41 UTC (permalink / raw)
  To: Jens Axboe; +Cc: io-uring, linux-kernel, Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iterators require callers to provide a temporary cursor
even when the cursor is only used by the iterator itself.  The mutable
iterator variants keep the same removal-safe traversal semantics while
allowing those internal cursors to be hidden from the call sites.

Convert io_uring users of list and hlist safe iterators to the new
mutable helpers.  Drop the now-unused temporary cursor variables where
the loop body does not inspect or reset them.

This is a mechanical cleanup with no intended change in traversal order
or list mutation behavior.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 io_uring/cancel.c    | 6 ++----
 io_uring/poll.c      | 3 +--
 io_uring/rw.c        | 4 ++--
 io_uring/timeout.c   | 8 ++++----
 io_uring/uring_cmd.c | 3 +--
 5 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/io_uring/cancel.c b/io_uring/cancel.c
index 8c6fa6f367e4..2d5b27e64582 100644
--- a/io_uring/cancel.c
+++ b/io_uring/cancel.c
@@ -358,13 +358,12 @@ bool io_cancel_remove_all(struct io_ring_ctx *ctx, struct io_uring_task *tctx,
 			  struct hlist_head *list, bool cancel_all,
 			  bool (*cancel)(struct io_kiocb *))
 {
-	struct hlist_node *tmp;
 	struct io_kiocb *req;
 	bool found = false;
 
 	lockdep_assert_held(&ctx->uring_lock);
 
-	hlist_for_each_entry_safe(req, tmp, list, hash_node) {
+	hlist_for_each_entry_mutable(req, list, hash_node) {
 		if (!io_match_task_safe(req, tctx, cancel_all))
 			continue;
 		hlist_del_init(&req->hash_node);
@@ -379,12 +378,11 @@ int io_cancel_remove(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
 		     unsigned int issue_flags, struct hlist_head *list,
 		     bool (*cancel)(struct io_kiocb *))
 {
-	struct hlist_node *tmp;
 	struct io_kiocb *req;
 	int nr = 0;
 
 	io_ring_submit_lock(ctx, issue_flags);
-	hlist_for_each_entry_safe(req, tmp, list, hash_node) {
+	hlist_for_each_entry_mutable(req, list, hash_node) {
 		if (!io_cancel_req_match(req, cd))
 			continue;
 		if (cancel(req))
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 0204affdc308..2b8d15fe1227 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -734,7 +734,6 @@ __cold bool io_poll_remove_all(struct io_ring_ctx *ctx, struct io_uring_task *tc
 			       bool cancel_all)
 {
 	unsigned nr_buckets = 1U << ctx->cancel_table.hash_bits;
-	struct hlist_node *tmp;
 	struct io_kiocb *req;
 	bool found = false;
 	int i;
@@ -744,7 +743,7 @@ __cold bool io_poll_remove_all(struct io_ring_ctx *ctx, struct io_uring_task *tc
 	for (i = 0; i < nr_buckets; i++) {
 		struct io_hash_bucket *hb = &ctx->cancel_table.hbs[i];
 
-		hlist_for_each_entry_safe(req, tmp, &hb->list, hash_node) {
+		hlist_for_each_entry_mutable(req, &hb->list, hash_node) {
 			if (io_match_task_safe(req, tctx, cancel_all)) {
 				hlist_del_init(&req->hash_node);
 				io_poll_cancel_req(req);
diff --git a/io_uring/rw.c b/io_uring/rw.c
index 63b6519e498c..25b896269e87 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -1326,7 +1326,7 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
 {
 	unsigned int poll_flags = 0;
 	DEFINE_IO_COMP_BATCH(iob);
-	struct io_kiocb *req, *tmp;
+	struct io_kiocb *req;
 	int nr_events = 0;
 
 	/*
@@ -1372,7 +1372,7 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
 	if (!rq_list_empty(&iob.req_list))
 		iob.complete(&iob);
 
-	list_for_each_entry_safe(req, tmp, &ctx->iopoll_list, iopoll_node) {
+	list_for_each_entry_mutable(req, &ctx->iopoll_list, iopoll_node) {
 		/* order with io_complete_rw_iopoll(), e.g. ->result updates */
 		if (!smp_load_acquire(&req->iopoll_completed))
 			continue;
diff --git a/io_uring/timeout.c b/io_uring/timeout.c
index c4dd26cf342d..63671231cb08 100644
--- a/io_uring/timeout.c
+++ b/io_uring/timeout.c
@@ -164,14 +164,14 @@ static void io_kill_timeout(struct io_kiocb *req, struct list_head *list)
 
 __cold void io_flush_timeouts(struct io_ring_ctx *ctx)
 {
-	struct io_timeout *timeout, *tmp;
+	struct io_timeout *timeout;
 	LIST_HEAD(list);
 	u32 seq;
 
 	raw_spin_lock_irq(&ctx->timeout_lock);
 	seq = READ_ONCE(ctx->cached_cq_tail) - atomic_read(&ctx->cq_timeouts);
 
-	list_for_each_entry_safe(timeout, tmp, &ctx->timeout_list, list) {
+	list_for_each_entry_mutable(timeout, &ctx->timeout_list, list) {
 		struct io_kiocb *req = cmd_to_io_kiocb(timeout);
 		u32 events_needed, events_got;
 
@@ -733,7 +733,7 @@ static bool io_match_task(struct io_kiocb *head, struct io_uring_task *tctx,
 __cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct io_uring_task *tctx,
 			     bool cancel_all)
 {
-	struct io_timeout *timeout, *tmp;
+	struct io_timeout *timeout;
 	LIST_HEAD(list);
 
 	/*
@@ -742,7 +742,7 @@ __cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct io_uring_task *tctx
 	 */
 	spin_lock(&ctx->completion_lock);
 	raw_spin_lock_irq(&ctx->timeout_lock);
-	list_for_each_entry_safe(timeout, tmp, &ctx->timeout_list, list) {
+	list_for_each_entry_mutable(timeout, &ctx->timeout_list, list) {
 		struct io_kiocb *req = cmd_to_io_kiocb(timeout);
 
 		if (io_match_task(req, tctx, cancel_all))
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 7b25dcd9d05f..ce6f4fe93b20 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -49,13 +49,12 @@ void io_uring_cmd_cleanup(struct io_kiocb *req)
 bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
 				   struct io_uring_task *tctx, bool cancel_all)
 {
-	struct hlist_node *tmp;
 	struct io_kiocb *req;
 	bool ret = false;
 
 	lockdep_assert_held(&ctx->uring_lock);
 
-	hlist_for_each_entry_safe(req, tmp, &ctx->cancelable_uring_cmd,
+	hlist_for_each_entry_mutable(req, &ctx->cancelable_uring_cmd,
 			hash_node) {
 		struct io_uring_cmd *cmd = io_kiocb_to_cmd(req,
 				struct io_uring_cmd);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 4/7] block: Use mutable list iterators
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (5 preceding siblings ...)
  2026-06-22  4:41 ` [PATCH v3 7/7] io_uring: Use mutable list iterators Kaitao Cheng
@ 2026-06-22  4:42 ` Kaitao Cheng
  2026-06-22  5:28 ` [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Alexei Starovoitov
  2026-06-22  8:37 ` Jani Nikula
  8 siblings, 0 replies; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  4:42 UTC (permalink / raw)
  To: Yu Kuai, Jens Axboe, Tejun Heo, Josef Bacik,
	Richard Russon (FlatCap), Jonathan Derrick
  Cc: linux-block, linux-kernel, cgroups, linux-ntfs-dev, Kaitao Cheng

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iterators require callers to provide a temporary cursor
even when the cursor is only used by the iterator itself.  The mutable
iterator variants keep the same removal-safe traversal semantics while
allowing those internal cursors to be hidden from the call sites.

Convert block users of list, hlist and llist safe iterators to the new
mutable helpers.  Drop the now-unused temporary cursor variables where
the loop body does not inspect or reset them.

This is a mechanical cleanup with no intended change in traversal order
or list mutation behavior.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 block/bfq-iosched.c    | 17 +++++++----------
 block/blk-cgroup.c     | 12 ++++++------
 block/blk-flush.c      |  4 ++--
 block/blk-iocost.c     | 18 +++++++++---------
 block/blk-mq.c         |  8 ++++----
 block/blk-throttle.c   |  4 ++--
 block/kyber-iosched.c  |  4 ++--
 block/partitions/ldm.c |  8 ++++----
 block/sed-opal.c       |  4 ++--
 9 files changed, 38 insertions(+), 41 deletions(-)

diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 141c602d5e85..78e32ba0553d 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -1209,9 +1209,8 @@ static int bfqq_process_refs(struct bfq_queue *bfqq)
 static void bfq_reset_burst_list(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 {
 	struct bfq_queue *item;
-	struct hlist_node *n;
 
-	hlist_for_each_entry_safe(item, n, &bfqd->burst_list, burst_list_node)
+	hlist_for_each_entry_mutable(item, &bfqd->burst_list, burst_list_node)
 		hlist_del_init(&item->burst_list_node);
 
 	/*
@@ -1236,7 +1235,6 @@ static void bfq_add_to_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 
 	if (bfqd->burst_size == bfqd->bfq_large_burst_thresh) {
 		struct bfq_queue *pos, *bfqq_item;
-		struct hlist_node *n;
 
 		/*
 		 * Enough queues have been activated shortly after each
@@ -1260,8 +1258,8 @@ static void bfq_add_to_burst(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 		 * belonging to a large burst. So the burst list is not
 		 * needed any more. Remove it.
 		 */
-		hlist_for_each_entry_safe(pos, n, &bfqd->burst_list,
-					  burst_list_node)
+		hlist_for_each_entry_mutable(pos, &bfqd->burst_list,
+					     burst_list_node)
 			hlist_del_init(&pos->burst_list_node);
 	} else /*
 		* Burst not yet large: add bfqq to the burst list. Do
@@ -5330,7 +5328,6 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
 void bfq_put_queue(struct bfq_queue *bfqq)
 {
 	struct bfq_queue *item;
-	struct hlist_node *n;
 	struct bfq_group *bfqg = bfqq_group(bfqq);
 
 	bfq_log_bfqq(bfqq->bfqd, bfqq, "put_queue: %p %d", bfqq, bfqq->ref);
@@ -5391,8 +5388,8 @@ void bfq_put_queue(struct bfq_queue *bfqq)
 		hlist_del_init(&bfqq->woken_list_node);
 
 	/* reset waker for all queues in woken list */
-	hlist_for_each_entry_safe(item, n, &bfqq->woken_list,
-				  woken_list_node) {
+	hlist_for_each_entry_mutable(item, &bfqq->woken_list,
+				     woken_list_node) {
 		item->waker_bfqq = NULL;
 		hlist_del_init(&item->woken_list_node);
 	}
@@ -7141,13 +7138,13 @@ static void bfq_depth_updated(struct request_queue *q)
 static void bfq_exit_queue(struct elevator_queue *e)
 {
 	struct bfq_data *bfqd = e->elevator_data;
-	struct bfq_queue *bfqq, *n;
+	struct bfq_queue *bfqq;
 	unsigned int actuator;
 
 	hrtimer_cancel(&bfqd->idle_slice_timer);
 
 	spin_lock_irq(&bfqd->lock);
-	list_for_each_entry_safe(bfqq, n, &bfqd->idle_list, bfqq_list)
+	list_for_each_entry_mutable(bfqq, &bfqd->idle_list, bfqq_list)
 		bfq_deactivate_bfqq(bfqd, bfqq, false, false);
 	spin_unlock_irq(&bfqd->lock);
 
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 3093c1c03902..ced900019f2e 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -997,7 +997,7 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu)
 {
 	struct llist_head *lhead = per_cpu_ptr(blkcg->lhead, cpu);
 	struct llist_node *lnode;
-	struct blkg_iostat_set *bisc, *next_bisc;
+	struct blkg_iostat_set *bisc;
 	unsigned long flags;
 
 	rcu_read_lock();
@@ -1017,17 +1017,17 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu)
 	/*
 	 * Iterate only the iostat_cpu's queued in the lockless list.
 	 */
-	llist_for_each_entry_safe(bisc, next_bisc, lnode, lnode) {
+	llist_for_each_entry_mutable(bisc, lnode, lnode) {
 		struct blkcg_gq *blkg = bisc->blkg;
 		struct blkcg_gq *parent = blkg->parent;
 		struct blkg_iostat cur;
 		unsigned int seq;
 
 		/*
-		 * Order assignment of `next_bisc` from `bisc->lnode.next` in
-		 * llist_for_each_entry_safe and clearing `bisc->lqueued` for
-		 * avoiding to assign `next_bisc` with new next pointer added
-		 * in blk_cgroup_bio_start() in case of re-ordering.
+		 * Order the iterator's internal `bisc->lnode.next` load before
+		 * clearing `bisc->lqueued`, so the iterator can't pick up a new
+		 * next pointer added in blk_cgroup_bio_start() in case of
+		 * re-ordering.
 		 *
 		 * The pair barrier is implied in llist_add() in blk_cgroup_bio_start().
 		 */
diff --git a/block/blk-flush.c b/block/blk-flush.c
index 403a46c86411..20654c2103f2 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -204,7 +204,7 @@ static enum rq_end_io_ret flush_end_io(struct request *flush_rq,
 {
 	struct request_queue *q = flush_rq->q;
 	struct list_head *running;
-	struct request *rq, *n;
+	struct request *rq;
 	unsigned long flags = 0;
 	struct blk_flush_queue *fq = blk_get_flush_queue(flush_rq->mq_ctx);
 
@@ -243,7 +243,7 @@ static enum rq_end_io_ret flush_end_io(struct request *flush_rq,
 	fq->flush_running_idx ^= 1;
 
 	/* and push the waiting requests to the next stage */
-	list_for_each_entry_safe(rq, n, running, queuelist) {
+	list_for_each_entry_mutable(rq, running, queuelist) {
 		unsigned int seq = blk_flush_cur_seq(rq);
 
 		BUG_ON(seq != REQ_FSEQ_PREFLUSH && seq != REQ_FSEQ_POSTFLUSH);
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 563cc7dcf348..2ca18e52bc13 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -1718,7 +1718,7 @@ static void iocg_flush_stat_leaf(struct ioc_gq *iocg, struct ioc_now *now)
 static void iocg_flush_stat(struct list_head *target_iocgs, struct ioc_now *now)
 {
 	LIST_HEAD(inner_walk);
-	struct ioc_gq *iocg, *tiocg;
+	struct ioc_gq *iocg;
 
 	/* flush leaves and build inner node walk list */
 	list_for_each_entry(iocg, target_iocgs, active_list) {
@@ -1727,7 +1727,7 @@ static void iocg_flush_stat(struct list_head *target_iocgs, struct ioc_now *now)
 	}
 
 	/* keep flushing upwards by walking the inner list backwards */
-	list_for_each_entry_safe_reverse(iocg, tiocg, &inner_walk, walk_list) {
+	list_for_each_entry_mutable_reverse(iocg, &inner_walk, walk_list) {
 		iocg_flush_stat_upward(iocg);
 		list_del_init(&iocg->walk_list);
 	}
@@ -1848,7 +1848,7 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now)
 {
 	LIST_HEAD(over_hwa);
 	LIST_HEAD(inner_walk);
-	struct ioc_gq *iocg, *tiocg, *root_iocg;
+	struct ioc_gq *iocg, *root_iocg;
 	u32 after_sum, over_sum, over_target, gamma;
 
 	/*
@@ -1884,7 +1884,7 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now)
 		over_target = 0;
 	}
 
-	list_for_each_entry_safe(iocg, tiocg, &over_hwa, walk_list) {
+	list_for_each_entry_mutable(iocg, &over_hwa, walk_list) {
 		if (over_target)
 			iocg->hweight_after_donation =
 				div_u64((u64)iocg->hweight_after_donation *
@@ -2055,7 +2055,7 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now)
 	}
 
 	/* walk list should be dissolved after use */
-	list_for_each_entry_safe(iocg, tiocg, &inner_walk, walk_list)
+	list_for_each_entry_mutable(iocg, &inner_walk, walk_list)
 		list_del_init(&iocg->walk_list);
 }
 
@@ -2166,9 +2166,9 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
 static int ioc_check_iocgs(struct ioc *ioc, struct ioc_now *now)
 {
 	int nr_debtors = 0;
-	struct ioc_gq *iocg, *tiocg;
+	struct ioc_gq *iocg;
 
-	list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
+	list_for_each_entry_mutable(iocg, &ioc->active_iocgs, active_list) {
 		if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
 		    !iocg->delay && !iocg_is_idle(iocg))
 			continue;
@@ -2234,7 +2234,7 @@ static int ioc_check_iocgs(struct ioc *ioc, struct ioc_now *now)
 static void ioc_timer_fn(struct timer_list *timer)
 {
 	struct ioc *ioc = container_of(timer, struct ioc, timer);
-	struct ioc_gq *iocg, *tiocg;
+	struct ioc_gq *iocg;
 	struct ioc_now now;
 	LIST_HEAD(surpluses);
 	int nr_debtors, nr_shortages = 0, nr_lagging = 0;
@@ -2378,7 +2378,7 @@ static void ioc_timer_fn(struct timer_list *timer)
 	commit_weights(ioc);
 
 	/* surplus list should be dissolved after use */
-	list_for_each_entry_safe(iocg, tiocg, &surpluses, surplus_list)
+	list_for_each_entry_mutable(iocg, &surpluses, surplus_list)
 		list_del_init(&iocg->surplus_list);
 
 	/*
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 88cb5acc4f39..2daed45ad4e7 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1216,9 +1216,9 @@ EXPORT_SYMBOL_GPL(blk_mq_end_request_batch);
 static void blk_complete_reqs(struct llist_head *list)
 {
 	struct llist_node *entry = llist_reverse_order(llist_del_all(list));
-	struct request *rq, *next;
+	struct request *rq;
 
-	llist_for_each_entry_safe(rq, next, entry, ipi_list)
+	llist_for_each_entry_mutable(rq, entry, ipi_list)
 		rq->q->mq_ops->complete(rq);
 }
 
@@ -4383,14 +4383,14 @@ static int blk_mq_alloc_ctxs(struct request_queue *q)
  */
 void blk_mq_release(struct request_queue *q)
 {
-	struct blk_mq_hw_ctx *hctx, *next;
+	struct blk_mq_hw_ctx *hctx;
 	unsigned long i;
 
 	queue_for_each_hw_ctx(q, hctx, i)
 		WARN_ON_ONCE(hctx && list_empty(&hctx->hctx_list));
 
 	/* all hctx are in .unused_hctx_list now */
-	list_for_each_entry_safe(hctx, next, &q->unused_hctx_list, hctx_list) {
+	list_for_each_entry_mutable(hctx, &q->unused_hctx_list, hctx_list) {
 		list_del_init(&hctx->hctx_list);
 		kobject_put(&hctx->kobj);
 	}
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 47052ba21d1b..1dd4901f00f3 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -1686,10 +1686,10 @@ static void tg_cancel_writeback_bios(struct throtl_grp *tg,
 	tg->flags |= THROTL_TG_CANCELING;
 
 	for (rw = READ; rw <= WRITE; rw++) {
-		struct throtl_qnode *qn, *tmp;
+		struct throtl_qnode *qn;
 		unsigned int nr_bios = 0;
 
-		list_for_each_entry_safe(qn, tmp, &sq->queued[rw], node) {
+		list_for_each_entry_mutable(qn, &sq->queued[rw], node) {
 			struct bio *bio;
 
 			while ((bio = bio_list_pop(&qn->bios_iops))) {
diff --git a/block/kyber-iosched.c b/block/kyber-iosched.c
index 971818bcdc9d..1a509666b861 100644
--- a/block/kyber-iosched.c
+++ b/block/kyber-iosched.c
@@ -578,9 +578,9 @@ static void kyber_insert_requests(struct blk_mq_hw_ctx *hctx,
 				  blk_insert_t flags)
 {
 	struct kyber_hctx_data *khd = hctx->sched_data;
-	struct request *rq, *next;
+	struct request *rq;
 
-	list_for_each_entry_safe(rq, next, rq_list, queuelist) {
+	list_for_each_entry_mutable(rq, rq_list, queuelist) {
 		unsigned int sched_domain = kyber_sched_domain(rq->cmd_flags);
 		struct kyber_ctx_queue *kcq = &khd->kcqs[rq->mq_ctx->index_hw[hctx->type]];
 		struct list_head *head = &kcq->rq_list[sched_domain];
diff --git a/block/partitions/ldm.c b/block/partitions/ldm.c
index c0bdcae58a3e..459f72f2148a 100644
--- a/block/partitions/ldm.c
+++ b/block/partitions/ldm.c
@@ -1285,11 +1285,11 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
  */
 static void ldm_frag_free (struct list_head *list)
 {
-	struct list_head *item, *tmp;
+	struct list_head *item;
 
 	BUG_ON (!list);
 
-	list_for_each_safe (item, tmp, list)
+	list_for_each_mutable(item, list)
 		kfree (list_entry (item, struct frag, list));
 }
 
@@ -1400,11 +1400,11 @@ static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base,
  */
 static void ldm_free_vblks (struct list_head *lh)
 {
-	struct list_head *item, *tmp;
+	struct list_head *item;
 
 	BUG_ON (!lh);
 
-	list_for_each_safe (item, tmp, lh)
+	list_for_each_mutable(item, lh)
 		kfree (list_entry (item, struct vblk, list));
 }
 
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 79b290d9458a..5bf9ebce8452 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -2573,10 +2573,10 @@ static int check_opal_support(struct opal_dev *dev)
 static void clean_opal_dev(struct opal_dev *dev)
 {
 
-	struct opal_suspend_data *suspend, *next;
+	struct opal_suspend_data *suspend;
 
 	mutex_lock(&dev->dev_lock);
-	list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
+	list_for_each_entry_mutable(suspend, &dev->unlk_lst, node) {
 		list_del(&suspend->node);
 		kfree(suspend);
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 3/7] mm: Use mutable list iterators
  2026-06-22  4:15 ` [PATCH v3 3/7] mm: Use mutable list iterators Kaitao Cheng
@ 2026-06-22  4:57   ` sashiko-bot
  0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-22  4:57 UTC (permalink / raw)
  To: Kaitao Cheng; +Cc: hannes, mkoutny, damon, tj

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] An unused `folio2` pointer was mistakenly added to `struct rmap_walk_arg`.
--

commit 8a79df314e3109d54ebea51144ac490e11160cb4
Author: Kaitao Cheng <chengkaitao@kylinos.cn>

mm: Use mutable list iterators

This patch mechanically converts mm users of safe list iterators to new mutable 
helpers. It drops temporary cursor variables that are no longer explicitly 
needed by the calling loops.

> diff --git a/mm/migrate.c b/mm/migrate.c
> index d9b23909d716c..acc7925d1d1b8 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
[ ... ]
> @@ -336,7 +335,7 @@ static bool try_to_map_unused_to_zeropage(struct page_vma_mapped_walk *pvmw,
>  }
>  
>  struct rmap_walk_arg {
> -	struct folio *folio;
> +	struct folio *folio, *folio2;
>  	bool map_unused_to_zeropage;
>  };

[Severity: Low]
Is folio2 actually used anywhere in struct rmap_walk_arg? It looks like this 
was mistakenly added as a leftover artifact of a mechanical search-and-replace 
when cleaning up the local cursor variables in nearby functions.

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622040533.29824-1-kaitao.cheng@linux.dev?part=3

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/7] kernel: Use mutable list iterators
  2026-06-22  4:28 ` [PATCH v3 5/7] kernel: " Kaitao Cheng
@ 2026-06-22  5:22     ` bot+bpf-ci
  2026-06-22 19:03   ` Eduard Zingerman
  1 sibling, 0 replies; 19+ messages in thread
From: bot+bpf-ci @ 2026-06-22  5:22 UTC (permalink / raw)
  To: kaitao.cheng, paul, eparis, ast, daniel, andrii, eddyz87, memxor,
	davem, kuba, hawk, john.fastabend, tj, hannes, mkoutny, dev,
	mripard, natalie.vock, peterz, mingo, acme, namhyung, mhiramat,
	oleg, oberpar, akpm, baoquan.he, rppt, pasha.tatashin, pratyush,
	naveen, jpoimboe, jikos, mbenes, pmladek, will, boqun, mcgrof,
	petr.pavlu, da.gomez, samitolvanen, steffen.klassert,
	daniel.m.jordan, rafael, dave, paulmck, josh, frederic,
	neeraj.upadhyay, joelagnelf, urezki, juri.lelli, vincent.guittot,
	kees, bsingharora, anna-maria, tglx, jstultz, kpsingh,
	mattbobrowski, nathan, martin.lau, song, mark.rutland,
	mathieu.desnoyers, dietmar.eggemann, void, rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	chengkaitao, ast, andrii, daniel, martin.lau, eddyz87,
	yonghong.song, clm, ihor.solodrai

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

> diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
> index c4dfbc293bae..9e076106bee7 100644
> --- a/kernel/trace/trace_dynevent.c
> +++ b/kernel/trace/trace_dynevent.c

[ ... ]

> @@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
>  		return -EINVAL;
>
>  	mutex_lock(&event_mutex);
> -	for_each_dyn_event_safe(pos, n) {
> +	for_each_dyn_event_safe(pos) {
>  		if (type && type != pos->ops)
>  			continue;
>  		if (!pos->ops->match(system, event,

Does this leave the variable n unused? Looking at the function
declaration around line 74, it still has:

	struct dyn_event *pos, *n;

but after this change n is no longer passed to for_each_dyn_event_safe().
The macro now hides the temporary cursor internally, so n appears to be
dead code. This would trigger -Wunused-variable warnings and break builds
with CONFIG_WERROR=y.

For comparison, the sibling change at line 219 (dyn_events_release_all)
correctly removed the *tmp variable from its declaration.

> diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
> index beee3f8d7544..a4dc0812284f 100644
> --- a/kernel/trace/trace_dynevent.h
> +++ b/kernel/trace/trace_dynevent.h
> @@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
>  /*
>   * for_each_dyn_event	-	iterate over the dyn_event list safely
>   * @pos:	the struct dyn_event * to use as a loop cursor
> - * @n:		the struct dyn_event * to use as temporary storage
>   */
> -#define for_each_dyn_event_safe(pos, n)	\
> -	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
> +#define for_each_dyn_event_safe(pos)	\
> +	list_for_each_entry_mutable(pos, &dyn_event_list, list)


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27930295027

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/7] kernel: Use mutable list iterators
@ 2026-06-22  5:22     ` bot+bpf-ci
  0 siblings, 0 replies; 19+ messages in thread
From: bot+bpf-ci @ 2026-06-22  5:22 UTC (permalink / raw)
  To: kaitao.cheng, paul, eparis, ast, daniel, andrii, eddyz87, memxor,
	davem, kuba, hawk, john.fastabend, tj, hannes, mkoutny, dev,
	mripard, natalie.vock, peterz, mingo, acme, namhyung, mhiramat,
	oleg, oberpar, akpm, baoquan.he, rppt, pasha.tatashin, pratyush,
	naveen, jpoimboe, jikos, mbenes, pmladek, will, boqun, mcgrof,
	petr.pavlu, da.gomez, samitolvanen, steffen.klassert,
	daniel.m.jordan, rafael, dave, paulmck, josh, frederic,
	neeraj.upadhyay, joelagnelf, urezki, juri.lelli, vincent.guittot,
	kees, bsingharora, anna-maria, tglx, jstultz, kpsingh,
	mattbobrowski, nathan, martin.lau, song, mark.rutland,
	mathieu.desnoyers, dietmar.eggemann, void, rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	chengkaitao, ast, andrii, daniel, martin.lau, eddyz87,
	yonghong.song, clm, ihor.solodrai

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

> diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
> index c4dfbc293bae..9e076106bee7 100644
> --- a/kernel/trace/trace_dynevent.c
> +++ b/kernel/trace/trace_dynevent.c

[ ... ]

> @@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
>  		return -EINVAL;
>
>  	mutex_lock(&event_mutex);
> -	for_each_dyn_event_safe(pos, n) {
> +	for_each_dyn_event_safe(pos) {
>  		if (type && type != pos->ops)
>  			continue;
>  		if (!pos->ops->match(system, event,

Does this leave the variable n unused? Looking at the function
declaration around line 74, it still has:

	struct dyn_event *pos, *n;

but after this change n is no longer passed to for_each_dyn_event_safe().
The macro now hides the temporary cursor internally, so n appears to be
dead code. This would trigger -Wunused-variable warnings and break builds
with CONFIG_WERROR=y.

For comparison, the sibling change at line 219 (dyn_events_release_all)
correctly removed the *tmp variable from its declaration.

> diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
> index beee3f8d7544..a4dc0812284f 100644
> --- a/kernel/trace/trace_dynevent.h
> +++ b/kernel/trace/trace_dynevent.h
> @@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
>  /*
>   * for_each_dyn_event	-	iterate over the dyn_event list safely
>   * @pos:	the struct dyn_event * to use as a loop cursor
> - * @n:		the struct dyn_event * to use as temporary storage
>   */
> -#define for_each_dyn_event_safe(pos, n)	\
> -	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
> +#define for_each_dyn_event_safe(pos)	\
> +	list_for_each_entry_mutable(pos, &dyn_event_list, list)


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27930295027

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (6 preceding siblings ...)
  2026-06-22  4:42 ` [PATCH v3 4/7] block: " Kaitao Cheng
@ 2026-06-22  5:28 ` Alexei Starovoitov
  2026-06-22  6:15   ` Kaitao Cheng
  2026-06-22 11:27   ` David Hildenbrand (Arm)
  2026-06-22  8:37 ` Jani Nikula
  8 siblings, 2 replies; 19+ messages in thread
From: Alexei Starovoitov @ 2026-06-22  5:28 UTC (permalink / raw)
  To: Kaitao Cheng
  Cc: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König, David Howells, Simona Vetter, Randy Dunlap,
	Luca Ceresoli, Philipp Stanner, linux-block, LKML,
	open list:CONTROL GROUP (CGROUP), linux-ntfs-dev, Linux-Fsdevel,
	io-uring, audit, bpf, Network Development, dri-devel,
	linux-perf-use., linux-trace-kernel, kexec, live-patching,
	linux-modules, Linux Crypto Mailing List, Linux Power Management,
	rcu, sched-ext, linux-mm, virtualization, damon,
	clang-built-linux, chengkaitao

On Sun, Jun 21, 2026 at 9:06 PM Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>
> From: chengkaitao <chengkaitao@kylinos.cn>
>
> The list_for_each*_safe() helpers are used when the loop body may remove
> the current entry.  Their current interface, however, forces every caller
> to define a temporary cursor outside the macro and pass it in, even when
> the caller never uses that cursor directly.  For most call sites this
> extra cursor is just boilerplate required by the macro implementation.
>
> This is awkward because the saved next pointer is an internal detail of
> the iteration.  Callers that only remove or move the current entry do not
> need to spell it out.
>
> The _safe() suffix has also caused confusion.  Christian Koenig pointed
> out that the name is easy to read as a thread-safe variant, especially
> for beginners, even though it only means that the iterator keeps enough
> state to tolerate removal of the current entry.  He suggested _mutable()
> as a clearer description of what the loop permits.
>
> Add *_mutable() iterator variants for list, hlist and llist.  The new
> helpers are variadic and support both forms.  In the common case, the
> caller omits the temporary cursor and the macro creates a unique internal
> cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
> explicit temporary cursor, the caller can still pass it and the helper
> keeps the existing *_safe() behaviour.
>
> For example, a call site may use the shorter form:
>
>   list_for_each_entry_mutable(pos, head, member)
>
> or keep the explicit temporary cursor form:
>
>   list_for_each_entry_mutable(pos, tmp, head, member)
>
> The existing *_safe() helpers remain available for compatibility.  This
> series only converts users in mm, block, kernel, init and io_uring.  If
> this approach looks acceptable, the remaining users can be converted in
> follow-up series.
>
> Changes in v3 (Christian König, Andy Shevchenko):
> - Convert safe list walks to mutable iterators
>
> Changes in v2 (Muchun Song, Andy Shevchenko):
> - Drop the list_for_each_entry_mutable*() helpers from v1 and make the
>   cursor change directly in the existing list_for_each_entry*() helpers.
> - Open-code special list walks that rely on updating the loop cursor in
>   the body, preserving their existing traversal semantics.
>
> Link to v2:
> https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/
>
> Link to v1:
> https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/
>
> Kaitao Cheng (7):
>   list: Add mutable iterator variants
>   llist: Add mutable iterator variants
>   mm: Use mutable list iterators
>   block: Use mutable list iterators
>   kernel: Use mutable list iterators
>   initramfs: Use mutable list iterator
>   io_uring: Use mutable list iterators
>
>  block/bfq-iosched.c                 |  17 +-
>  block/blk-cgroup.c                  |  12 +-
>  block/blk-flush.c                   |   4 +-
>  block/blk-iocost.c                  |  18 +-
>  block/blk-mq.c                      |   8 +-
>  block/blk-throttle.c                |   4 +-
>  block/kyber-iosched.c               |   4 +-
>  block/partitions/ldm.c              |   8 +-
>  block/sed-opal.c                    |   4 +-
>  include/linux/list.h                | 269 ++++++++++++++++++++++++----
>  include/linux/llist.h               |  81 +++++++--
>  init/initramfs.c                    |   5 +-
>  io_uring/cancel.c                   |   6 +-
>  io_uring/poll.c                     |   3 +-
>  io_uring/rw.c                       |   4 +-
>  io_uring/timeout.c                  |   8 +-
>  io_uring/uring_cmd.c                |   3 +-
>  kernel/audit_tree.c                 |   4 +-
>  kernel/audit_watch.c                |  16 +-
>  kernel/auditfilter.c                |   4 +-
>  kernel/auditsc.c                    |   4 +-
>  kernel/bpf/arena.c                  |  10 +-
>  kernel/bpf/arraymap.c               |   8 +-
>  kernel/bpf/bpf_local_storage.c      |   3 +-
>  kernel/bpf/bpf_lru_list.c           |  25 ++-
>  kernel/bpf/btf.c                    |  18 +-
>  kernel/bpf/cgroup.c                 |   7 +-
>  kernel/bpf/cpumap.c                 |   4 +-
>  kernel/bpf/devmap.c                 |  10 +-
>  kernel/bpf/helpers.c                |   8 +-
>  kernel/bpf/local_storage.c          |   4 +-
>  kernel/bpf/memalloc.c               |  16 +-
>  kernel/bpf/offload.c                |   8 +-
>  kernel/bpf/states.c                 |   4 +-
>  kernel/bpf/stream.c                 |   4 +-
>  kernel/bpf/verifier.c               |   6 +-
>  kernel/cgroup/cgroup-v1.c           |   4 +-
>  kernel/cgroup/cgroup.c              |  54 +++---
>  kernel/cgroup/dmem.c                |  12 +-
>  kernel/cgroup/rdma.c                |   8 +-
>  kernel/events/core.c                |  44 +++--
>  kernel/events/uprobes.c             |  12 +-
>  kernel/exit.c                       |   8 +-
>  kernel/fail_function.c              |   4 +-
>  kernel/gcov/clang.c                 |   4 +-
>  kernel/irq_work.c                   |   4 +-
>  kernel/kexec_core.c                 |   4 +-
>  kernel/kprobes.c                    |  16 +-
>  kernel/livepatch/core.c             |   4 +-
>  kernel/livepatch/core.h             |   4 +-
>  kernel/liveupdate/kho_block.c       |   4 +-
>  kernel/liveupdate/luo_flb.c         |   4 +-
>  kernel/locking/rwsem.c              |   2 +-
>  kernel/locking/test-ww_mutex.c      |   2 +-
>  kernel/module/main.c                |  11 +-
>  kernel/padata.c                     |   4 +-
>  kernel/power/snapshot.c             |   8 +-
>  kernel/power/wakelock.c             |   4 +-
>  kernel/printk/printk.c              |  11 +-
>  kernel/ptrace.c                     |   4 +-
>  kernel/rcu/rcutorture.c             |   3 +-
>  kernel/rcu/tasks.h                  |   9 +-
>  kernel/rcu/tree.c                   |   6 +-
>  kernel/resource.c                   |   4 +-
>  kernel/sched/core.c                 |   4 +-
>  kernel/sched/ext.c                  |  22 +--
>  kernel/sched/fair.c                 |  28 +--
>  kernel/sched/topology.c             |   4 +-
>  kernel/sched/wait.c                 |   4 +-
>  kernel/seccomp.c                    |   4 +-
>  kernel/signal.c                     |  11 +-
>  kernel/smp.c                        |   4 +-
>  kernel/taskstats.c                  |   8 +-
>  kernel/time/clockevents.c           |   6 +-
>  kernel/time/clocksource.c           |   4 +-
>  kernel/time/posix-cpu-timers.c      |   4 +-
>  kernel/time/posix-timers.c          |   3 +-
>  kernel/torture.c                    |   3 +-
>  kernel/trace/bpf_trace.c            |   4 +-
>  kernel/trace/ftrace.c               |  49 +++--
>  kernel/trace/ring_buffer.c          |  25 ++-
>  kernel/trace/trace.c                |  12 +-
>  kernel/trace/trace_dynevent.c       |   6 +-
>  kernel/trace/trace_dynevent.h       |   5 +-
>  kernel/trace/trace_events.c         |  35 ++--
>  kernel/trace/trace_events_filter.c  |   4 +-
>  kernel/trace/trace_events_hist.c    |   8 +-
>  kernel/trace/trace_events_trigger.c |  17 +-
>  kernel/trace/trace_events_user.c    |  16 +-
>  kernel/trace/trace_stat.c           |   4 +-
>  kernel/user-return-notifier.c       |   3 +-
>  kernel/workqueue.c                  |  16 +-
>  mm/backing-dev.c                    |   8 +-
>  mm/balloon.c                        |   8 +-
>  mm/cma.c                            |   4 +-
>  mm/compaction.c                     |   4 +-
>  mm/damon/core.c                     |   4 +-
>  mm/damon/sysfs-schemes.c            |   4 +-
>  mm/dmapool.c                        |   4 +-
>  mm/huge_memory.c                    |   8 +-
>  mm/hugetlb.c                        |  56 +++---
>  mm/hugetlb_vmemmap.c                |  16 +-
>  mm/khugepaged.c                     |  14 +-
>  mm/kmemleak.c                       |   7 +-
>  mm/ksm.c                            |  25 +--
>  mm/list_lru.c                       |   4 +-
>  mm/memcontrol-v1.c                  |   8 +-
>  mm/memory-failure.c                 |  12 +-
>  mm/memory-tiers.c                   |   4 +-
>  mm/migrate.c                        |  23 ++-
>  mm/mmu_notifier.c                   |   9 +-
>  mm/page_alloc.c                     |   8 +-
>  mm/page_reporting.c                 |   2 +-
>  mm/percpu.c                         |  11 +-
>  mm/pgtable-generic.c                |   4 +-
>  mm/rmap.c                           |  10 +-
>  mm/shmem.c                          |   9 +-
>  mm/slab_common.c                    |  14 +-
>  mm/slub.c                           |  33 ++--
>  mm/swapfile.c                       |   4 +-
>  mm/userfaultfd.c                    |  12 +-
>  mm/vmalloc.c                        |  24 +--
>  mm/vmscan.c                         |   7 +-
>  mm/zsmalloc.c                       |   4 +-
>  124 files changed, 875 insertions(+), 681 deletions(-)

Not sure what you were thinking, but this diff stat
is not landable.

pw-bot: cr


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
  2026-06-22  5:28 ` [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Alexei Starovoitov
@ 2026-06-22  6:15   ` Kaitao Cheng
  2026-06-22 10:46     ` Andy Shevchenko
  2026-06-22 11:27   ` David Hildenbrand (Arm)
  1 sibling, 1 reply; 19+ messages in thread
From: Kaitao Cheng @ 2026-06-22  6:15 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König, David Howells, Simona Vetter, Randy Dunlap,
	Luca Ceresoli, Philipp Stanner, linux-block, LKML,
	open list:CONTROL GROUP (CGROUP), linux-ntfs-dev, Linux-Fsdevel,
	io-uring, audit, bpf, Network Development, dri-devel,
	linux-perf-use., linux-trace-kernel, kexec, live-patching,
	linux-modules, Linux Crypto Mailing List, Linux Power Management,
	rcu, sched-ext, linux-mm, virtualization, damon,
	clang-built-linux, chengkaitao, Muchun Song



在 2026/6/22 13:28, Alexei Starovoitov 写道:
> On Sun, Jun 21, 2026 at 9:06 PM Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>>
>> From: chengkaitao <chengkaitao@kylinos.cn>
>>
>> The list_for_each*_safe() helpers are used when the loop body may remove
>> the current entry.  Their current interface, however, forces every caller
>> to define a temporary cursor outside the macro and pass it in, even when
>> the caller never uses that cursor directly.  For most call sites this
>> extra cursor is just boilerplate required by the macro implementation.
>>
>> This is awkward because the saved next pointer is an internal detail of
>> the iteration.  Callers that only remove or move the current entry do not
>> need to spell it out.
>>
>> The _safe() suffix has also caused confusion.  Christian Koenig pointed
>> out that the name is easy to read as a thread-safe variant, especially
>> for beginners, even though it only means that the iterator keeps enough
>> state to tolerate removal of the current entry.  He suggested _mutable()
>> as a clearer description of what the loop permits.
>>
>> Add *_mutable() iterator variants for list, hlist and llist.  The new
>> helpers are variadic and support both forms.  In the common case, the
>> caller omits the temporary cursor and the macro creates a unique internal
>> cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
>> explicit temporary cursor, the caller can still pass it and the helper
>> keeps the existing *_safe() behaviour.
>>
>> For example, a call site may use the shorter form:
>>
>>   list_for_each_entry_mutable(pos, head, member)
>>
>> or keep the explicit temporary cursor form:
>>
>>   list_for_each_entry_mutable(pos, tmp, head, member)
>>
>> The existing *_safe() helpers remain available for compatibility.  This
>> series only converts users in mm, block, kernel, init and io_uring.  If
>> this approach looks acceptable, the remaining users can be converted in
>> follow-up series.
>>
>> Changes in v3 (Christian König, Andy Shevchenko):
>> - Convert safe list walks to mutable iterators
>>
>> Changes in v2 (Muchun Song, Andy Shevchenko):
>> - Drop the list_for_each_entry_mutable*() helpers from v1 and make the
>>   cursor change directly in the existing list_for_each_entry*() helpers.
>> - Open-code special list walks that rely on updating the loop cursor in
>>   the body, preserving their existing traversal semantics.
>>
>> Link to v2:
>> https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/
>>
>> Link to v1:
>> https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/
>>
>> Kaitao Cheng (7):
>>   list: Add mutable iterator variants
>>   llist: Add mutable iterator variants
>>   mm: Use mutable list iterators
>>   block: Use mutable list iterators
>>   kernel: Use mutable list iterators
>>   initramfs: Use mutable list iterator
>>   io_uring: Use mutable list iterators
>>
>>  block/bfq-iosched.c                 |  17 +-
>>  block/blk-cgroup.c                  |  12 +-
>>  block/blk-flush.c                   |   4 +-
>>  block/blk-iocost.c                  |  18 +-
>>  block/blk-mq.c                      |   8 +-
>>  block/blk-throttle.c                |   4 +-
>>  block/kyber-iosched.c               |   4 +-
>>  block/partitions/ldm.c              |   8 +-
>>  block/sed-opal.c                    |   4 +-
>>  include/linux/list.h                | 269 ++++++++++++++++++++++++----
>>  include/linux/llist.h               |  81 +++++++--
>>  init/initramfs.c                    |   5 +-
>>  io_uring/cancel.c                   |   6 +-
>>  io_uring/poll.c                     |   3 +-
>>  io_uring/rw.c                       |   4 +-
>>  io_uring/timeout.c                  |   8 +-
>>  io_uring/uring_cmd.c                |   3 +-
>>  kernel/audit_tree.c                 |   4 +-
>>  kernel/audit_watch.c                |  16 +-
>>  kernel/auditfilter.c                |   4 +-
>>  kernel/auditsc.c                    |   4 +-
>>  kernel/bpf/arena.c                  |  10 +-
>>  kernel/bpf/arraymap.c               |   8 +-
>>  kernel/bpf/bpf_local_storage.c      |   3 +-
>>  kernel/bpf/bpf_lru_list.c           |  25 ++-
>>  kernel/bpf/btf.c                    |  18 +-
>>  kernel/bpf/cgroup.c                 |   7 +-
>>  kernel/bpf/cpumap.c                 |   4 +-
>>  kernel/bpf/devmap.c                 |  10 +-
>>  kernel/bpf/helpers.c                |   8 +-
>>  kernel/bpf/local_storage.c          |   4 +-
>>  kernel/bpf/memalloc.c               |  16 +-
>>  kernel/bpf/offload.c                |   8 +-
>>  kernel/bpf/states.c                 |   4 +-
>>  kernel/bpf/stream.c                 |   4 +-
>>  kernel/bpf/verifier.c               |   6 +-
>>  kernel/cgroup/cgroup-v1.c           |   4 +-
>>  kernel/cgroup/cgroup.c              |  54 +++---
>>  kernel/cgroup/dmem.c                |  12 +-
>>  kernel/cgroup/rdma.c                |   8 +-
>>  kernel/events/core.c                |  44 +++--
>>  kernel/events/uprobes.c             |  12 +-
>>  kernel/exit.c                       |   8 +-
>>  kernel/fail_function.c              |   4 +-
>>  kernel/gcov/clang.c                 |   4 +-
>>  kernel/irq_work.c                   |   4 +-
>>  kernel/kexec_core.c                 |   4 +-
>>  kernel/kprobes.c                    |  16 +-
>>  kernel/livepatch/core.c             |   4 +-
>>  kernel/livepatch/core.h             |   4 +-
>>  kernel/liveupdate/kho_block.c       |   4 +-
>>  kernel/liveupdate/luo_flb.c         |   4 +-
>>  kernel/locking/rwsem.c              |   2 +-
>>  kernel/locking/test-ww_mutex.c      |   2 +-
>>  kernel/module/main.c                |  11 +-
>>  kernel/padata.c                     |   4 +-
>>  kernel/power/snapshot.c             |   8 +-
>>  kernel/power/wakelock.c             |   4 +-
>>  kernel/printk/printk.c              |  11 +-
>>  kernel/ptrace.c                     |   4 +-
>>  kernel/rcu/rcutorture.c             |   3 +-
>>  kernel/rcu/tasks.h                  |   9 +-
>>  kernel/rcu/tree.c                   |   6 +-
>>  kernel/resource.c                   |   4 +-
>>  kernel/sched/core.c                 |   4 +-
>>  kernel/sched/ext.c                  |  22 +--
>>  kernel/sched/fair.c                 |  28 +--
>>  kernel/sched/topology.c             |   4 +-
>>  kernel/sched/wait.c                 |   4 +-
>>  kernel/seccomp.c                    |   4 +-
>>  kernel/signal.c                     |  11 +-
>>  kernel/smp.c                        |   4 +-
>>  kernel/taskstats.c                  |   8 +-
>>  kernel/time/clockevents.c           |   6 +-
>>  kernel/time/clocksource.c           |   4 +-
>>  kernel/time/posix-cpu-timers.c      |   4 +-
>>  kernel/time/posix-timers.c          |   3 +-
>>  kernel/torture.c                    |   3 +-
>>  kernel/trace/bpf_trace.c            |   4 +-
>>  kernel/trace/ftrace.c               |  49 +++--
>>  kernel/trace/ring_buffer.c          |  25 ++-
>>  kernel/trace/trace.c                |  12 +-
>>  kernel/trace/trace_dynevent.c       |   6 +-
>>  kernel/trace/trace_dynevent.h       |   5 +-
>>  kernel/trace/trace_events.c         |  35 ++--
>>  kernel/trace/trace_events_filter.c  |   4 +-
>>  kernel/trace/trace_events_hist.c    |   8 +-
>>  kernel/trace/trace_events_trigger.c |  17 +-
>>  kernel/trace/trace_events_user.c    |  16 +-
>>  kernel/trace/trace_stat.c           |   4 +-
>>  kernel/user-return-notifier.c       |   3 +-
>>  kernel/workqueue.c                  |  16 +-
>>  mm/backing-dev.c                    |   8 +-
>>  mm/balloon.c                        |   8 +-
>>  mm/cma.c                            |   4 +-
>>  mm/compaction.c                     |   4 +-
>>  mm/damon/core.c                     |   4 +-
>>  mm/damon/sysfs-schemes.c            |   4 +-
>>  mm/dmapool.c                        |   4 +-
>>  mm/huge_memory.c                    |   8 +-
>>  mm/hugetlb.c                        |  56 +++---
>>  mm/hugetlb_vmemmap.c                |  16 +-
>>  mm/khugepaged.c                     |  14 +-
>>  mm/kmemleak.c                       |   7 +-
>>  mm/ksm.c                            |  25 +--
>>  mm/list_lru.c                       |   4 +-
>>  mm/memcontrol-v1.c                  |   8 +-
>>  mm/memory-failure.c                 |  12 +-
>>  mm/memory-tiers.c                   |   4 +-
>>  mm/migrate.c                        |  23 ++-
>>  mm/mmu_notifier.c                   |   9 +-
>>  mm/page_alloc.c                     |   8 +-
>>  mm/page_reporting.c                 |   2 +-
>>  mm/percpu.c                         |  11 +-
>>  mm/pgtable-generic.c                |   4 +-
>>  mm/rmap.c                           |  10 +-
>>  mm/shmem.c                          |   9 +-
>>  mm/slab_common.c                    |  14 +-
>>  mm/slub.c                           |  33 ++--
>>  mm/swapfile.c                       |   4 +-
>>  mm/userfaultfd.c                    |  12 +-
>>  mm/vmalloc.c                        |  24 +--
>>  mm/vmscan.c                         |   7 +-
>>  mm/zsmalloc.c                       |   4 +-
>>  124 files changed, 875 insertions(+), 681 deletions(-)
> 
> Not sure what you were thinking, but this diff stat
> is not landable.

[PATCH v3 1/7] and [PATCH v3 2/7] contain the main logic and can
be merged directly. They are also compatible with the old API.
[PATCH v3 3/7] through [PATCH v3 7/7] are just simple interface
replacements and do not change any functional logic. They can be
left unmerged for now; individual modules can pick them up later
if needed.

In v2, Andy Shevchenko mentioned: "If it's done by Linus himself
during the day when he prepares -rc1, it's fine." Even so, the
changes in this patch series are indeed quite large and touch
almost every subsystem. I have only converted part of them for
now, so I wanted to send this out first and see what people think.

-- 
Thanks
Kaitao Cheng


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
  2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
                   ` (7 preceding siblings ...)
  2026-06-22  5:28 ` [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Alexei Starovoitov
@ 2026-06-22  8:37 ` Jani Nikula
  8 siblings, 0 replies; 19+ messages in thread
From: Jani Nikula @ 2026-06-22  8:37 UTC (permalink / raw)
  To: Kaitao Cheng, Andrew Morton, David Hildenbrand, Jens Axboe,
	Tejun Heo, Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, chengkaitao

On Mon, 22 Jun 2026, Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
> Add *_mutable() iterator variants for list, hlist and llist.  The new
> helpers are variadic and support both forms.  In the common case, the
> caller omits the temporary cursor and the macro creates a unique internal
> cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
> explicit temporary cursor, the caller can still pass it and the helper
> keeps the existing *_safe() behaviour.
>
> For example, a call site may use the shorter form:
>
>   list_for_each_entry_mutable(pos, head, member)
>
> or keep the explicit temporary cursor form:
>
>   list_for_each_entry_mutable(pos, tmp, head, member)

I'm unconvinced it's a good idea to allow two forms with macro trickery,
*especially* when it's not the last argument you can omit. I think it's
a footgun.

IMO stick with the first form only, and there'll always be the _safe
variant that can be used when the temp pointer is needed.


BR,
Jani.


-- 
Jani Nikula, Intel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 1/7] list: Add mutable iterator variants
  2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
@ 2026-06-22  8:42   ` David Laight
  2026-06-22  8:51   ` Christian König
  1 sibling, 0 replies; 19+ messages in thread
From: David Laight @ 2026-06-22  8:42 UTC (permalink / raw)
  To: Kaitao Cheng
  Cc: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König, David Howells, Simona Vetter, Randy Dunlap,
	Luca Ceresoli, Philipp Stanner, linux-block, linux-kernel,
	cgroups, linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf,
	netdev, dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng

On Mon, 22 Jun 2026 12:05:31 +0800
Kaitao Cheng <kaitao.cheng@linux.dev> wrote:

> From: Kaitao Cheng <chengkaitao@kylinos.cn>
> 
> The list_for_each*_safe() helpers are used when the loop body may
> remove the current entry.  Their API exposes the temporary cursor at
> every call site, even though most users only need it for the iterator
> implementation and never reference it in the loop body.
> 
> Add *_mutable() variants for list and hlist iteration.  The new helpers
> support both forms: callers may keep passing an explicit temporary cursor
> when they need to inspect or reset it, or omit it and let the helper use
> a unique internal cursor.

I'm not really sure 'mutable' means anything either.
It is possible to make it valid for the loop body (or even other threads)
to delete arbitrary list items - but that needs significant extra overheads.

It might be worth doing something that doesn't need the extra variable,
but there is little point doing all the churn just to rename things.

> 
> This makes call sites that only mutate the list through the current entry
> less noisy, while keeping the existing *_safe() helpers available for
> compatibility.
> 
> Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
> ---
>  include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
>  1 file changed, 231 insertions(+), 38 deletions(-)
> 
> diff --git a/include/linux/list.h b/include/linux/list.h
> index 09d979976b3b..1081def7cea9 100644
> --- a/include/linux/list.h
> +++ b/include/linux/list.h
> @@ -7,6 +7,7 @@
>  #include <linux/stddef.h>
>  #include <linux/poison.h>
>  #include <linux/const.h>
> +#include <linux/args.h>
>  
>  #include <asm/barrier.h>
>  
> @@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
>  #define list_for_each_prev(pos, head) \
>  	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
>  
> -/**
> - * list_for_each_safe - iterate over a list safe against removal of list entry
> - * @pos:	the &struct list_head to use as a loop cursor.
> - * @n:		another &struct list_head to use as temporary storage
> - * @head:	the head for your list.
> +/*
> + * list_for_each_safe is an old interface, use list_for_each_mutable instead.
>   */
>  #define list_for_each_safe(pos, n, head) \
>  	for (pos = (head)->next, n = pos->next; \
>  	     !list_is_head(pos, (head)); \
>  	     pos = n, n = pos->next)
>  
> +#define __list_for_each_mutable_internal(pos, tmp, head)		\
> +	for (typeof(pos) tmp = (pos = (head)->next)->next;		\

Use auto

> +	     !list_is_head(pos, (head));				\
> +	     pos = tmp, tmp = pos->next)
> +
> +#define __list_for_each_mutable1(pos, head)				\
> +	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
> +
> +#define __list_for_each_mutable2(pos, next, head)			\
> +	list_for_each_safe(pos, next, head)
> +
>  /**
> - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
> + * list_for_each_mutable - iterate over a list safe against entry removal
>   * @pos:	the &struct list_head to use as a loop cursor.
> - * @n:		another &struct list_head to use as temporary storage
> - * @head:	the head for your list.
> + * @...:	either (head) or (next, head)
> + *
> + * next:	another &struct list_head to use as optional temporary storage.
> + *		The temporary cursor is internal unless explicitly supplied by
> + *		the caller.
> + * head:	the head for your list.
> + */
> +#define list_for_each_mutable(pos, ...)					\
> +	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
> +		(pos, __VA_ARGS__)

The variable argument count logic really just slows down compilation.
Maybe there aren't enough copies of this code to make that significant.
But just because you can do it doesn't mean it is a gooD idea.
I'm also not sure it really adds anything to the readability.

And, it you are going to make the middle argument optional there is
no need to change the macro name.

	David



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 1/7] list: Add mutable iterator variants
  2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
  2026-06-22  8:42   ` David Laight
@ 2026-06-22  8:51   ` Christian König
  1 sibling, 0 replies; 19+ messages in thread
From: Christian König @ 2026-06-22  8:51 UTC (permalink / raw)
  To: Kaitao Cheng, Andrew Morton, David Hildenbrand, Jens Axboe,
	Tejun Heo, Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng

On 6/22/26 06:05, Kaitao Cheng wrote:
> From: Kaitao Cheng <chengkaitao@kylinos.cn>
> 
> The list_for_each*_safe() helpers are used when the loop body may
> remove the current entry.  Their API exposes the temporary cursor at
> every call site, even though most users only need it for the iterator
> implementation and never reference it in the loop body.
> 
> Add *_mutable() variants for list and hlist iteration.  The new helpers
> support both forms: callers may keep passing an explicit temporary cursor
> when they need to inspect or reset it, or omit it and let the helper use
> a unique internal cursor.

That sounds like a bad idea to me. The macro should really be doing one job and that as best as it can.

> This makes call sites that only mutate the list through the current entry
> less noisy, while keeping the existing *_safe() helpers available for
> compatibility.

This can be perfectly used for code that which really needs the separate variable for the next entry.

Regards,
Christian.


> 
> Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
> ---
>  include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
>  1 file changed, 231 insertions(+), 38 deletions(-)
> 
> diff --git a/include/linux/list.h b/include/linux/list.h
> index 09d979976b3b..1081def7cea9 100644
> --- a/include/linux/list.h
> +++ b/include/linux/list.h
> @@ -7,6 +7,7 @@
>  #include <linux/stddef.h>
>  #include <linux/poison.h>
>  #include <linux/const.h>
> +#include <linux/args.h>
>  
>  #include <asm/barrier.h>
>  
> @@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
>  #define list_for_each_prev(pos, head) \
>  	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
>  
> -/**
> - * list_for_each_safe - iterate over a list safe against removal of list entry
> - * @pos:	the &struct list_head to use as a loop cursor.
> - * @n:		another &struct list_head to use as temporary storage
> - * @head:	the head for your list.
> +/*
> + * list_for_each_safe is an old interface, use list_for_each_mutable instead.
>   */
>  #define list_for_each_safe(pos, n, head) \
>  	for (pos = (head)->next, n = pos->next; \
>  	     !list_is_head(pos, (head)); \
>  	     pos = n, n = pos->next)
>  
> +#define __list_for_each_mutable_internal(pos, tmp, head)		\
> +	for (typeof(pos) tmp = (pos = (head)->next)->next;		\
> +	     !list_is_head(pos, (head));				\
> +	     pos = tmp, tmp = pos->next)
> +
> +#define __list_for_each_mutable1(pos, head)				\
> +	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
> +
> +#define __list_for_each_mutable2(pos, next, head)			\
> +	list_for_each_safe(pos, next, head)
> +
>  /**
> - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
> + * list_for_each_mutable - iterate over a list safe against entry removal
>   * @pos:	the &struct list_head to use as a loop cursor.
> - * @n:		another &struct list_head to use as temporary storage
> - * @head:	the head for your list.
> + * @...:	either (head) or (next, head)
> + *
> + * next:	another &struct list_head to use as optional temporary storage.
> + *		The temporary cursor is internal unless explicitly supplied by
> + *		the caller.
> + * head:	the head for your list.
> + */
> +#define list_for_each_mutable(pos, ...)					\
> +	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
> +		(pos, __VA_ARGS__)
> +
> +/*
> + * list_for_each_prev_safe is an old interface, use list_for_each_prev_mutable instead.
>   */
>  #define list_for_each_prev_safe(pos, n, head) \
>  	for (pos = (head)->prev, n = pos->prev; \
>  	     !list_is_head(pos, (head)); \
>  	     pos = n, n = pos->prev)
>  
> +#define __list_for_each_prev_mutable_internal(pos, tmp, head)		\
> +	for (typeof(pos) tmp = (pos = (head)->prev)->prev;		\
> +	     !list_is_head(pos, (head));				\
> +	     pos = tmp, tmp = pos->prev)
> +
> +#define __list_for_each_prev_mutable1(pos, head)			\
> +	__list_for_each_prev_mutable_internal(pos, __UNIQUE_ID(prev), head)
> +
> +#define __list_for_each_prev_mutable2(pos, prev, head)			\
> +	list_for_each_prev_safe(pos, prev, head)
> +
> +/**
> + * list_for_each_prev_mutable - iterate over a list backwards safe against entry removal
> + * @pos:	the &struct list_head to use as a loop cursor.
> + * @...:	either (head) or (prev, head)
> + *
> + * prev:	another &struct list_head to use as optional temporary storage.
> + *		The temporary cursor is internal unless explicitly supplied by
> + *		the caller.
> + * head:	the head for your list.
> + */
> +#define list_for_each_prev_mutable(pos, ...)				\
> +	CONCATENATE(__list_for_each_prev_mutable, COUNT_ARGS(__VA_ARGS__)) \
> +		(pos, __VA_ARGS__)
> +
>  /**
>   * list_count_nodes - count nodes in the list
>   * @head:	the head for your list.
> @@ -895,12 +940,8 @@ static inline size_t list_count_nodes(struct list_head *head)
>  	for (; !list_entry_is_head(pos, head, member);			\
>  	     pos = list_prev_entry(pos, member))
>  
> -/**
> - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
> - * @pos:	the type * to use as a loop cursor.
> - * @n:		another type * to use as temporary storage
> - * @head:	the head for your list.
> - * @member:	the name of the list_head within the struct.
> +/*
> + * list_for_each_entry_safe is an old interface, use list_for_each_entry_mutable instead.
>   */
>  #define list_for_each_entry_safe(pos, n, head, member)			\
>  	for (pos = list_first_entry(head, typeof(*pos), member),	\
> @@ -908,15 +949,36 @@ static inline size_t list_count_nodes(struct list_head *head)
>  	     !list_entry_is_head(pos, head, member); 			\
>  	     pos = n, n = list_next_entry(n, member))
>  
> +#define __list_for_each_entry_mutable_internal(pos, tmp, head, member)	\
> +	for (typeof(pos) tmp = list_next_entry(pos =			\
> +		list_first_entry(head, typeof(*pos), member), member);	\
> +	     !list_entry_is_head(pos, head, member);			\
> +	     pos = tmp, tmp = list_next_entry(tmp, member))
> +
> +#define __list_for_each_entry_mutable2(pos, head, member)		\
> +	__list_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), head, member)
> +
> +#define __list_for_each_entry_mutable3(pos, next, head, member)		\
> +	list_for_each_entry_safe(pos, next, head, member)
> +
>  /**
> - * list_for_each_entry_safe_continue - continue list iteration safe against removal
> + * list_for_each_entry_mutable - iterate over a list safe against entry removal
>   * @pos:	the type * to use as a loop cursor.
> - * @n:		another type * to use as temporary storage
> - * @head:	the head for your list.
> - * @member:	the name of the list_head within the struct.
> + * @...:	either (head, member) or (next, head, member)
>   *
> - * Iterate over list of given type, continuing after current point,
> - * safe against removal of list entry.
> + * next:	another type * to use as optional temporary storage. The
> + *		temporary cursor is internal unless explicitly supplied by the
> + *		caller.
> + * head:	the head for your list.
> + * member:	the name of the list_head within the struct.
> + */
> +#define list_for_each_entry_mutable(pos, ...)				\
> +	CONCATENATE(__list_for_each_entry_mutable, COUNT_ARGS(__VA_ARGS__)) \
> +		(pos, __VA_ARGS__)
> +
> +/*
> + * list_for_each_entry_safe_continue is an old interface,
> + * use list_for_each_entry_mutable_continue instead.
>   */
>  #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
>  	for (pos = list_next_entry(pos, member), 				\
> @@ -924,30 +986,79 @@ static inline size_t list_count_nodes(struct list_head *head)
>  	     !list_entry_is_head(pos, head, member);				\
>  	     pos = n, n = list_next_entry(n, member))
>  
> +#define __list_for_each_entry_mutable_continue_internal(pos, tmp, head, member) \
> +	for (typeof(pos) tmp = list_next_entry(pos =			\
> +		list_next_entry(pos, member), member);			\
> +	     !list_entry_is_head(pos, head, member);			\
> +	     pos = tmp, tmp = list_next_entry(tmp, member))
> +
> +#define __list_for_each_entry_mutable_continue2(pos, head, member)	\
> +	__list_for_each_entry_mutable_continue_internal(pos,		\
> +		__UNIQUE_ID(next), head, member)
> +
> +#define __list_for_each_entry_mutable_continue3(pos, next, head, member) \
> +	list_for_each_entry_safe_continue(pos, next, head, member)
> +
>  /**
> - * list_for_each_entry_safe_from - iterate over list from current point safe against removal
> + * list_for_each_entry_mutable_continue - continue list iteration safe against removal
>   * @pos:	the type * to use as a loop cursor.
> - * @n:		another type * to use as temporary storage
> - * @head:	the head for your list.
> - * @member:	the name of the list_head within the struct.
> + * @...:	either (head, member) or (next, head, member)
>   *
> - * Iterate over list of given type from current point, safe against
> - * removal of list entry.
> + * next:	another type * to use as optional temporary storage. The
> + *		temporary cursor is internal unless explicitly supplied by the
> + *		caller.
> + * head:	the head for your list.
> + * member:	the name of the list_head within the struct.
> + *
> + * Iterate over list of given type, continuing after current point,
> + * safe against removal of list entry.
> + */
> +#define list_for_each_entry_mutable_continue(pos, ...)			\
> +	CONCATENATE(__list_for_each_entry_mutable_continue,		\
> +		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
> +
> +/*
> + * list_for_each_entry_safe_from is an old interface,
> + * use list_for_each_entry_mutable_from instead.
>   */
>  #define list_for_each_entry_safe_from(pos, n, head, member) 			\
>  	for (n = list_next_entry(pos, member);					\
>  	     !list_entry_is_head(pos, head, member);				\
>  	     pos = n, n = list_next_entry(n, member))
>  
> +#define __list_for_each_entry_mutable_from_internal(pos, tmp, head, member) \
> +	for (typeof(pos) tmp = list_next_entry(pos, member);		\
> +	     !list_entry_is_head(pos, head, member);			\
> +	     pos = tmp, tmp = list_next_entry(tmp, member))
> +
> +#define __list_for_each_entry_mutable_from2(pos, head, member)		\
> +	__list_for_each_entry_mutable_from_internal(pos,		\
> +		__UNIQUE_ID(next), head, member)
> +
> +#define __list_for_each_entry_mutable_from3(pos, next, head, member)	\
> +	list_for_each_entry_safe_from(pos, next, head, member)
> +
>  /**
> - * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
> + * list_for_each_entry_mutable_from - iterate over list from current point safe against removal
>   * @pos:	the type * to use as a loop cursor.
> - * @n:		another type * to use as temporary storage
> - * @head:	the head for your list.
> - * @member:	the name of the list_head within the struct.
> + * @...:	either (head, member) or (next, head, member)
>   *
> - * Iterate backwards over list of given type, safe against removal
> - * of list entry.
> + * next:	another type * to use as optional temporary storage. The
> + *		temporary cursor is internal unless explicitly supplied by the
> + *		caller.
> + * head:	the head for your list.
> + * member:	the name of the list_head within the struct.
> + *
> + * Iterate over list of given type from current point, safe against
> + * removal of list entry.
> + */
> +#define list_for_each_entry_mutable_from(pos, ...)			\
> +	CONCATENATE(__list_for_each_entry_mutable_from,			\
> +		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
> +
> +/*
> + * list_for_each_entry_safe_reverse is an old interface,
> + * use list_for_each_entry_mutable_reverse instead.
>   */
>  #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
>  	for (pos = list_last_entry(head, typeof(*pos), member),		\
> @@ -955,6 +1066,37 @@ static inline size_t list_count_nodes(struct list_head *head)
>  	     !list_entry_is_head(pos, head, member); 			\
>  	     pos = n, n = list_prev_entry(n, member))
>  
> +#define __list_for_each_entry_mutable_reverse_internal(pos, tmp, head, member) \
> +	for (typeof(pos) tmp = list_prev_entry(pos =			\
> +		list_last_entry(head, typeof(*pos), member), member);	\
> +	     !list_entry_is_head(pos, head, member);			\
> +	     pos = tmp, tmp = list_prev_entry(tmp, member))
> +
> +#define __list_for_each_entry_mutable_reverse2(pos, head, member)	\
> +	__list_for_each_entry_mutable_reverse_internal(pos,		\
> +		__UNIQUE_ID(prev), head, member)
> +
> +#define __list_for_each_entry_mutable_reverse3(pos, prev, head, member)	\
> +	list_for_each_entry_safe_reverse(pos, prev, head, member)
> +
> +/**
> + * list_for_each_entry_mutable_reverse - iterate backwards over list safe against removal
> + * @pos:	the type * to use as a loop cursor.
> + * @...:	either (head, member) or (prev, head, member)
> + *
> + * prev:	another type * to use as optional temporary storage. The
> + *		temporary cursor is internal unless explicitly supplied by the
> + *		caller.
> + * head:	the head for your list.
> + * member:	the name of the list_head within the struct.
> + *
> + * Iterate backwards over list of given type, safe against removal
> + * of list entry.
> + */
> +#define list_for_each_entry_mutable_reverse(pos, ...)			\
> +	CONCATENATE(__list_for_each_entry_mutable_reverse,		\
> +		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
> +
>  /**
>   * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
>   * @pos:	the loop cursor used in the list_for_each_entry_safe loop
> @@ -1189,6 +1331,31 @@ static inline void hlist_splice_init(struct hlist_head *from,
>  	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
>  	     pos = n)
>  
> +#define __hlist_for_each_mutable_internal(pos, tmp, head)		\
> +	for (typeof(pos) tmp = (pos = (head)->first) ? pos->next : NULL; \
> +	     pos;							\
> +	     pos = tmp, tmp = pos ? pos->next : NULL)
> +
> +#define __hlist_for_each_mutable1(pos, head)				\
> +	__hlist_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
> +
> +#define __hlist_for_each_mutable2(pos, next, head)			\
> +	hlist_for_each_safe(pos, next, head)
> +
> +/**
> + * hlist_for_each_mutable - iterate over a hlist safe against entry removal
> + * @pos:	the &struct hlist_node to use as a loop cursor.
> + * @...:	either (head) or (next, head)
> + *
> + * next:	another &struct hlist_node to use as optional temporary storage.
> + *		The temporary cursor is internal unless explicitly supplied by
> + *		the caller.
> + * head:	the head for your hlist.
> + */
> +#define hlist_for_each_mutable(pos, ...)				\
> +	CONCATENATE(__hlist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
> +		(pos, __VA_ARGS__)
> +
>  #define hlist_entry_safe(ptr, type, member) \
>  	({ typeof(ptr) ____ptr = (ptr); \
>  	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> @@ -1224,18 +1391,44 @@ static inline void hlist_splice_init(struct hlist_head *from,
>  	for (; pos;							\
>  	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
>  
> -/**
> - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
> - * @pos:	the type * to use as a loop cursor.
> - * @n:		a &struct hlist_node to use as temporary storage
> - * @head:	the head for your list.
> - * @member:	the name of the hlist_node within the struct.
> +/*
> + * hlist_for_each_entry_safe is an old interface, use hlist_for_each_entry_mutable instead.
>   */
>  #define hlist_for_each_entry_safe(pos, n, head, member) 		\
>  	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
>  	     pos && ({ n = pos->member.next; 1; });			\
>  	     pos = hlist_entry_safe(n, typeof(*pos), member))
>  
> +#define __hlist_for_each_entry_mutable_internal(pos, tmp, head, member)	\
> +	for (struct hlist_node *tmp = (pos =				\
> +		hlist_entry_safe((head)->first, typeof(*pos), member)) ? \
> +		pos->member.next : NULL;				\
> +	     pos;							\
> +	     pos = hlist_entry_safe((tmp), typeof(*pos), member),	\
> +		tmp = pos ? pos->member.next : NULL)
> +
> +#define __hlist_for_each_entry_mutable2(pos, head, member)		\
> +	__hlist_for_each_entry_mutable_internal(pos,			\
> +		__UNIQUE_ID(next), head, member)
> +
> +#define __hlist_for_each_entry_mutable3(pos, next, head, member)	\
> +	hlist_for_each_entry_safe(pos, next, head, member)
> +
> +/**
> + * hlist_for_each_entry_mutable - iterate over hlist safe against entry removal
> + * @pos:	the type * to use as a loop cursor.
> + * @...:	either (head, member) or (next, head, member)
> + *
> + * next:	a &struct hlist_node to use as optional temporary storage. The
> + *		temporary cursor is internal unless explicitly supplied by the
> + *		caller.
> + * head:	the head for your hlist.
> + * member:	the name of the hlist_node within the struct.
> + */
> +#define hlist_for_each_entry_mutable(pos, ...)				\
> +	CONCATENATE(__hlist_for_each_entry_mutable,			\
> +		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
> +
>  /**
>   * hlist_count_nodes - count nodes in the hlist
>   * @head:	the head for your hlist.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
  2026-06-22  6:15   ` Kaitao Cheng
@ 2026-06-22 10:46     ` Andy Shevchenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2026-06-22 10:46 UTC (permalink / raw)
  To: Kaitao Cheng
  Cc: Alexei Starovoitov, Andrew Morton, David Hildenbrand, Jens Axboe,
	Tejun Heo, Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Paul E. McKenney, Shakeel Butt, Christian König,
	David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, LKML,
	open list:CONTROL GROUP (CGROUP), linux-ntfs-dev, Linux-Fsdevel,
	io-uring, audit, bpf, Network Development, dri-devel,
	linux-perf-use., linux-trace-kernel, kexec, live-patching,
	linux-modules, Linux Crypto Mailing List, Linux Power Management,
	rcu, sched-ext, linux-mm, virtualization, damon,
	clang-built-linux, chengkaitao, Muchun Song

On Mon, Jun 22, 2026 at 02:15:01PM +0800, Kaitao Cheng wrote:
> 在 2026/6/22 13:28, Alexei Starovoitov 写道:
> > On Sun, Jun 21, 2026 at 9:06 PM Kaitao Cheng <kaitao.cheng@linux.dev> wrote:

...

> >>  block/bfq-iosched.c                 |  17 +-
> >>  block/blk-cgroup.c                  |  12 +-
> >>  block/blk-flush.c                   |   4 +-
> >>  block/blk-iocost.c                  |  18 +-
> >>  block/blk-mq.c                      |   8 +-
> >>  block/blk-throttle.c                |   4 +-
> >>  block/kyber-iosched.c               |   4 +-
> >>  block/partitions/ldm.c              |   8 +-
> >>  block/sed-opal.c                    |   4 +-
> >>  include/linux/list.h                | 269 ++++++++++++++++++++++++----
> >>  include/linux/llist.h               |  81 +++++++--
> >>  init/initramfs.c                    |   5 +-
> >>  io_uring/cancel.c                   |   6 +-
> >>  io_uring/poll.c                     |   3 +-
> >>  io_uring/rw.c                       |   4 +-
> >>  io_uring/timeout.c                  |   8 +-
> >>  io_uring/uring_cmd.c                |   3 +-
> >>  kernel/audit_tree.c                 |   4 +-
> >>  kernel/audit_watch.c                |  16 +-
> >>  kernel/auditfilter.c                |   4 +-
> >>  kernel/auditsc.c                    |   4 +-
> >>  kernel/bpf/arena.c                  |  10 +-
> >>  kernel/bpf/arraymap.c               |   8 +-
> >>  kernel/bpf/bpf_local_storage.c      |   3 +-
> >>  kernel/bpf/bpf_lru_list.c           |  25 ++-
> >>  kernel/bpf/btf.c                    |  18 +-
> >>  kernel/bpf/cgroup.c                 |   7 +-
> >>  kernel/bpf/cpumap.c                 |   4 +-
> >>  kernel/bpf/devmap.c                 |  10 +-
> >>  kernel/bpf/helpers.c                |   8 +-
> >>  kernel/bpf/local_storage.c          |   4 +-
> >>  kernel/bpf/memalloc.c               |  16 +-
> >>  kernel/bpf/offload.c                |   8 +-
> >>  kernel/bpf/states.c                 |   4 +-
> >>  kernel/bpf/stream.c                 |   4 +-
> >>  kernel/bpf/verifier.c               |   6 +-
> >>  kernel/cgroup/cgroup-v1.c           |   4 +-
> >>  kernel/cgroup/cgroup.c              |  54 +++---
> >>  kernel/cgroup/dmem.c                |  12 +-
> >>  kernel/cgroup/rdma.c                |   8 +-
> >>  kernel/events/core.c                |  44 +++--
> >>  kernel/events/uprobes.c             |  12 +-
> >>  kernel/exit.c                       |   8 +-
> >>  kernel/fail_function.c              |   4 +-
> >>  kernel/gcov/clang.c                 |   4 +-
> >>  kernel/irq_work.c                   |   4 +-
> >>  kernel/kexec_core.c                 |   4 +-
> >>  kernel/kprobes.c                    |  16 +-
> >>  kernel/livepatch/core.c             |   4 +-
> >>  kernel/livepatch/core.h             |   4 +-
> >>  kernel/liveupdate/kho_block.c       |   4 +-
> >>  kernel/liveupdate/luo_flb.c         |   4 +-
> >>  kernel/locking/rwsem.c              |   2 +-
> >>  kernel/locking/test-ww_mutex.c      |   2 +-
> >>  kernel/module/main.c                |  11 +-
> >>  kernel/padata.c                     |   4 +-
> >>  kernel/power/snapshot.c             |   8 +-
> >>  kernel/power/wakelock.c             |   4 +-
> >>  kernel/printk/printk.c              |  11 +-
> >>  kernel/ptrace.c                     |   4 +-
> >>  kernel/rcu/rcutorture.c             |   3 +-
> >>  kernel/rcu/tasks.h                  |   9 +-
> >>  kernel/rcu/tree.c                   |   6 +-
> >>  kernel/resource.c                   |   4 +-
> >>  kernel/sched/core.c                 |   4 +-
> >>  kernel/sched/ext.c                  |  22 +--
> >>  kernel/sched/fair.c                 |  28 +--
> >>  kernel/sched/topology.c             |   4 +-
> >>  kernel/sched/wait.c                 |   4 +-
> >>  kernel/seccomp.c                    |   4 +-
> >>  kernel/signal.c                     |  11 +-
> >>  kernel/smp.c                        |   4 +-
> >>  kernel/taskstats.c                  |   8 +-
> >>  kernel/time/clockevents.c           |   6 +-
> >>  kernel/time/clocksource.c           |   4 +-
> >>  kernel/time/posix-cpu-timers.c      |   4 +-
> >>  kernel/time/posix-timers.c          |   3 +-
> >>  kernel/torture.c                    |   3 +-
> >>  kernel/trace/bpf_trace.c            |   4 +-
> >>  kernel/trace/ftrace.c               |  49 +++--
> >>  kernel/trace/ring_buffer.c          |  25 ++-
> >>  kernel/trace/trace.c                |  12 +-
> >>  kernel/trace/trace_dynevent.c       |   6 +-
> >>  kernel/trace/trace_dynevent.h       |   5 +-
> >>  kernel/trace/trace_events.c         |  35 ++--
> >>  kernel/trace/trace_events_filter.c  |   4 +-
> >>  kernel/trace/trace_events_hist.c    |   8 +-
> >>  kernel/trace/trace_events_trigger.c |  17 +-
> >>  kernel/trace/trace_events_user.c    |  16 +-
> >>  kernel/trace/trace_stat.c           |   4 +-
> >>  kernel/user-return-notifier.c       |   3 +-
> >>  kernel/workqueue.c                  |  16 +-
> >>  mm/backing-dev.c                    |   8 +-
> >>  mm/balloon.c                        |   8 +-
> >>  mm/cma.c                            |   4 +-
> >>  mm/compaction.c                     |   4 +-
> >>  mm/damon/core.c                     |   4 +-
> >>  mm/damon/sysfs-schemes.c            |   4 +-
> >>  mm/dmapool.c                        |   4 +-
> >>  mm/huge_memory.c                    |   8 +-
> >>  mm/hugetlb.c                        |  56 +++---
> >>  mm/hugetlb_vmemmap.c                |  16 +-
> >>  mm/khugepaged.c                     |  14 +-
> >>  mm/kmemleak.c                       |   7 +-
> >>  mm/ksm.c                            |  25 +--
> >>  mm/list_lru.c                       |   4 +-
> >>  mm/memcontrol-v1.c                  |   8 +-
> >>  mm/memory-failure.c                 |  12 +-
> >>  mm/memory-tiers.c                   |   4 +-
> >>  mm/migrate.c                        |  23 ++-
> >>  mm/mmu_notifier.c                   |   9 +-
> >>  mm/page_alloc.c                     |   8 +-
> >>  mm/page_reporting.c                 |   2 +-
> >>  mm/percpu.c                         |  11 +-
> >>  mm/pgtable-generic.c                |   4 +-
> >>  mm/rmap.c                           |  10 +-
> >>  mm/shmem.c                          |   9 +-
> >>  mm/slab_common.c                    |  14 +-
> >>  mm/slub.c                           |  33 ++--
> >>  mm/swapfile.c                       |   4 +-
> >>  mm/userfaultfd.c                    |  12 +-
> >>  mm/vmalloc.c                        |  24 +--
> >>  mm/vmscan.c                         |   7 +-
> >>  mm/zsmalloc.c                       |   4 +-
> >>  124 files changed, 875 insertions(+), 681 deletions(-)
> > 
> > Not sure what you were thinking, but this diff stat
> > is not landable.
> 
> [PATCH v3 1/7] and [PATCH v3 2/7] contain the main logic and can
> be merged directly. They are also compatible with the old API.
> [PATCH v3 3/7] through [PATCH v3 7/7] are just simple interface
> replacements and do not change any functional logic. They can be
> left unmerged for now; individual modules can pick them up later
> if needed.
> 
> In v2, Andy Shevchenko mentioned: "If it's done by Linus himself
> during the day when he prepares -rc1, it's fine."

Yes, but you need to get his blessing first to go with this.
Have you communicated with him on this?

> Even so, the
> changes in this patch series are indeed quite large and touch
> almost every subsystem. I have only converted part of them for
> now, so I wanted to send this out first and see what people think.

That's why it's better to provide a script to convert (e.g., coccinelle)
instead of tons of patches.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
  2026-06-22  5:28 ` [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Alexei Starovoitov
  2026-06-22  6:15   ` Kaitao Cheng
@ 2026-06-22 11:27   ` David Hildenbrand (Arm)
  1 sibling, 0 replies; 19+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-22 11:27 UTC (permalink / raw)
  To: Alexei Starovoitov, Kaitao Cheng
  Cc: Andrew Morton, Jens Axboe, Tejun Heo, Alexander Viro,
	Christian Brauner, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Johannes Weiner, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Thomas Gleixner,
	Juri Lelli, Vincent Guittot, Paul Moore, Andy Shevchenko,
	Paul E. McKenney, Shakeel Butt, Christian König,
	David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, LKML,
	open list:CONTROL GROUP (CGROUP), linux-ntfs-dev, Linux-Fsdevel,
	io-uring, audit, bpf, Network Development, dri-devel,
	linux-perf-use., linux-trace-kernel, kexec, live-patching,
	linux-modules, Linux Crypto Mailing List, Linux Power Management,
	rcu, sched-ext, linux-mm, virtualization, damon,
	clang-built-linux, chengkaitao

On 6/22/26 07:28, Alexei Starovoitov wrote:
> On Sun, Jun 21, 2026 at 9:06 PM Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>>
>> From: chengkaitao <chengkaitao@kylinos.cn>
>>
>> The list_for_each*_safe() helpers are used when the loop body may remove
>> the current entry.  Their current interface, however, forces every caller
>> to define a temporary cursor outside the macro and pass it in, even when
>> the caller never uses that cursor directly.  For most call sites this
>> extra cursor is just boilerplate required by the macro implementation.
>>
>> This is awkward because the saved next pointer is an internal detail of
>> the iteration.  Callers that only remove or move the current entry do not
>> need to spell it out.
>>
>> The _safe() suffix has also caused confusion.  Christian Koenig pointed
>> out that the name is easy to read as a thread-safe variant, especially
>> for beginners, even though it only means that the iterator keeps enough
>> state to tolerate removal of the current entry.  He suggested _mutable()
>> as a clearer description of what the loop permits.
>>
>> Add *_mutable() iterator variants for list, hlist and llist.  The new
>> helpers are variadic and support both forms.  In the common case, the
>> caller omits the temporary cursor and the macro creates a unique internal
>> cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
>> explicit temporary cursor, the caller can still pass it and the helper
>> keeps the existing *_safe() behaviour.
>>
>> For example, a call site may use the shorter form:
>>
>>   list_for_each_entry_mutable(pos, head, member)
>>
>> or keep the explicit temporary cursor form:
>>
>>   list_for_each_entry_mutable(pos, tmp, head, member)
>>
>> The existing *_safe() helpers remain available for compatibility.  This
>> series only converts users in mm, block, kernel, init and io_uring.  If
>> this approach looks acceptable, the remaining users can be converted in
>> follow-up series.
>>
>> Changes in v3 (Christian König, Andy Shevchenko):
>> - Convert safe list walks to mutable iterators
>>
>> Changes in v2 (Muchun Song, Andy Shevchenko):
>> - Drop the list_for_each_entry_mutable*() helpers from v1 and make the
>>   cursor change directly in the existing list_for_each_entry*() helpers.
>> - Open-code special list walks that rely on updating the loop cursor in
>>   the body, preserving their existing traversal semantics.
>>
>> Link to v2:
>> https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/
>>
>> Link to v1:
>> https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/
>>
>> Kaitao Cheng (7):
>>   list: Add mutable iterator variants
>>   llist: Add mutable iterator variants
>>   mm: Use mutable list iterators
>>   block: Use mutable list iterators
>>   kernel: Use mutable list iterators
>>   initramfs: Use mutable list iterator
>>   io_uring: Use mutable list iterators
>>
>>  block/bfq-iosched.c                 |  17 +-
>>  block/blk-cgroup.c                  |  12 +-
>>  block/blk-flush.c                   |   4 +-
>>  block/blk-iocost.c                  |  18 +-
>>  block/blk-mq.c                      |   8 +-
>>  block/blk-throttle.c                |   4 +-
>>  block/kyber-iosched.c               |   4 +-
>>  block/partitions/ldm.c              |   8 +-
>>  block/sed-opal.c                    |   4 +-
>>  include/linux/list.h                | 269 ++++++++++++++++++++++++----
>>  include/linux/llist.h               |  81 +++++++--
>>  init/initramfs.c                    |   5 +-
>>  io_uring/cancel.c                   |   6 +-
>>  io_uring/poll.c                     |   3 +-
>>  io_uring/rw.c                       |   4 +-
>>  io_uring/timeout.c                  |   8 +-
>>  io_uring/uring_cmd.c                |   3 +-
>>  kernel/audit_tree.c                 |   4 +-
>>  kernel/audit_watch.c                |  16 +-
>>  kernel/auditfilter.c                |   4 +-
>>  kernel/auditsc.c                    |   4 +-
>>  kernel/bpf/arena.c                  |  10 +-
>>  kernel/bpf/arraymap.c               |   8 +-
>>  kernel/bpf/bpf_local_storage.c      |   3 +-
>>  kernel/bpf/bpf_lru_list.c           |  25 ++-
>>  kernel/bpf/btf.c                    |  18 +-
>>  kernel/bpf/cgroup.c                 |   7 +-
>>  kernel/bpf/cpumap.c                 |   4 +-
>>  kernel/bpf/devmap.c                 |  10 +-
>>  kernel/bpf/helpers.c                |   8 +-
>>  kernel/bpf/local_storage.c          |   4 +-
>>  kernel/bpf/memalloc.c               |  16 +-
>>  kernel/bpf/offload.c                |   8 +-
>>  kernel/bpf/states.c                 |   4 +-
>>  kernel/bpf/stream.c                 |   4 +-
>>  kernel/bpf/verifier.c               |   6 +-
>>  kernel/cgroup/cgroup-v1.c           |   4 +-
>>  kernel/cgroup/cgroup.c              |  54 +++---
>>  kernel/cgroup/dmem.c                |  12 +-
>>  kernel/cgroup/rdma.c                |   8 +-
>>  kernel/events/core.c                |  44 +++--
>>  kernel/events/uprobes.c             |  12 +-
>>  kernel/exit.c                       |   8 +-
>>  kernel/fail_function.c              |   4 +-
>>  kernel/gcov/clang.c                 |   4 +-
>>  kernel/irq_work.c                   |   4 +-
>>  kernel/kexec_core.c                 |   4 +-
>>  kernel/kprobes.c                    |  16 +-
>>  kernel/livepatch/core.c             |   4 +-
>>  kernel/livepatch/core.h             |   4 +-
>>  kernel/liveupdate/kho_block.c       |   4 +-
>>  kernel/liveupdate/luo_flb.c         |   4 +-
>>  kernel/locking/rwsem.c              |   2 +-
>>  kernel/locking/test-ww_mutex.c      |   2 +-
>>  kernel/module/main.c                |  11 +-
>>  kernel/padata.c                     |   4 +-
>>  kernel/power/snapshot.c             |   8 +-
>>  kernel/power/wakelock.c             |   4 +-
>>  kernel/printk/printk.c              |  11 +-
>>  kernel/ptrace.c                     |   4 +-
>>  kernel/rcu/rcutorture.c             |   3 +-
>>  kernel/rcu/tasks.h                  |   9 +-
>>  kernel/rcu/tree.c                   |   6 +-
>>  kernel/resource.c                   |   4 +-
>>  kernel/sched/core.c                 |   4 +-
>>  kernel/sched/ext.c                  |  22 +--
>>  kernel/sched/fair.c                 |  28 +--
>>  kernel/sched/topology.c             |   4 +-
>>  kernel/sched/wait.c                 |   4 +-
>>  kernel/seccomp.c                    |   4 +-
>>  kernel/signal.c                     |  11 +-
>>  kernel/smp.c                        |   4 +-
>>  kernel/taskstats.c                  |   8 +-
>>  kernel/time/clockevents.c           |   6 +-
>>  kernel/time/clocksource.c           |   4 +-
>>  kernel/time/posix-cpu-timers.c      |   4 +-
>>  kernel/time/posix-timers.c          |   3 +-
>>  kernel/torture.c                    |   3 +-
>>  kernel/trace/bpf_trace.c            |   4 +-
>>  kernel/trace/ftrace.c               |  49 +++--
>>  kernel/trace/ring_buffer.c          |  25 ++-
>>  kernel/trace/trace.c                |  12 +-
>>  kernel/trace/trace_dynevent.c       |   6 +-
>>  kernel/trace/trace_dynevent.h       |   5 +-
>>  kernel/trace/trace_events.c         |  35 ++--
>>  kernel/trace/trace_events_filter.c  |   4 +-
>>  kernel/trace/trace_events_hist.c    |   8 +-
>>  kernel/trace/trace_events_trigger.c |  17 +-
>>  kernel/trace/trace_events_user.c    |  16 +-
>>  kernel/trace/trace_stat.c           |   4 +-
>>  kernel/user-return-notifier.c       |   3 +-
>>  kernel/workqueue.c                  |  16 +-
>>  mm/backing-dev.c                    |   8 +-
>>  mm/balloon.c                        |   8 +-
>>  mm/cma.c                            |   4 +-
>>  mm/compaction.c                     |   4 +-
>>  mm/damon/core.c                     |   4 +-
>>  mm/damon/sysfs-schemes.c            |   4 +-
>>  mm/dmapool.c                        |   4 +-
>>  mm/huge_memory.c                    |   8 +-
>>  mm/hugetlb.c                        |  56 +++---
>>  mm/hugetlb_vmemmap.c                |  16 +-
>>  mm/khugepaged.c                     |  14 +-
>>  mm/kmemleak.c                       |   7 +-
>>  mm/ksm.c                            |  25 +--
>>  mm/list_lru.c                       |   4 +-
>>  mm/memcontrol-v1.c                  |   8 +-
>>  mm/memory-failure.c                 |  12 +-
>>  mm/memory-tiers.c                   |   4 +-
>>  mm/migrate.c                        |  23 ++-
>>  mm/mmu_notifier.c                   |   9 +-
>>  mm/page_alloc.c                     |   8 +-
>>  mm/page_reporting.c                 |   2 +-
>>  mm/percpu.c                         |  11 +-
>>  mm/pgtable-generic.c                |   4 +-
>>  mm/rmap.c                           |  10 +-
>>  mm/shmem.c                          |   9 +-
>>  mm/slab_common.c                    |  14 +-
>>  mm/slub.c                           |  33 ++--
>>  mm/swapfile.c                       |   4 +-
>>  mm/userfaultfd.c                    |  12 +-
>>  mm/vmalloc.c                        |  24 +--
>>  mm/vmscan.c                         |   7 +-
>>  mm/zsmalloc.c                       |   4 +-
>>  124 files changed, 875 insertions(+), 681 deletions(-)
> 
> Not sure what you were thinking, but this diff stat
> is not landable.

Agreed. If we decide we want this, I guess we should target per-subsystem
conversions.

If this goes through the MM tree, I would even appreciate doing this on a per-MM
component granularity.

(unless we have some magic "Linus converts all of them" script, which I doubt we
will have)

Is there a way forward to replace list_for_each_*_safe entirely, possibly just
reusing the old name but simply the parameter?

-- 
Cheers,

David

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/7] kernel: Use mutable list iterators
  2026-06-22  4:28 ` [PATCH v3 5/7] kernel: " Kaitao Cheng
  2026-06-22  5:22     ` bot+bpf-ci
@ 2026-06-22 19:03   ` Eduard Zingerman
  1 sibling, 0 replies; 19+ messages in thread
From: Eduard Zingerman @ 2026-06-22 19:03 UTC (permalink / raw)
  To: Kaitao Cheng, Paul Moore, Eric Paris, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Kumar Kartikeya Dwivedi,
	David S. Miller, Jakub Kicinski, Jesper Dangaard Brouer,
	John Fastabend, Tejun Heo, Johannes Weiner, Michal Koutný,
	Maarten Lankhorst, Maxime Ripard, Natalie Vock, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Masami Hiramatsu, Oleg Nesterov, Peter Oberparleiter,
	Andrew Morton, Baoquan He, Mike Rapoport, Pasha Tatashin,
	Pratyush Yadav, Naveen N Rao, Josh Poimboeuf, Jiri Kosina,
	Miroslav Benes, Petr Mladek, Will Deacon, Boqun Feng,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Steffen Klassert, Daniel Jordan, Rafael J. Wysocki,
	Davidlohr Bueso, Paul E. McKenney, Josh Triplett,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Uladzislau Rezki, Juri Lelli, Vincent Guittot, Kees Cook,
	Balbir Singh, Anna-Maria Behnsen, Thomas Gleixner, John Stultz,
	KP Singh, Matt Bobrowski, Nathan Chancellor, Martin KaFai Lau,
	Song Liu, Mark Rutland, Mathieu Desnoyers, Dietmar Eggemann,
	David Vernet, Steven Rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	Kaitao Cheng

On Mon, 2026-06-22 at 12:28 +0800, Kaitao Cheng wrote:
> From: Kaitao Cheng <chengkaitao@kylinos.cn>
> 
> The safe list iteration helpers require callers to provide a temporary
> cursor even when the cursor is only used internally by the loop. This
> leaves many functions with otherwise unused variables whose only purpose
> is to satisfy the old iterator interface.
> 
> Use the mutable list iteration helpers for those cases. The mutable
> helpers keep the same removal-safe traversal semantics, while allowing
> the temporary cursor to be internal to the macro when the caller does
> not need to observe it.
> 
> Convert list, hlist and llist users under kernel/ where the temporary
> cursor is not used outside the iteration. Keep the explicit cursor form
> where the next entry is still needed by the surrounding code.
> 
> No functional change intended.
> 
> Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
> ---

Beside the fact that this does not apply,
I don't see a reason why is this needed for BPF sub-tree.

[...]

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-06-22 19:03 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22  4:05 [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Kaitao Cheng
2026-06-22  4:05 ` [PATCH v3 1/7] list: Add mutable iterator variants Kaitao Cheng
2026-06-22  8:42   ` David Laight
2026-06-22  8:51   ` Christian König
2026-06-22  4:05 ` [PATCH v3 2/7] llist: " Kaitao Cheng
2026-06-22  4:15 ` [PATCH v3 3/7] mm: Use mutable list iterators Kaitao Cheng
2026-06-22  4:57   ` sashiko-bot
2026-06-22  4:28 ` [PATCH v3 5/7] kernel: " Kaitao Cheng
2026-06-22  5:22   ` bot+bpf-ci
2026-06-22  5:22     ` bot+bpf-ci
2026-06-22 19:03   ` Eduard Zingerman
2026-06-22  4:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator Kaitao Cheng
2026-06-22  4:41 ` [PATCH v3 7/7] io_uring: Use mutable list iterators Kaitao Cheng
2026-06-22  4:42 ` [PATCH v3 4/7] block: " Kaitao Cheng
2026-06-22  5:28 ` [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state Alexei Starovoitov
2026-06-22  6:15   ` Kaitao Cheng
2026-06-22 10:46     ` Andy Shevchenko
2026-06-22 11:27   ` David Hildenbrand (Arm)
2026-06-22  8:37 ` Jani Nikula

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.