mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
IPoIB: Wait for join to finish before freeing mcast struct
ipoib_mcast_restart_task() might free an mcast object while a join request is still outstanding, leading to an oops when the query completes. Fix this by waiting for query to complete, similar to what ipoib_stop_thread() is doing. The wait for mcast completion code is consolidated in wait_for_mcast_join(). Signed-off-by: Eli Cohen <eli@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
bf6a9e31cf
commit
f2de3b0612
@ -609,6 +609,22 @@ int ipoib_mcast_start_thread(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_for_mcast_join(struct ipoib_dev_priv *priv,
|
||||
struct ipoib_mcast *mcast)
|
||||
{
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (mcast && mcast->query) {
|
||||
ib_sa_cancel_query(mcast->query_id, mcast->query);
|
||||
mcast->query = NULL;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
|
||||
IPOIB_GID_ARG(mcast->mcmember.mgid));
|
||||
wait_for_completion(&mcast->done);
|
||||
}
|
||||
else
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
@ -628,28 +644,10 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
|
||||
if (flush)
|
||||
flush_workqueue(ipoib_workqueue);
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (priv->broadcast && priv->broadcast->query) {
|
||||
ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
|
||||
priv->broadcast->query = NULL;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
ipoib_dbg_mcast(priv, "waiting for bcast\n");
|
||||
wait_for_completion(&priv->broadcast->done);
|
||||
} else
|
||||
spin_unlock_irq(&priv->lock);
|
||||
wait_for_mcast_join(priv, priv->broadcast);
|
||||
|
||||
list_for_each_entry(mcast, &priv->multicast_list, list) {
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (mcast->query) {
|
||||
ib_sa_cancel_query(mcast->query_id, mcast->query);
|
||||
mcast->query = NULL;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
|
||||
IPOIB_GID_ARG(mcast->mcmember.mgid));
|
||||
wait_for_completion(&mcast->done);
|
||||
} else
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
list_for_each_entry(mcast, &priv->multicast_list, list)
|
||||
wait_for_mcast_join(priv, mcast);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -902,6 +900,7 @@ void ipoib_mcast_restart_task(void *dev_ptr)
|
||||
|
||||
/* We have to cancel outside of the spinlock */
|
||||
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
|
||||
wait_for_mcast_join(priv, mcast);
|
||||
ipoib_mcast_leave(mcast->dev, mcast);
|
||||
ipoib_mcast_free(mcast);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user