| From dcfea72e79b0aa7a057c8f6024169d86a1bbc84b Mon Sep 17 00:00:00 2001 |
| From: "Jason A. Donenfeld" <Jason@zx2c4.com> |
| Date: Wed, 8 Jan 2020 16:59:02 -0500 |
| Subject: net: introduce skb_list_walk_safe for skb segment walking |
| |
| From: Jason A. Donenfeld <Jason@zx2c4.com> |
| |
| commit dcfea72e79b0aa7a057c8f6024169d86a1bbc84b upstream. |
| |
| As part of the continual effort to remove direct usage of skb->next and |
| skb->prev, this patch adds a helper for iterating through the |
| singly-linked variant of skb lists, which are used for lists of GSO |
| packet. The name "skb_list_..." has been chosen to match the existing |
| function, "kfree_skb_list, which also operates on these singly-linked |
| lists, and the "..._walk_safe" part is the same idiom as elsewhere in |
| the kernel. |
| |
| This patch removes the helper from wireguard and puts it into |
| linux/skbuff.h, while making it a bit more robust for general usage. In |
| particular, parenthesis are added around the macro argument usage, and it |
| now accounts for trying to iterate through an already-null skb pointer, |
| which will simply run the iteration zero times. This latter enhancement |
| means it can be used to replace both do { ... } while and while (...) |
| open-coded idioms. |
| |
| This should take care of these three possible usages, which match all |
| current methods of iterations. |
| |
| skb_list_walk_safe(segs, skb, next) { ... } |
| skb_list_walk_safe(skb, skb, next) { ... } |
| skb_list_walk_safe(segs, skb, segs) { ... } |
| |
| Gcc appears to generate efficient code for each of these. |
| |
| Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| [ Just the skbuff.h changes for backporting - gregkh] |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/skbuff.h | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/include/linux/skbuff.h |
| +++ b/include/linux/skbuff.h |
| @@ -1363,6 +1363,11 @@ static inline void skb_mark_not_on_list( |
| skb->next = NULL; |
| } |
| |
| +/* Iterate through singly-linked GSO fragments of an skb. */ |
| +#define skb_list_walk_safe(first, skb, next) \ |
| + for ((skb) = (first), (next) = (skb) ? (skb)->next : NULL; (skb); \ |
| + (skb) = (next), (next) = (skb) ? (skb)->next : NULL) |
| + |
| static inline void skb_list_del_init(struct sk_buff *skb) |
| { |
| __list_del_entry(&skb->list); |