[PATCH v4 4/4] scripts/list: Add mutable iterator variants
From: Kaitao Cheng
Date: Thu Jul 30 2026 - 06:12:47 EST
From: Kaitao Cheng <chengkaitao@xxxxxxxxxx>
The kernel has added mutable iterator variants, so sync the scripts/list
implementation accordingly. The safe iterators require callers to declare
and pass a temporary cursor even when the loop body only needs to remove
the current entry.
Add list_for_each_entry_mutable() and hlist_for_each_entry_mutable() so
callers can use removal-safe iteration without exposing the temporary
cursor. Keep the existing safe variants for users that need direct access
to the cursor, and document the distinction.
Add local __PASTE() and __UNIQUE_ID() helpers to generate the internal
cursor name, matching the format used by include/linux/compiler.h.
Signed-off-by: Kaitao Cheng <chengkaitao@xxxxxxxxxx>
---
scripts/include/list.h | 56 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/scripts/include/list.h b/scripts/include/list.h
index 8bdcaadca709..ff1c84339344 100644
--- a/scripts/include/list.h
+++ b/scripts/include/list.h
@@ -9,6 +9,16 @@
/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+#ifndef __PASTE
+/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
+#define ___PASTE(a, b) a##b
+#define __PASTE(a, b) ___PASTE(a, b)
+#endif
+
+#ifndef __UNIQUE_ID
+#define __UNIQUE_ID(name) __PASTE(__UNIQUE_ID_, __PASTE(name, __PASTE(_, __COUNTER__)))
+#endif
+
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
@@ -298,11 +308,15 @@ static inline int list_empty(const struct list_head *head)
pos = list_prev_entry(pos, member))
/**
- * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
+ * list_for_each_entry_safe - iterate over list of given type safe against
+ * removal of list entry with a caller-provided temporary cursor
* @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.
+ *
+ * If the caller does not need to access the temporary cursor, 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), \
@@ -310,6 +324,22 @@ static inline int list_empty(const 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(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))
+
+/**
+ * list_for_each_entry_mutable - iterate over a list safe against removal of
+ * list entry with an internal temporary cursor
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_mutable(pos, head, member) \
+ __list_for_each_entry_mutable(pos, __UNIQUE_ID(next), head, member)
+
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
@@ -414,15 +444,37 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
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
+ * hlist_for_each_entry_safe - iterate over list of given type safe against
+ * removal of list entry with a caller-provided temporary cursor
* @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.
+ *
+ * If the caller does not need to access the temporary cursor, 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(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)
+
+/**
+ * hlist_for_each_entry_mutable - iterate over hlist safe against removal of
+ * list entry with an internal temporary cursor
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your hlist.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_mutable(pos, head, member) \
+ __hlist_for_each_entry_mutable(pos, __UNIQUE_ID(next), head, member)
+
#endif /* LIST_H */
--
2.43.0