diff options
author | Michael S. Tsirkin <mst@mellanox.co.il> | 2006-11-16 07:16:47 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-11-29 18:33:09 -0500 |
commit | 2745b5b713bf3457d8977c62dc2b3aa61f4a14b0 (patch) | |
tree | 69ccbda1932d6c95b9beb9a40f5ca3a012b023bf /drivers/infiniband | |
parent | d2fcea7d68473b8bb3e0addb4926c87e2217ca83 (diff) |
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: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 19 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 2 |
3 files changed, 15 insertions, 8 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 0b8a79d53a00..f2b61851a49c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -233,7 +233,7 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh) | |||
233 | } | 233 | } |
234 | 234 | ||
235 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); | 235 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); |
236 | void ipoib_neigh_free(struct ipoib_neigh *neigh); | 236 | void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh); |
237 | 237 | ||
238 | extern struct workqueue_struct *ipoib_workqueue; | 238 | extern struct workqueue_struct *ipoib_workqueue; |
239 | 239 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 85522daeb946..5ba3154320b4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -264,7 +264,7 @@ static void path_free(struct net_device *dev, struct ipoib_path *path) | |||
264 | if (neigh->ah) | 264 | if (neigh->ah) |
265 | ipoib_put_ah(neigh->ah); | 265 | ipoib_put_ah(neigh->ah); |
266 | 266 | ||
267 | ipoib_neigh_free(neigh); | 267 | ipoib_neigh_free(dev, neigh); |
268 | } | 268 | } |
269 | 269 | ||
270 | spin_unlock_irqrestore(&priv->lock, flags); | 270 | spin_unlock_irqrestore(&priv->lock, flags); |
@@ -525,10 +525,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) | |||
525 | ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); | 525 | ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); |
526 | } else { | 526 | } else { |
527 | neigh->ah = NULL; | 527 | neigh->ah = NULL; |
528 | __skb_queue_tail(&neigh->queue, skb); | ||
529 | 528 | ||
530 | if (!path->query && path_rec_start(dev, path)) | 529 | if (!path->query && path_rec_start(dev, path)) |
531 | goto err_list; | 530 | goto err_list; |
531 | |||
532 | __skb_queue_tail(&neigh->queue, skb); | ||
532 | } | 533 | } |
533 | 534 | ||
534 | spin_unlock(&priv->lock); | 535 | spin_unlock(&priv->lock); |
@@ -538,7 +539,7 @@ err_list: | |||
538 | list_del(&neigh->list); | 539 | list_del(&neigh->list); |
539 | 540 | ||
540 | err_path: | 541 | err_path: |
541 | ipoib_neigh_free(neigh); | 542 | ipoib_neigh_free(dev, neigh); |
542 | ++priv->stats.tx_dropped; | 543 | ++priv->stats.tx_dropped; |
543 | dev_kfree_skb_any(skb); | 544 | dev_kfree_skb_any(skb); |
544 | 545 | ||
@@ -655,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
655 | */ | 656 | */ |
656 | ipoib_put_ah(neigh->ah); | 657 | ipoib_put_ah(neigh->ah); |
657 | list_del(&neigh->list); | 658 | list_del(&neigh->list); |
658 | ipoib_neigh_free(neigh); | 659 | ipoib_neigh_free(dev, neigh); |
659 | spin_unlock(&priv->lock); | 660 | spin_unlock(&priv->lock); |
660 | ipoib_path_lookup(skb, dev); | 661 | ipoib_path_lookup(skb, dev); |
661 | goto out; | 662 | goto out; |
@@ -786,7 +787,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) | |||
786 | if (neigh->ah) | 787 | if (neigh->ah) |
787 | ah = neigh->ah; | 788 | ah = neigh->ah; |
788 | list_del(&neigh->list); | 789 | list_del(&neigh->list); |
789 | ipoib_neigh_free(neigh); | 790 | ipoib_neigh_free(n->dev, neigh); |
790 | } | 791 | } |
791 | 792 | ||
792 | spin_unlock_irqrestore(&priv->lock, flags); | 793 | spin_unlock_irqrestore(&priv->lock, flags); |
@@ -809,9 +810,15 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) | |||
809 | return neigh; | 810 | return neigh; |
810 | } | 811 | } |
811 | 812 | ||
812 | void ipoib_neigh_free(struct ipoib_neigh *neigh) | 813 | void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) |
813 | { | 814 | { |
815 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
816 | struct sk_buff *skb; | ||
814 | *to_ipoib_neigh(neigh->neighbour) = NULL; | 817 | *to_ipoib_neigh(neigh->neighbour) = NULL; |
818 | while ((skb = __skb_dequeue(&neigh->queue))) { | ||
819 | ++priv->stats.tx_dropped; | ||
820 | dev_kfree_skb_any(skb); | ||
821 | } | ||
815 | kfree(neigh); | 822 | kfree(neigh); |
816 | } | 823 | } |
817 | 824 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 3faa1820f0e9..d282d65e3ee0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -114,7 +114,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) | |||
114 | */ | 114 | */ |
115 | if (neigh->ah) | 115 | if (neigh->ah) |
116 | ipoib_put_ah(neigh->ah); | 116 | ipoib_put_ah(neigh->ah); |
117 | ipoib_neigh_free(neigh); | 117 | ipoib_neigh_free(dev, neigh); |
118 | } | 118 | } |
119 | 119 | ||
120 | spin_unlock_irqrestore(&priv->lock, flags); | 120 | spin_unlock_irqrestore(&priv->lock, flags); |