On 6/22/26 06:05, Kaitao Cheng wrote: > From: Kaitao Cheng <[email protected]> > > 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 <[email protected]> > --- > 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.
