Commit 90cee52f authored by Dust Li's avatar Dust Li Committed by David S. Miller

net/smc: don't send CDC/LLC message if link not ready

We found smc_llc_send_link_delete_all() sometimes wait
for 2s timeout when testing with RDMA link up/down.
It is possible when a smc_link is in ACTIVATING state,
the underlaying QP is still in RESET or RTR state, which
cannot send any messages out.

smc_llc_send_link_delete_all() use smc_link_usable() to
checks whether the link is usable, if the QP is still in
RESET or RTR state, but the smc_link is in ACTIVATING, this
LLC message will always fail without any CQE entering the
CQ, and we will always wait 2s before timeout.

Since we cannot send any messages through the QP before
the QP enter RTS. I add a wrapper smc_link_sendable()
which checks the state of QP along with the link state.
And replace smc_link_usable() with smc_link_sendable()
in all LLC & CDC message sending routine.

Fixes: 5f08318f ("smc: connection data control (CDC)")
Signed-off-by: default avatarDust Li <dust.li@linux.alibaba.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b9dadba
...@@ -647,7 +647,7 @@ static void smcr_lgr_link_deactivate_all(struct smc_link_group *lgr) ...@@ -647,7 +647,7 @@ static void smcr_lgr_link_deactivate_all(struct smc_link_group *lgr)
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
struct smc_link *lnk = &lgr->lnk[i]; struct smc_link *lnk = &lgr->lnk[i];
if (smc_link_usable(lnk)) if (smc_link_sendable(lnk))
lnk->state = SMC_LNK_INACTIVE; lnk->state = SMC_LNK_INACTIVE;
} }
wake_up_all(&lgr->llc_msg_waiter); wake_up_all(&lgr->llc_msg_waiter);
......
...@@ -415,6 +415,12 @@ static inline bool smc_link_usable(struct smc_link *lnk) ...@@ -415,6 +415,12 @@ static inline bool smc_link_usable(struct smc_link *lnk)
return true; return true;
} }
static inline bool smc_link_sendable(struct smc_link *lnk)
{
return smc_link_usable(lnk) &&
lnk->qp_attr.cur_qp_state == IB_QPS_RTS;
}
static inline bool smc_link_active(struct smc_link *lnk) static inline bool smc_link_active(struct smc_link *lnk)
{ {
return lnk->state == SMC_LNK_ACTIVE; return lnk->state == SMC_LNK_ACTIVE;
......
...@@ -1630,7 +1630,7 @@ void smc_llc_send_link_delete_all(struct smc_link_group *lgr, bool ord, u32 rsn) ...@@ -1630,7 +1630,7 @@ void smc_llc_send_link_delete_all(struct smc_link_group *lgr, bool ord, u32 rsn)
delllc.reason = htonl(rsn); delllc.reason = htonl(rsn);
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
if (!smc_link_usable(&lgr->lnk[i])) if (!smc_link_sendable(&lgr->lnk[i]))
continue; continue;
if (!smc_llc_send_message_wait(&lgr->lnk[i], &delllc)) if (!smc_llc_send_message_wait(&lgr->lnk[i], &delllc))
break; break;
......
...@@ -188,7 +188,7 @@ void smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context) ...@@ -188,7 +188,7 @@ void smc_wr_tx_cq_handler(struct ib_cq *ib_cq, void *cq_context)
static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx) static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx)
{ {
*idx = link->wr_tx_cnt; *idx = link->wr_tx_cnt;
if (!smc_link_usable(link)) if (!smc_link_sendable(link))
return -ENOLINK; return -ENOLINK;
for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) { for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) {
if (!test_and_set_bit(*idx, link->wr_tx_mask)) if (!test_and_set_bit(*idx, link->wr_tx_mask))
...@@ -231,7 +231,7 @@ int smc_wr_tx_get_free_slot(struct smc_link *link, ...@@ -231,7 +231,7 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
} else { } else {
rc = wait_event_interruptible_timeout( rc = wait_event_interruptible_timeout(
link->wr_tx_wait, link->wr_tx_wait,
!smc_link_usable(link) || !smc_link_sendable(link) ||
lgr->terminating || lgr->terminating ||
(smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY), (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
SMC_WR_TX_WAIT_FREE_SLOT_TIME); SMC_WR_TX_WAIT_FREE_SLOT_TIME);
......
...@@ -62,7 +62,7 @@ static inline void smc_wr_tx_set_wr_id(atomic_long_t *wr_tx_id, long val) ...@@ -62,7 +62,7 @@ static inline void smc_wr_tx_set_wr_id(atomic_long_t *wr_tx_id, long val)
static inline bool smc_wr_tx_link_hold(struct smc_link *link) static inline bool smc_wr_tx_link_hold(struct smc_link *link)
{ {
if (!smc_link_usable(link)) if (!smc_link_sendable(link))
return false; return false;
atomic_inc(&link->wr_tx_refcnt); atomic_inc(&link->wr_tx_refcnt);
return true; return true;
......
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