Commit 2b133adf authored by David S. Miller's avatar David S. Miller

Merge branch 'skb_list_walk_safe-refactoring'

Jason A. Donenfeld says:

====================
skb_list_walk_safe refactoring for net/*'s skb_gso_segment usage

This patchset adjusts all return values of skb_gso_segment in net/* to
use the new skb_list_walk_safe helper.

First we fix a minor bug in the helper macro that didn't come up in the
last patchset's uses. Then we adjust several cases throughout net/. The
xfrm changes were a bit hairy, but doable. Reading and thinking about
the code in mac80211 indicates a memory leak, which the commit
addresses. All the other cases were pretty trivial.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ec22ab00 9f3ef3d7
...@@ -1479,9 +1479,9 @@ static inline void skb_mark_not_on_list(struct sk_buff *skb) ...@@ -1479,9 +1479,9 @@ static inline void skb_mark_not_on_list(struct sk_buff *skb)
} }
/* Iterate through singly-linked GSO fragments of an skb. */ /* Iterate through singly-linked GSO fragments of an skb. */
#define skb_list_walk_safe(first, skb, next) \ #define skb_list_walk_safe(first, skb, next_skb) \
for ((skb) = (first), (next) = (skb) ? (skb)->next : NULL; (skb); \ for ((skb) = (first), (next_skb) = (skb) ? (skb)->next : NULL; (skb); \
(skb) = (next), (next) = (skb) ? (skb)->next : NULL) (skb) = (next_skb), (next_skb) = (skb) ? (skb)->next : NULL)
static inline void skb_list_del_init(struct sk_buff *skb) static inline void skb_list_del_init(struct sk_buff *skb)
{ {
......
...@@ -240,8 +240,8 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s ...@@ -240,8 +240,8 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
static int ip_finish_output_gso(struct net *net, struct sock *sk, static int ip_finish_output_gso(struct net *net, struct sock *sk,
struct sk_buff *skb, unsigned int mtu) struct sk_buff *skb, unsigned int mtu)
{ {
struct sk_buff *segs, *nskb;
netdev_features_t features; netdev_features_t features;
struct sk_buff *segs;
int ret = 0; int ret = 0;
/* common case: seglen is <= mtu /* common case: seglen is <= mtu
...@@ -272,8 +272,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, ...@@ -272,8 +272,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
consume_skb(skb); consume_skb(skb);
do { skb_list_walk_safe(segs, segs, nskb) {
struct sk_buff *nskb = segs->next;
int err; int err;
skb_mark_not_on_list(segs); skb_mark_not_on_list(segs);
...@@ -281,8 +280,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, ...@@ -281,8 +280,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
if (err && ret == 0) if (err && ret == 0)
ret = err; ret = err;
segs = nskb; }
} while (segs);
return ret; return ret;
} }
......
...@@ -2104,8 +2104,7 @@ static int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -2104,8 +2104,7 @@ static int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
BUILD_BUG_ON(sizeof(struct udp_skb_cb) > SKB_SGO_CB_OFFSET); BUILD_BUG_ON(sizeof(struct udp_skb_cb) > SKB_SGO_CB_OFFSET);
__skb_push(skb, -skb_mac_offset(skb)); __skb_push(skb, -skb_mac_offset(skb));
segs = udp_rcv_segment(sk, skb, true); segs = udp_rcv_segment(sk, skb, true);
for (skb = segs; skb; skb = next) { skb_list_walk_safe(segs, skb, next) {
next = skb->next;
__skb_pull(skb, skb_transport_offset(skb)); __skb_pull(skb, skb_transport_offset(skb));
ret = udp_queue_rcv_one_skb(sk, skb); ret = udp_queue_rcv_one_skb(sk, skb);
if (ret > 0) if (ret > 0)
......
...@@ -690,8 +690,7 @@ static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -690,8 +690,7 @@ static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
__skb_push(skb, -skb_mac_offset(skb)); __skb_push(skb, -skb_mac_offset(skb));
segs = udp_rcv_segment(sk, skb, false); segs = udp_rcv_segment(sk, skb, false);
for (skb = segs; skb; skb = next) { skb_list_walk_safe(segs, skb, next) {
next = skb->next;
__skb_pull(skb, skb_transport_offset(skb)); __skb_pull(skb, skb_transport_offset(skb));
ret = udpv6_queue_rcv_one_skb(sk, skb); ret = udpv6_queue_rcv_one_skb(sk, skb);
......
...@@ -3949,18 +3949,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -3949,18 +3949,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
} }
} }
next = skb; skb_list_walk_safe(skb, skb, next) {
while (next) { skb_mark_not_on_list(skb);
skb = next;
next = skb->next;
skb->prev = NULL;
skb->next = NULL;
skb = ieee80211_build_hdr(sdata, skb, info_flags, skb = ieee80211_build_hdr(sdata, skb, info_flags,
sta, ctrl_flags); sta, ctrl_flags);
if (IS_ERR(skb)) if (IS_ERR(skb)) {
kfree_skb_list(next);
goto out; goto out;
}
ieee80211_tx_stats(dev, skb->len); ieee80211_tx_stats(dev, skb->len);
......
...@@ -778,7 +778,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) ...@@ -778,7 +778,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
{ {
unsigned int queued; unsigned int queued;
struct nfqnl_instance *queue; struct nfqnl_instance *queue;
struct sk_buff *skb, *segs; struct sk_buff *skb, *segs, *nskb;
int err = -ENOBUFS; int err = -ENOBUFS;
struct net *net = entry->state.net; struct net *net = entry->state.net;
struct nfnl_queue_net *q = nfnl_queue_pernet(net); struct nfnl_queue_net *q = nfnl_queue_pernet(net);
...@@ -815,8 +815,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) ...@@ -815,8 +815,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
goto out_err; goto out_err;
queued = 0; queued = 0;
err = 0; err = 0;
do { skb_list_walk_safe(segs, segs, nskb) {
struct sk_buff *nskb = segs->next;
if (err == 0) if (err == 0)
err = __nfqnl_enqueue_packet_gso(net, queue, err = __nfqnl_enqueue_packet_gso(net, queue,
segs, entry); segs, entry);
...@@ -824,8 +823,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) ...@@ -824,8 +823,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
queued++; queued++;
else else
kfree_skb(segs); kfree_skb(segs);
segs = nskb; }
} while (segs);
if (queued) { if (queued) {
if (err) /* some segments are already queued */ if (err) /* some segments are already queued */
......
...@@ -321,8 +321,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, ...@@ -321,8 +321,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
} }
/* Queue all of the segments. */ /* Queue all of the segments. */
skb = segs; skb_list_walk_safe(segs, skb, nskb) {
do {
if (gso_type & SKB_GSO_UDP && skb != segs) if (gso_type & SKB_GSO_UDP && skb != segs)
key = &later_key; key = &later_key;
...@@ -330,17 +329,15 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb, ...@@ -330,17 +329,15 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
if (err) if (err)
break; break;
} while ((skb = skb->next)); }
/* Free all of the segments. */ /* Free all of the segments. */
skb = segs; skb_list_walk_safe(segs, skb, nskb) {
do {
nskb = skb->next;
if (err) if (err)
kfree_skb(skb); kfree_skb(skb);
else else
consume_skb(skb); consume_skb(skb);
} while ((skb = nskb)); }
return err; return err;
} }
......
...@@ -1682,8 +1682,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, ...@@ -1682,8 +1682,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (IS_ERR_OR_NULL(segs)) if (IS_ERR_OR_NULL(segs))
return qdisc_drop(skb, sch, to_free); return qdisc_drop(skb, sch, to_free);
while (segs) { skb_list_walk_safe(segs, segs, nskb) {
nskb = segs->next;
skb_mark_not_on_list(segs); skb_mark_not_on_list(segs);
qdisc_skb_cb(segs)->pkt_len = segs->len; qdisc_skb_cb(segs)->pkt_len = segs->len;
cobalt_set_enqueue_time(segs, now); cobalt_set_enqueue_time(segs, now);
...@@ -1696,7 +1695,6 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, ...@@ -1696,7 +1695,6 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
slen += segs->len; slen += segs->len;
q->buffer_used += segs->truesize; q->buffer_used += segs->truesize;
b->packets++; b->packets++;
segs = nskb;
} }
/* stats */ /* stats */
......
...@@ -155,8 +155,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, ...@@ -155,8 +155,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
return qdisc_drop(skb, sch, to_free); return qdisc_drop(skb, sch, to_free);
nb = 0; nb = 0;
while (segs) { skb_list_walk_safe(segs, segs, nskb) {
nskb = segs->next;
skb_mark_not_on_list(segs); skb_mark_not_on_list(segs);
qdisc_skb_cb(segs)->pkt_len = segs->len; qdisc_skb_cb(segs)->pkt_len = segs->len;
len += segs->len; len += segs->len;
...@@ -167,7 +166,6 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, ...@@ -167,7 +166,6 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
} else { } else {
nb++; nb++;
} }
segs = nskb;
} }
sch->q.qlen += nb; sch->q.qlen += nb;
if (nb > 1) if (nb > 1)
......
...@@ -78,7 +78,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur ...@@ -78,7 +78,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
int err; int err;
unsigned long flags; unsigned long flags;
struct xfrm_state *x; struct xfrm_state *x;
struct sk_buff *skb2; struct sk_buff *skb2, *nskb;
struct softnet_data *sd; struct softnet_data *sd;
netdev_features_t esp_features = features; netdev_features_t esp_features = features;
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
...@@ -148,11 +148,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur ...@@ -148,11 +148,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
return skb; return skb;
} }
skb2 = skb; skb_list_walk_safe(skb, skb2, nskb) {
do {
struct sk_buff *nskb = skb2->next;
esp_features |= skb->dev->gso_partial_features; esp_features |= skb->dev->gso_partial_features;
skb_mark_not_on_list(skb2); skb_mark_not_on_list(skb2);
...@@ -176,14 +172,11 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur ...@@ -176,14 +172,11 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
if (!skb) if (!skb)
return NULL; return NULL;
goto skip_push; continue;
} }
skb_push(skb2, skb2->data - skb_mac_header(skb2)); skb_push(skb2, skb2->data - skb_mac_header(skb2));
}
skip_push:
skb2 = nskb;
} while (skb2);
return skb; return skb;
} }
......
...@@ -533,7 +533,7 @@ static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -533,7 +533,7 @@ static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb) static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb)
{ {
struct sk_buff *segs; struct sk_buff *segs, *nskb;
BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET); BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET); BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
...@@ -544,8 +544,7 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -544,8 +544,7 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb
if (segs == NULL) if (segs == NULL)
return -EINVAL; return -EINVAL;
do { skb_list_walk_safe(segs, segs, nskb) {
struct sk_buff *nskb = segs->next;
int err; int err;
skb_mark_not_on_list(segs); skb_mark_not_on_list(segs);
...@@ -555,9 +554,7 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -555,9 +554,7 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb
kfree_skb_list(nskb); kfree_skb_list(nskb);
return err; return err;
} }
}
segs = nskb;
} while (segs);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment