From: Kaitao Cheng <[email protected]>

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 <[email protected]>
---
 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


Reply via email to