Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2de3b06 authored by Eli Cohen's avatar Eli Cohen Committed by Roland Dreier
Browse files

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: default avatarEli Cohen <eli@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent bf6a9e31
Loading
Loading
Loading
Loading
+20 −21
Original line number Original line Diff line number Diff line
@@ -609,6 +609,22 @@ int ipoib_mcast_start_thread(struct net_device *dev)
	return 0;
	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)
int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
{
{
	struct ipoib_dev_priv *priv = netdev_priv(dev);
	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)
	if (flush)
		flush_workqueue(ipoib_workqueue);
		flush_workqueue(ipoib_workqueue);


	spin_lock_irq(&priv->lock);
	wait_for_mcast_join(priv, priv->broadcast);
	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);


	list_for_each_entry(mcast, &priv->multicast_list, list) {
	list_for_each_entry(mcast, &priv->multicast_list, list)
		spin_lock_irq(&priv->lock);
		wait_for_mcast_join(priv, mcast);
		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);
	}


	return 0;
	return 0;
}
}
@@ -902,6 +900,7 @@ void ipoib_mcast_restart_task(void *dev_ptr)


	/* We have to cancel outside of the spinlock */
	/* We have to cancel outside of the spinlock */
	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
		wait_for_mcast_join(priv, mcast);
		ipoib_mcast_leave(mcast->dev, mcast);
		ipoib_mcast_leave(mcast->dev, mcast);
		ipoib_mcast_free(mcast);
		ipoib_mcast_free(mcast);
	}
	}