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

net/smc: wait for tx completions before link freeing

Make sure all pending work requests are completed before freeing
a link.
Dismiss tx pending slots already when terminating a link group to
exploit termination shortcut in tx completion queue handler.

And kill the completion queue tasklets after destroy of the
completion queues, otherwise there is a time window for another
tasklet schedule of an already killed tasklet.

Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ursula Braun and committed by
David S. Miller
6a37ad3d 2c1d3e50

+28 -3
+2
net/smc/smc_core.c
··· 548 548 tasklet_kill(&conn->rx_tsklet); 549 549 else 550 550 tasklet_unlock_wait(&conn->rx_tsklet); 551 + } else { 552 + smc_cdc_tx_dismiss_slots(conn); 551 553 } 552 554 smc_lgr_unregister_conn(conn); 553 555 smc_close_active_abort(smc);
+1 -1
net/smc/smc_ib.c
··· 520 520 if (!smcibdev->initialized) 521 521 return; 522 522 smcibdev->initialized = 0; 523 - smc_wr_remove_dev(smcibdev); 524 523 ib_destroy_cq(smcibdev->roce_cq_recv); 525 524 ib_destroy_cq(smcibdev->roce_cq_send); 525 + smc_wr_remove_dev(smcibdev); 526 526 } 527 527 528 528 static struct ib_client smc_ib_client;
+25 -2
net/smc/smc_wr.c
··· 50 50 51 51 /*------------------------------- completion --------------------------------*/ 52 52 53 + /* returns true if at least one tx work request is pending on the given link */ 54 + static inline bool smc_wr_is_tx_pend(struct smc_link *link) 55 + { 56 + if (find_first_bit(link->wr_tx_mask, link->wr_tx_cnt) != 57 + link->wr_tx_cnt) { 58 + return true; 59 + } 60 + return false; 61 + } 62 + 63 + /* wait till all pending tx work requests on the given link are completed */ 64 + static inline int smc_wr_tx_wait_no_pending_sends(struct smc_link *link) 65 + { 66 + if (wait_event_timeout(link->wr_tx_wait, !smc_wr_is_tx_pend(link), 67 + SMC_WR_TX_WAIT_PENDING_TIME)) 68 + return 0; 69 + else /* timeout */ 70 + return -EPIPE; 71 + } 72 + 53 73 static inline int smc_wr_tx_find_pending_index(struct smc_link *link, u64 wr_id) 54 74 { 55 75 u32 i; ··· 249 229 memset(&link->wr_tx_bufs[idx], 0, 250 230 sizeof(link->wr_tx_bufs[idx])); 251 231 test_and_clear_bit(idx, link->wr_tx_mask); 232 + wake_up(&link->wr_tx_wait); 252 233 return 1; 253 234 } 254 235 ··· 533 512 { 534 513 struct ib_device *ibdev; 535 514 536 - memset(lnk->wr_tx_mask, 0, 537 - BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask)); 515 + if (smc_wr_tx_wait_no_pending_sends(lnk)) 516 + memset(lnk->wr_tx_mask, 0, 517 + BITS_TO_LONGS(SMC_WR_BUF_CNT) * 518 + sizeof(*lnk->wr_tx_mask)); 538 519 539 520 if (!lnk->smcibdev) 540 521 return;