Commit 2745b5b7 authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by Roland Dreier

IPoIB: Fix skb leak when freeing neighbour

ipoib_neigh_free() is sometimes called while neighbour is still alive,
so it might still have queued skbs.  Fix skb leak in this case.
Signed-off-by: default avatarMichael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent d2fcea7d
...@@ -233,7 +233,7 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh) ...@@ -233,7 +233,7 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
} }
struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh);
void ipoib_neigh_free(struct ipoib_neigh *neigh); void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh);
extern struct workqueue_struct *ipoib_workqueue; extern struct workqueue_struct *ipoib_workqueue;
......
...@@ -264,7 +264,7 @@ static void path_free(struct net_device *dev, struct ipoib_path *path) ...@@ -264,7 +264,7 @@ static void path_free(struct net_device *dev, struct ipoib_path *path)
if (neigh->ah) if (neigh->ah)
ipoib_put_ah(neigh->ah); ipoib_put_ah(neigh->ah);
ipoib_neigh_free(neigh); ipoib_neigh_free(dev, neigh);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -525,10 +525,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -525,10 +525,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
} else { } else {
neigh->ah = NULL; neigh->ah = NULL;
__skb_queue_tail(&neigh->queue, skb);
if (!path->query && path_rec_start(dev, path)) if (!path->query && path_rec_start(dev, path))
goto err_list; goto err_list;
__skb_queue_tail(&neigh->queue, skb);
} }
spin_unlock(&priv->lock); spin_unlock(&priv->lock);
...@@ -538,7 +539,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -538,7 +539,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
list_del(&neigh->list); list_del(&neigh->list);
err_path: err_path:
ipoib_neigh_free(neigh); ipoib_neigh_free(dev, neigh);
++priv->stats.tx_dropped; ++priv->stats.tx_dropped;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -655,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -655,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/ */
ipoib_put_ah(neigh->ah); ipoib_put_ah(neigh->ah);
list_del(&neigh->list); list_del(&neigh->list);
ipoib_neigh_free(neigh); ipoib_neigh_free(dev, neigh);
spin_unlock(&priv->lock); spin_unlock(&priv->lock);
ipoib_path_lookup(skb, dev); ipoib_path_lookup(skb, dev);
goto out; goto out;
...@@ -786,7 +787,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) ...@@ -786,7 +787,7 @@ static void ipoib_neigh_destructor(struct neighbour *n)
if (neigh->ah) if (neigh->ah)
ah = neigh->ah; ah = neigh->ah;
list_del(&neigh->list); list_del(&neigh->list);
ipoib_neigh_free(neigh); ipoib_neigh_free(n->dev, neigh);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -809,9 +810,15 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) ...@@ -809,9 +810,15 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
return neigh; return neigh;
} }
void ipoib_neigh_free(struct ipoib_neigh *neigh) void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
*to_ipoib_neigh(neigh->neighbour) = NULL; *to_ipoib_neigh(neigh->neighbour) = NULL;
while ((skb = __skb_dequeue(&neigh->queue))) {
++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
kfree(neigh); kfree(neigh);
} }
......
...@@ -114,7 +114,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) ...@@ -114,7 +114,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
*/ */
if (neigh->ah) if (neigh->ah)
ipoib_put_ah(neigh->ah); ipoib_put_ah(neigh->ah);
ipoib_neigh_free(neigh); ipoib_neigh_free(dev, neigh);
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
......
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