Avoid corrupting mcast->pkt_queue by serializing access with
priv->tx_lock. Also, update dropped packet statistics to count
multicast packets removed from pkt_queue as dropped.
Signed-off-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Roland Dreier <[email protected]>
---
drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 25 +++++++++++++++++++++---
1 files changed, 22 insertions(+), 3 deletions(-)
b36f170b617a7cd147b694dabf504e856a50ee9d
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 98039da..ccaa0c3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -97,6 +97,7 @@ static void ipoib_mcast_free(struct ipoi
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_neigh *neigh, *tmp;
unsigned long flags;
+ int tx_dropped = 0;
ipoib_dbg_mcast(netdev_priv(dev),
"deleting multicast group " IPOIB_GID_FMT "\n",
@@ -123,8 +124,14 @@ static void ipoib_mcast_free(struct ipoi
if (mcast->ah)
ipoib_put_ah(mcast->ah);
- while (!skb_queue_empty(&mcast->pkt_queue))
+ while (!skb_queue_empty(&mcast->pkt_queue)) {
+ ++tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
+ }
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ priv->stats.tx_dropped += tx_dropped;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
kfree(mcast);
}
@@ -276,8 +283,10 @@ static int ipoib_mcast_join_finish(struc
}
/* actually send any queued packets */
+ spin_lock_irq(&priv->tx_lock);
while (!skb_queue_empty(&mcast->pkt_queue)) {
struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
+ spin_unlock_irq(&priv->tx_lock);
skb->dev = dev;
@@ -288,7 +297,9 @@ static int ipoib_mcast_join_finish(struc
if (dev_queue_xmit(skb))
ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
+ spin_lock_irq(&priv->tx_lock);
}
+ spin_unlock_irq(&priv->tx_lock);
return 0;
}
@@ -300,6 +311,7 @@ ipoib_mcast_sendonly_join_complete(int s
{
struct ipoib_mcast *mcast = mcast_ptr;
struct net_device *dev = mcast->dev;
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
if (!status)
ipoib_mcast_join_finish(mcast, mcmember);
@@ -310,8 +322,12 @@ ipoib_mcast_sendonly_join_complete(int s
IPOIB_GID_ARG(mcast->mcmember.mgid), status);
/* Flush out any queued packets */
- while (!skb_queue_empty(&mcast->pkt_queue))
+ spin_lock_irq(&priv->tx_lock);
+ while (!skb_queue_empty(&mcast->pkt_queue)) {
+ ++priv->stats.tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
+ }
+ spin_unlock_irq(&priv->tx_lock);
/* Clear the busy flag so we try again */
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
@@ -687,6 +703,7 @@ void ipoib_mcast_send(struct net_device
if (!mcast) {
ipoib_warn(priv, "unable to allocate memory for "
"multicast structure\n");
+ ++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
goto out;
}
@@ -700,8 +717,10 @@ void ipoib_mcast_send(struct net_device
if (!mcast->ah) {
if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
skb_queue_tail(&mcast->pkt_queue, skb);
- else
+ else {
+ ++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
+ }
if (mcast->query)
ipoib_dbg_mcast(priv, "no address vector, "
--
1.1.3
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]