diff options
author | Julian Wiedmann <jwi@linux.vnet.ibm.com> | 2017-08-15 17:02:39 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-15 10:58:39 -0700 |
commit | 886e1974dcc5866cbc3d133d1f3d2cc26af68cfc (patch) | |
tree | 0910a1aef5b8ae49d8f1db49c5aa2fca4d46f3a1 /drivers/s390/net | |
parent | d396179c166932e51b3a65c4f766671ac4e48763 (diff) |
s390/qeth: don't access skb after transmission
After transmitting a skb via send_packet[_fast](), the statistics
code accesses the skb once more to account for transmitted page frags.
This has a (theoretical?) race against the TX completion - if the TX
completion is processed and frees the skb before hard_start_xmit()
gets to the statistics part, we access random memory.
Fix this by caching the # of page frags, before the skb is transmitted.
Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
Acked-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 14 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 4 |
2 files changed, 8 insertions, 10 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ad110abfdd47..28c9a7eda507 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -707,7 +707,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, int data_offset = -1; int elements_needed = 0; int hd_len = 0; - int nr_frags; + unsigned int nr_frags; if (card->qdio.do_prio_queueing || (cast_type && card->info.is_multicast_different)) @@ -747,6 +747,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, if (lin_rc) goto tx_drop; } + nr_frags = skb_shinfo(new_skb)->nr_frags; if (card->info.type == QETH_CARD_TYPE_OSN) hdr = (struct qeth_hdr *)skb->data; @@ -799,13 +800,10 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, if (!rc) { card->stats.tx_packets++; card->stats.tx_bytes += tx_bytes; - if (card->options.performance_stats) { - nr_frags = skb_shinfo(new_skb)->nr_frags; - if (nr_frags) { - card->perf_stats.sg_skbs_sent++; - /* nr_frags + skb->data */ - card->perf_stats.sg_frags_sent += nr_frags + 1; - } + if (card->options.performance_stats && nr_frags) { + card->perf_stats.sg_skbs_sent++; + /* nr_frags + skb->data */ + card->perf_stats.sg_frags_sent += nr_frags + 1; } if (new_skb != skb) dev_kfree_skb_any(skb); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d42e758518ed..6648f02d61ea 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2650,7 +2650,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, int tx_bytes = skb->len; bool use_tso; int data_offset = -1; - int nr_frags; + unsigned int nr_frags; if (((card->info.type == QETH_CARD_TYPE_IQD) && (((card->options.cq != QETH_CQ_ENABLED) && !ipv) || @@ -2727,6 +2727,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (lin_rc) goto tx_drop; } + nr_frags = skb_shinfo(new_skb)->nr_frags; if (use_tso) { hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); @@ -2786,7 +2787,6 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (new_skb != skb) dev_kfree_skb_any(skb); if (card->options.performance_stats) { - nr_frags = skb_shinfo(new_skb)->nr_frags; if (use_tso) { card->perf_stats.large_send_bytes += tx_bytes; card->perf_stats.large_send_cnt++; |