Skip to content

Commit 6ea0032

Browse files
committed
Merge branch 'reduce-open-coded-skb-next-access-for-gso-segment-walking'
Jason A. Donenfeld says: ==================== reduce open coded skb->next access for gso segment walking This patchset introduces the skb_list_walk_safe helper macro, in order to add some sanity to the myrid ways drivers have of walking through gso segments. The goal is to reduce future bugs commonly caused by open coding these sorts of things, and to in the future make it easier to swap out the underlying list representation. This first patch series addresses the easy uses of drivers iterating over the returned list of skb_gso_segments, for drivers that live in drivers/net/*. There are still other use cases to tackle later for net/*, and after these low-hanging fruits are taken care of, I imagine there are more subtle cases of gso segment walking that isn't just a direct return value from skb_gso_segments, and eventually this will have to be tackled. This series is the first in that direction. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 542d306 + 66de4b1 commit 6ea0032

File tree

9 files changed

+31
-53
lines changed

9 files changed

+31
-53
lines changed

drivers/net/ethernet/broadcom/tg3.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7874,8 +7874,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);
78747874
static int tg3_tso_bug(struct tg3 *tp, struct tg3_napi *tnapi,
78757875
struct netdev_queue *txq, struct sk_buff *skb)
78767876
{
7877-
struct sk_buff *segs, *nskb;
78787877
u32 frag_cnt_est = skb_shinfo(skb)->gso_segs * 3;
7878+
struct sk_buff *segs, *seg, *next;
78797879

78807880
/* Estimate the number of fragments in the worst case */
78817881
if (unlikely(tg3_tx_avail(tnapi) <= frag_cnt_est)) {
@@ -7898,12 +7898,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct tg3_napi *tnapi,
78987898
if (IS_ERR(segs) || !segs)
78997899
goto tg3_tso_bug_end;
79007900

7901-
do {
7902-
nskb = segs;
7903-
segs = segs->next;
7904-
nskb->next = NULL;
7905-
tg3_start_xmit(nskb, tp->dev);
7906-
} while (segs);
7901+
skb_list_walk_safe(segs, seg, next) {
7902+
skb_mark_not_on_list(seg);
7903+
tg3_start_xmit(seg, tp->dev);
7904+
}
79077905

79087906
tg3_tso_bug_end:
79097907
dev_consume_skb_any(skb);

drivers/net/ethernet/myricom/myri10ge/myri10ge.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,7 +2892,7 @@ static netdev_tx_t myri10ge_xmit(struct sk_buff *skb,
28922892
static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb,
28932893
struct net_device *dev)
28942894
{
2895-
struct sk_buff *segs, *curr;
2895+
struct sk_buff *segs, *curr, *next;
28962896
struct myri10ge_priv *mgp = netdev_priv(dev);
28972897
struct myri10ge_slice_state *ss;
28982898
netdev_tx_t status;
@@ -2901,10 +2901,8 @@ static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb,
29012901
if (IS_ERR(segs))
29022902
goto drop;
29032903

2904-
while (segs) {
2905-
curr = segs;
2906-
segs = segs->next;
2907-
curr->next = NULL;
2904+
skb_list_walk_safe(segs, curr, next) {
2905+
skb_mark_not_on_list(curr);
29082906
status = myri10ge_xmit(curr, dev);
29092907
if (status != 0) {
29102908
dev_kfree_skb_any(curr);

drivers/net/ethernet/sfc/tx.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,9 @@ static int efx_tx_tso_fallback(struct efx_tx_queue *tx_queue,
307307
dev_consume_skb_any(skb);
308308
skb = segments;
309309

310-
while (skb) {
311-
next = skb->next;
312-
skb->next = NULL;
313-
310+
skb_list_walk_safe(skb, skb, next) {
311+
skb_mark_not_on_list(skb);
314312
efx_enqueue_skb(tx_queue, skb);
315-
skb = next;
316313
}
317314

318315
return 0;

drivers/net/ethernet/sun/sunvnet_common.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,7 +1223,7 @@ vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb,
12231223
{
12241224
struct net_device *dev = VNET_PORT_TO_NET_DEVICE(port);
12251225
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
1226-
struct sk_buff *segs;
1226+
struct sk_buff *segs, *curr, *next;
12271227
int maclen, datalen;
12281228
int status;
12291229
int gso_size, gso_type, gso_segs;
@@ -1282,11 +1282,8 @@ vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb,
12821282
skb_reset_mac_header(skb);
12831283

12841284
status = 0;
1285-
while (segs) {
1286-
struct sk_buff *curr = segs;
1287-
1288-
segs = segs->next;
1289-
curr->next = NULL;
1285+
skb_list_walk_safe(segs, curr, next) {
1286+
skb_mark_not_on_list(curr);
12901287
if (port->tso && curr->len > dev->mtu) {
12911288
skb_shinfo(curr)->gso_size = gso_size;
12921289
skb_shinfo(curr)->gso_type = gso_type;

drivers/net/tap.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
341341
features |= tap->tap_features;
342342
if (netif_needs_gso(skb, features)) {
343343
struct sk_buff *segs = __skb_gso_segment(skb, features, false);
344+
struct sk_buff *next;
344345

345346
if (IS_ERR(segs))
346347
goto drop;
@@ -352,16 +353,13 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
352353
}
353354

354355
consume_skb(skb);
355-
while (segs) {
356-
struct sk_buff *nskb = segs->next;
357-
358-
segs->next = NULL;
359-
if (ptr_ring_produce(&q->ring, segs)) {
360-
kfree_skb(segs);
361-
kfree_skb_list(nskb);
356+
skb_list_walk_safe(segs, skb, next) {
357+
skb_mark_not_on_list(skb);
358+
if (ptr_ring_produce(&q->ring, skb)) {
359+
kfree_skb(skb);
360+
kfree_skb_list(next);
362361
break;
363362
}
364-
segs = nskb;
365363
}
366364
} else {
367365
/* If we receive a partial checksum and the tap side

drivers/net/usb/r8152.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,8 +1897,8 @@ static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
18971897
{
18981898
if (skb_shinfo(skb)->gso_size) {
18991899
netdev_features_t features = tp->netdev->features;
1900+
struct sk_buff *segs, *seg, *next;
19001901
struct sk_buff_head seg_list;
1901-
struct sk_buff *segs, *nskb;
19021902

19031903
features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
19041904
segs = skb_gso_segment(skb, features);
@@ -1907,12 +1907,10 @@ static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
19071907

19081908
__skb_queue_head_init(&seg_list);
19091909

1910-
do {
1911-
nskb = segs;
1912-
segs = segs->next;
1913-
nskb->next = NULL;
1914-
__skb_queue_tail(&seg_list, nskb);
1915-
} while (segs);
1910+
skb_list_walk_safe(segs, seg, next) {
1911+
skb_mark_not_on_list(seg);
1912+
__skb_queue_tail(&seg_list, seg);
1913+
}
19161914

19171915
skb_queue_splice(&seg_list, list);
19181916
dev_kfree_skb(skb);

drivers/net/wireguard/device.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,4 @@ struct wg_device {
6262
int wg_device_init(void);
6363
void wg_device_uninit(void);
6464

65-
/* Later after the dust settles, this can be moved into include/linux/skbuff.h,
66-
* where virtually all code that deals with GSO segs can benefit, around ~30
67-
* drivers as of writing.
68-
*/
69-
#define skb_list_walk_safe(first, skb, next) \
70-
for (skb = first, next = skb->next; skb; \
71-
skb = next, next = skb ? skb->next : NULL)
72-
7365
#endif /* _WG_DEVICE_H */

drivers/net/wireless/intel/iwlwifi/mvm/tx.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -847,10 +847,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
847847
else if (next)
848848
consume_skb(skb);
849849

850-
while (next) {
851-
tmp = next;
852-
next = tmp->next;
853-
850+
skb_list_walk_safe(next, tmp, next) {
854851
memcpy(tmp->cb, cb, sizeof(tmp->cb));
855852
/*
856853
* Compute the length of all the data added for the A-MSDU.
@@ -880,9 +877,7 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
880877
skb_shinfo(tmp)->gso_size = 0;
881878
}
882879

883-
tmp->prev = NULL;
884-
tmp->next = NULL;
885-
880+
skb_mark_not_on_list(tmp);
886881
__skb_queue_tail(mpdus_skb, tmp);
887882
i++;
888883
}

include/linux/skbuff.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,11 @@ static inline void skb_mark_not_on_list(struct sk_buff *skb)
14781478
skb->next = NULL;
14791479
}
14801480

1481+
/* Iterate through singly-linked GSO fragments of an skb. */
1482+
#define skb_list_walk_safe(first, skb, next) \
1483+
for ((skb) = (first), (next) = (skb) ? (skb)->next : NULL; (skb); \
1484+
(skb) = (next), (next) = (skb) ? (skb)->next : NULL)
1485+
14811486
static inline void skb_list_del_init(struct sk_buff *skb)
14821487
{
14831488
__list_del_entry(&skb->list);

0 commit comments

Comments
 (0)