Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 5f08318f617b ("smc: connection data control (CDC)")
Signed-off-by: Dust Li <dust.li@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Dust Li and committed by
David S. Miller
90cee52f 1b9dadba

+11 -5
+1 -1
net/smc/smc_core.c
··· 647 647 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 648 648 struct smc_link *lnk = &lgr->lnk[i]; 649 649 650 - if (smc_link_usable(lnk)) 650 + if (smc_link_sendable(lnk)) 651 651 lnk->state = SMC_LNK_INACTIVE; 652 652 } 653 653 wake_up_all(&lgr->llc_msg_waiter);
+6
net/smc/smc_core.h
··· 415 415 return true; 416 416 } 417 417 418 + static inline bool smc_link_sendable(struct smc_link *lnk) 419 + { 420 + return smc_link_usable(lnk) && 421 + lnk->qp_attr.cur_qp_state == IB_QPS_RTS; 422 + } 423 + 418 424 static inline bool smc_link_active(struct smc_link *lnk) 419 425 { 420 426 return lnk->state == SMC_LNK_ACTIVE;
+1 -1
net/smc/smc_llc.c
··· 1630 1630 delllc.reason = htonl(rsn); 1631 1631 1632 1632 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 1633 - if (!smc_link_usable(&lgr->lnk[i])) 1633 + if (!smc_link_sendable(&lgr->lnk[i])) 1634 1634 continue; 1635 1635 if (!smc_llc_send_message_wait(&lgr->lnk[i], &delllc)) 1636 1636 break;
+2 -2
net/smc/smc_wr.c
··· 188 188 static inline int smc_wr_tx_get_free_slot_index(struct smc_link *link, u32 *idx) 189 189 { 190 190 *idx = link->wr_tx_cnt; 191 - if (!smc_link_usable(link)) 191 + if (!smc_link_sendable(link)) 192 192 return -ENOLINK; 193 193 for_each_clear_bit(*idx, link->wr_tx_mask, link->wr_tx_cnt) { 194 194 if (!test_and_set_bit(*idx, link->wr_tx_mask)) ··· 231 231 } else { 232 232 rc = wait_event_interruptible_timeout( 233 233 link->wr_tx_wait, 234 - !smc_link_usable(link) || 234 + !smc_link_sendable(link) || 235 235 lgr->terminating || 236 236 (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY), 237 237 SMC_WR_TX_WAIT_FREE_SLOT_TIME);
+1 -1
net/smc/smc_wr.h
··· 62 62 63 63 static inline bool smc_wr_tx_link_hold(struct smc_link *link) 64 64 { 65 - if (!smc_link_usable(link)) 65 + if (!smc_link_sendable(link)) 66 66 return false; 67 67 atomic_inc(&link->wr_tx_refcnt); 68 68 return true;