diff options
author | Shlomo Pongratz <shlomop@mellanox.com> | 2013-02-04 10:29:10 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-02-05 12:35:06 -0500 |
commit | 7e5a90c25f89128c096dbdb0e5451962438b1e05 (patch) | |
tree | 0f7547c36c7d7ab5ed33a2922c18e452b1b627c7 | |
parent | 949db153b6466c6f7cad5a427ecea94985927311 (diff) |
IPoIB: Fix crash due to skb double destruct
After commit b13912bbb4a2 ("IPoIB: Call skb_dst_drop() once skb is
enqueued for sending"), using connected mode and running multithreaded
iperf for long time, ie
iperf -c <IP> -P 16 -t 3600
results in a crash.
After the above-mentioned patch, the driver is calling skb_orphan() and
skb_dst_drop() after calling post_send() in ipoib_cm.c::ipoib_cm_send()
(also in ipoib_ib.c::ipoib_send())
The problem with this is, as is written in a comment in both routines,
"it's entirely possible that the completion handler will run before we
execute anything after the post_send()." This leads to running the
skb cleanup routines simultaneously in two different contexts.
The solution is to always perform the skb_orphan() and skb_dst_drop()
before queueing the send work request. If an error occurs, then it
will be no different than the regular case where dev_free_skb_any() in
the completion path, which is assumed to be after these two routines.
Signed-off-by: Shlomo Pongratz <shlomop@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_cm.c | 6 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 6 |
2 files changed, 6 insertions, 6 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 03103d2bd641..67b0c1d23678 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c | |||
@@ -741,6 +741,9 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ | |||
741 | 741 | ||
742 | tx_req->mapping = addr; | 742 | tx_req->mapping = addr; |
743 | 743 | ||
744 | skb_orphan(skb); | ||
745 | skb_dst_drop(skb); | ||
746 | |||
744 | rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), | 747 | rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), |
745 | addr, skb->len); | 748 | addr, skb->len); |
746 | if (unlikely(rc)) { | 749 | if (unlikely(rc)) { |
@@ -752,9 +755,6 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ | |||
752 | dev->trans_start = jiffies; | 755 | dev->trans_start = jiffies; |
753 | ++tx->tx_head; | 756 | ++tx->tx_head; |
754 | 757 | ||
755 | skb_orphan(skb); | ||
756 | skb_dst_drop(skb); | ||
757 | |||
758 | if (++priv->tx_outstanding == ipoib_sendq_size) { | 758 | if (++priv->tx_outstanding == ipoib_sendq_size) { |
759 | ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", | 759 | ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", |
760 | tx->qp->qp_num); | 760 | tx->qp->qp_num); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index a1bca70e20aa..2cfa76f5d99e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
@@ -600,6 +600,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, | |||
600 | netif_stop_queue(dev); | 600 | netif_stop_queue(dev); |
601 | } | 601 | } |
602 | 602 | ||
603 | skb_orphan(skb); | ||
604 | skb_dst_drop(skb); | ||
605 | |||
603 | rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), | 606 | rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), |
604 | address->ah, qpn, tx_req, phead, hlen); | 607 | address->ah, qpn, tx_req, phead, hlen); |
605 | if (unlikely(rc)) { | 608 | if (unlikely(rc)) { |
@@ -615,9 +618,6 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, | |||
615 | 618 | ||
616 | address->last_send = priv->tx_head; | 619 | address->last_send = priv->tx_head; |
617 | ++priv->tx_head; | 620 | ++priv->tx_head; |
618 | |||
619 | skb_orphan(skb); | ||
620 | skb_dst_drop(skb); | ||
621 | } | 621 | } |
622 | 622 | ||
623 | if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) | 623 | if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) |