* [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
` (4 more replies)
0 siblings, 5 replies; 11+ 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] 11+ 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
` (3 subsequent siblings)
4 siblings, 2 replies; 11+ 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] 11+ 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:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator Kaitao Cheng
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ 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] 11+ 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
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:39 ` 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
4 siblings, 0 replies; 11+ 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] 11+ 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
` (2 preceding siblings ...)
2026-06-22 4:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator 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
4 siblings, 2 replies; 11+ 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] 11+ 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; 11+ 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] 11+ 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
` (3 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
4 siblings, 0 replies; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ messages in thread
end of thread, other threads:[~2026-06-22 11:27 UTC | newest]
Thread overview: 11+ 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:39 ` [PATCH v3 6/7] initramfs: Use mutable list iterator 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox