Commit e7a623d2 authored by Roland Dreier's avatar Roland Dreier

Revert "IPoIB: fix MCAST_FLAG_BUSY usage"

This reverts commit 016d9fb2.

The series of IPoIB bug fixes that went into 3.19-rc1 introduce
regressions, and after trying to sort things out, we decided to revert
to 3.18's IPoIB driver and get things right for 3.20.
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 962121b4
...@@ -98,15 +98,9 @@ enum { ...@@ -98,15 +98,9 @@ enum {
IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */
IPOIB_MCAST_FLAG_SENDONLY = 1, IPOIB_MCAST_FLAG_SENDONLY = 1,
/* IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */
* For IPOIB_MCAST_FLAG_BUSY
* When set, in flight join and mcast->mc is unreliable
* When clear and mcast->mc IS_ERR_OR_NULL, need to restart or
* haven't started yet
* When clear and mcast->mc is valid pointer, join was successful
*/
IPOIB_MCAST_FLAG_BUSY = 2,
IPOIB_MCAST_FLAG_ATTACHED = 3, IPOIB_MCAST_FLAG_ATTACHED = 3,
IPOIB_MCAST_JOIN_STARTED = 4,
MAX_SEND_CQE = 16, MAX_SEND_CQE = 16,
IPOIB_CM_COPYBREAK = 256, IPOIB_CM_COPYBREAK = 256,
......
...@@ -271,27 +271,16 @@ ipoib_mcast_sendonly_join_complete(int status, ...@@ -271,27 +271,16 @@ ipoib_mcast_sendonly_join_complete(int status,
struct ipoib_mcast *mcast = multicast->context; struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev; struct net_device *dev = mcast->dev;
/*
* We have to take the mutex to force mcast_sendonly_join to
* return from ib_sa_multicast_join and set mcast->mc to a
* valid value. Otherwise we were racing with ourselves in
* that we might fail here, but get a valid return from
* ib_sa_multicast_join after we had cleared mcast->mc here,
* resulting in mis-matched joins and leaves and a deadlock
*/
mutex_lock(&mcast_mutex);
/* We trap for port events ourselves. */ /* We trap for port events ourselves. */
if (status == -ENETRESET) if (status == -ENETRESET)
goto out; return 0;
if (!status) if (!status)
status = ipoib_mcast_join_finish(mcast, &multicast->rec); status = ipoib_mcast_join_finish(mcast, &multicast->rec);
if (status) { if (status) {
if (mcast->logcount++ < 20) if (mcast->logcount++ < 20)
ipoib_dbg_mcast(netdev_priv(dev), "sendonly multicast " ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n",
"join failed for %pI6, status %d\n",
mcast->mcmember.mgid.raw, status); mcast->mcmember.mgid.raw, status);
/* Flush out any queued packets */ /* Flush out any queued packets */
...@@ -301,15 +290,11 @@ ipoib_mcast_sendonly_join_complete(int status, ...@@ -301,15 +290,11 @@ ipoib_mcast_sendonly_join_complete(int status,
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
} }
netif_tx_unlock_bh(dev); netif_tx_unlock_bh(dev);
/* Clear the busy flag so we try again */
status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
&mcast->flags);
} }
out:
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
if (status)
mcast->mc = NULL;
complete(&mcast->done);
if (status == -ENETRESET)
status = 0;
mutex_unlock(&mcast_mutex);
return status; return status;
} }
...@@ -327,14 +312,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ...@@ -327,14 +312,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
int ret = 0; int ret = 0;
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) {
ipoib_dbg_mcast(priv, "device shutting down, no sendonly " ipoib_dbg_mcast(priv, "device shutting down, no multicast joins\n");
"multicast joins\n");
return -ENODEV; return -ENODEV;
} }
if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) { if (test_and_set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) {
ipoib_dbg_mcast(priv, "multicast entry busy, skipping " ipoib_dbg_mcast(priv, "multicast entry busy, skipping\n");
"sendonly join\n");
return -EBUSY; return -EBUSY;
} }
...@@ -342,9 +325,6 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ...@@ -342,9 +325,6 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
rec.port_gid = priv->local_gid; rec.port_gid = priv->local_gid;
rec.pkey = cpu_to_be16(priv->pkey); rec.pkey = cpu_to_be16(priv->pkey);
mutex_lock(&mcast_mutex);
init_completion(&mcast->done);
set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca,
priv->port, &rec, priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_MGID |
...@@ -357,14 +337,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ...@@ -357,14 +337,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
if (IS_ERR(mcast->mc)) { if (IS_ERR(mcast->mc)) {
ret = PTR_ERR(mcast->mc); ret = PTR_ERR(mcast->mc);
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
complete(&mcast->done); ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n",
ipoib_warn(priv, "ib_sa_join_multicast for sendonly join " ret);
"failed (ret = %d)\n", ret);
} else { } else {
ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting " ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n",
"sendonly join\n", mcast->mcmember.mgid.raw); mcast->mcmember.mgid.raw);
} }
mutex_unlock(&mcast_mutex);
return ret; return ret;
} }
...@@ -412,28 +390,22 @@ static int ipoib_mcast_join_complete(int status, ...@@ -412,28 +390,22 @@ static int ipoib_mcast_join_complete(int status,
ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n", ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n",
mcast->mcmember.mgid.raw, status); mcast->mcmember.mgid.raw, status);
/*
* We have to take the mutex to force mcast_join to
* return from ib_sa_multicast_join and set mcast->mc to a
* valid value. Otherwise we were racing with ourselves in
* that we might fail here, but get a valid return from
* ib_sa_multicast_join after we had cleared mcast->mc here,
* resulting in mis-matched joins and leaves and a deadlock
*/
mutex_lock(&mcast_mutex);
/* We trap for port events ourselves. */ /* We trap for port events ourselves. */
if (status == -ENETRESET) if (status == -ENETRESET) {
status = 0;
goto out; goto out;
}
if (!status) if (!status)
status = ipoib_mcast_join_finish(mcast, &multicast->rec); status = ipoib_mcast_join_finish(mcast, &multicast->rec);
if (!status) { if (!status) {
mcast->backoff = 1; mcast->backoff = 1;
mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
&priv->mcast_task, 0); &priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
/* /*
* Defer carrier on work to ipoib_workqueue to avoid a * Defer carrier on work to ipoib_workqueue to avoid a
...@@ -441,7 +413,11 @@ static int ipoib_mcast_join_complete(int status, ...@@ -441,7 +413,11 @@ static int ipoib_mcast_join_complete(int status,
*/ */
if (mcast == priv->broadcast) if (mcast == priv->broadcast)
queue_work(ipoib_workqueue, &priv->carrier_on_task); queue_work(ipoib_workqueue, &priv->carrier_on_task);
} else {
status = 0;
goto out;
}
if (mcast->logcount++ < 20) { if (mcast->logcount++ < 20) {
if (status == -ETIMEDOUT || status == -EAGAIN) { if (status == -ETIMEDOUT || status == -EAGAIN) {
ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n", ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
...@@ -455,21 +431,19 @@ static int ipoib_mcast_join_complete(int status, ...@@ -455,21 +431,19 @@ static int ipoib_mcast_join_complete(int status,
mcast->backoff *= 2; mcast->backoff *= 2;
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
}
out: /* Clear the busy flag so we try again */
status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
if (status)
mcast->mc = NULL;
complete(&mcast->done);
if (status == -ENETRESET)
status = 0;
if (status && test_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue, &priv->mcast_task, queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
mcast->backoff * HZ); mcast->backoff * HZ);
spin_unlock_irq(&priv->lock); spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex); mutex_unlock(&mcast_mutex);
out:
complete(&mcast->done);
return status; return status;
} }
...@@ -518,9 +492,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ...@@ -518,9 +492,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
rec.hop_limit = priv->broadcast->mcmember.hop_limit; rec.hop_limit = priv->broadcast->mcmember.hop_limit;
} }
mutex_lock(&mcast_mutex);
init_completion(&mcast->done);
set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
init_completion(&mcast->done);
set_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags);
mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
&rec, comp_mask, GFP_KERNEL, &rec, comp_mask, GFP_KERNEL,
ipoib_mcast_join_complete, mcast); ipoib_mcast_join_complete, mcast);
...@@ -534,12 +509,13 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ...@@ -534,12 +509,13 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
&priv->mcast_task, &priv->mcast_task,
mcast->backoff * HZ); mcast->backoff * HZ);
}
mutex_unlock(&mcast_mutex); mutex_unlock(&mcast_mutex);
}
} }
void ipoib_mcast_join_task(struct work_struct *work) void ipoib_mcast_join_task(struct work_struct *work)
...@@ -592,8 +568,7 @@ void ipoib_mcast_join_task(struct work_struct *work) ...@@ -592,8 +568,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
} }
if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
if (IS_ERR_OR_NULL(priv->broadcast->mc) && if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
ipoib_mcast_join(dev, priv->broadcast, 0); ipoib_mcast_join(dev, priv->broadcast, 0);
return; return;
} }
...@@ -601,32 +576,22 @@ void ipoib_mcast_join_task(struct work_struct *work) ...@@ -601,32 +576,22 @@ void ipoib_mcast_join_task(struct work_struct *work)
while (1) { while (1) {
struct ipoib_mcast *mcast = NULL; struct ipoib_mcast *mcast = NULL;
/*
* Need the mutex so our flags are consistent, need the
* priv->lock so we don't race with list removals in either
* mcast_dev_flush or mcast_restart_task
*/
mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
list_for_each_entry(mcast, &priv->multicast_list, list) { list_for_each_entry(mcast, &priv->multicast_list, list) {
if (IS_ERR_OR_NULL(mcast->mc) && if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)
!test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) && && !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)
!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { && !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
/* Found the next unjoined group */ /* Found the next unjoined group */
break; break;
} }
} }
spin_unlock_irq(&priv->lock); spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex);
if (&mcast->list == &priv->multicast_list) { if (&mcast->list == &priv->multicast_list) {
/* All done */ /* All done */
break; break;
} }
if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
ipoib_mcast_sendonly_join(mcast);
else
ipoib_mcast_join(dev, mcast, 1); ipoib_mcast_join(dev, mcast, 1);
return; return;
} }
...@@ -673,9 +638,6 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) ...@@ -673,9 +638,6 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
int ret = 0; int ret = 0;
if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_warn(priv, "ipoib_mcast_leave on an in-flight join\n");
if (!IS_ERR_OR_NULL(mcast->mc))
ib_sa_free_multicast(mcast->mc); ib_sa_free_multicast(mcast->mc);
if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
...@@ -728,8 +690,6 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) ...@@ -728,8 +690,6 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid)); memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid));
__ipoib_mcast_add(dev, mcast); __ipoib_mcast_add(dev, mcast);
list_add_tail(&mcast->list, &priv->multicast_list); list_add_tail(&mcast->list, &priv->multicast_list);
if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0);
} }
if (!mcast->ah) { if (!mcast->ah) {
...@@ -743,6 +703,8 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) ...@@ -743,6 +703,8 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_dbg_mcast(priv, "no address vector, " ipoib_dbg_mcast(priv, "no address vector, "
"but multicast join already started\n"); "but multicast join already started\n");
else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
ipoib_mcast_sendonly_join(mcast);
/* /*
* If lookup completes between here and out:, don't * If lookup completes between here and out:, don't
...@@ -804,7 +766,7 @@ void ipoib_mcast_dev_flush(struct net_device *dev) ...@@ -804,7 +766,7 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
/* seperate between the wait to the leave*/ /* seperate between the wait to the leave*/
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) list_for_each_entry_safe(mcast, tmcast, &remove_list, list)
if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) if (test_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags))
wait_for_completion(&mcast->done); wait_for_completion(&mcast->done);
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
......
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