|
@@ -902,8 +902,8 @@ static int path_rec_start(struct net_device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
- struct net_device *dev)
|
|
|
+static struct ipoib_neigh *neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
+ struct net_device *dev)
|
|
|
{
|
|
|
struct ipoib_dev_priv *priv = ipoib_priv(dev);
|
|
|
struct rdma_netdev *rn = netdev_priv(dev);
|
|
@@ -917,7 +917,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
++dev->stats.tx_dropped;
|
|
|
dev_kfree_skb_any(skb);
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* To avoid race condition, make sure that the
|
|
|
+ * neigh will be added only once.
|
|
|
+ */
|
|
|
+ if (unlikely(!list_empty(&neigh->list))) {
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
+ return neigh;
|
|
|
}
|
|
|
|
|
|
path = __path_find(dev, daddr + 4);
|
|
@@ -956,7 +964,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
path->ah->last_send = rn->send(dev, skb, path->ah->ah,
|
|
|
IPOIB_QPN(daddr));
|
|
|
ipoib_neigh_put(neigh);
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
} else {
|
|
|
neigh->ah = NULL;
|
|
@@ -973,7 +981,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
|
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
ipoib_neigh_put(neigh);
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
|
|
|
err_path:
|
|
|
ipoib_neigh_free(neigh);
|
|
@@ -983,6 +991,8 @@ err_drop:
|
|
|
|
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
ipoib_neigh_put(neigh);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
|
|
@@ -1091,8 +1101,9 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
case htons(ETH_P_TIPC):
|
|
|
neigh = ipoib_neigh_get(dev, phdr->hwaddr);
|
|
|
if (unlikely(!neigh)) {
|
|
|
- neigh_add_path(skb, phdr->hwaddr, dev);
|
|
|
- return NETDEV_TX_OK;
|
|
|
+ neigh = neigh_add_path(skb, phdr->hwaddr, dev);
|
|
|
+ if (likely(!neigh))
|
|
|
+ return NETDEV_TX_OK;
|
|
|
}
|
|
|
break;
|
|
|
case htons(ETH_P_ARP):
|