Commit 31c02e21 authored by Roland Dreier's avatar Roland Dreier

IPoIB: Avoid using stale last_send counter when reaping AHs

The comparisons of priv->tx_tail to ah->last_send in ipoib_free_ah()
and ipoib_post_receive() are slightly unsafe, because priv->tx_lock is
not held and hence a stale value of ah->last_send might be used, which
would lead to freeing an AH before the driver was really done with it.
The simple way to fix this is to the optimization of early free from
ipoib_free_ah() and unconditionally queue AHs for reaping, and then
take priv->tx_lock in __ipoib_reap_ah().
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 9874e746
...@@ -84,15 +84,9 @@ void ipoib_free_ah(struct kref *kref) ...@@ -84,15 +84,9 @@ void ipoib_free_ah(struct kref *kref)
unsigned long flags; unsigned long flags;
if ((int) priv->tx_tail - (int) ah->last_send >= 0) { spin_lock_irqsave(&priv->lock, flags);
ipoib_dbg(priv, "Freeing ah %p\n", ah->ah); list_add_tail(&ah->list, &priv->dead_ahs);
ib_destroy_ah(ah->ah); spin_unlock_irqrestore(&priv->lock, flags);
kfree(ah);
} else {
spin_lock_irqsave(&priv->lock, flags);
list_add_tail(&ah->list, &priv->dead_ahs);
spin_unlock_irqrestore(&priv->lock, flags);
}
} }
static int ipoib_ib_post_receive(struct net_device *dev, int id) static int ipoib_ib_post_receive(struct net_device *dev, int id)
...@@ -377,19 +371,16 @@ static void __ipoib_reap_ah(struct net_device *dev) ...@@ -377,19 +371,16 @@ static void __ipoib_reap_ah(struct net_device *dev)
struct ipoib_ah *ah, *tah; struct ipoib_ah *ah, *tah;
LIST_HEAD(remove_list); LIST_HEAD(remove_list);
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->tx_lock);
spin_lock(&priv->lock);
list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
if ((int) priv->tx_tail - (int) ah->last_send >= 0) { if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
list_del(&ah->list); list_del(&ah->list);
list_add_tail(&ah->list, &remove_list); ib_destroy_ah(ah->ah);
kfree(ah);
} }
spin_unlock_irq(&priv->lock); spin_unlock(&priv->lock);
spin_unlock_irq(&priv->tx_lock);
list_for_each_entry_safe(ah, tah, &remove_list, list) {
ipoib_dbg(priv, "Reaping ah %p\n", ah->ah);
ib_destroy_ah(ah->ah);
kfree(ah);
}
} }
void ipoib_reap_ah(void *dev_ptr) void ipoib_reap_ah(void *dev_ptr)
......
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