FAILED: patch "[PATCH] net/smc: improved fix wait on already cleared link" failed to apply to 5.10-stable tree
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 95f7f3e7dc6bd2e735cb5de11734ea2222b1e05a Mon Sep 17 00:00:00 2001
From: Karsten Graul <[email protected]>
Date: Thu, 7 Oct 2021 16:14:40 +0200
Subject: [PATCH] net/smc: improved fix wait on already cleared link
Commit 8f3d65c16679 ("net/smc: fix wait on already cleared link") introduced link refcounting to avoid waits on already cleared links. This patch extents and improves the refcounting to cover all remaining possible cases for this kind of error situation.
net/smc/smc_cdc.c +6 -1
@@ -150,9 +150,11 @@ static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn) again: link = conn->lnk; +if (!smc_wr_tx_link_hold (link)) +return -ENOLINK ; rc =smc_cdc_get_free_slot (conn, link, &wr_buf,NULL , &pend);if (rc) -return rc; + goto put_out;spin_lock_bh (&conn->send_lock);if (link != conn->lnk) {
@@ -160,6 +162,7 @@ static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn)spin_unlock_bh (&conn->send_lock);smc_wr_tx_put_slot (link, (struct smc_wr_tx_pend_priv *)pend); +smc_wr_tx_link_put (link);if (again)return -ENOLINK ; again = true;
@@ -167,6 +170,8 @@ static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn) } rc =smc_cdc_msg_send (conn, wr_buf, pend);spin_unlock_bh (&conn->send_lock); +put_out: +smc_wr_tx_link_put (link);return rc; }
net/smc/smc_core.c +11 -9
@@ -949,7 +949,7 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr, to_lnk = &lgr->lnk[i];break ; } -if (!to_lnk) { +if (!to_lnk || !smc_wr_tx_link_hold (to_lnk)) {smc_lgr_terminate_sched (lgr);return NULL ; }
@@ -981,24 +981,26 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr,read_unlock_bh (&lgr->conns_lock);/* pre-fetch buffer outside of send_lock, might sleep */ rc =smc_cdc_get_free_slot (conn, to_lnk, &wr_buf,NULL , &pend); -if (rc) { -smcr_link_down_cond_sched (to_lnk); -return NULL ; - } +if (rc) + goto err_out;/* avoid race with smcr_tx_sndbuf_nonempty() */ spin_lock_bh (&conn->send_lock);smc_switch_link_and_count (conn, to_lnk); rc =smc_switch_cursor (smc, pend, wr_buf);spin_unlock_bh (&conn->send_lock);sock_put (&smc->sk); -if (rc) { -smcr_link_down_cond_sched (to_lnk); -return NULL ; - } +if (rc) + goto err_out; goto again; }read_unlock_bh (&lgr->conns_lock); +smc_wr_tx_link_put (to_lnk);return to_lnk; + +err_out: +smcr_link_down_cond_sched (to_lnk); +smc_wr_tx_link_put (to_lnk); +return NULL ; } static void smcr_buf_unuse(struct smc_buf_desc *rmb_desc,
net/smc/smc_llc.c +49 -14
181 lines not on this page · raw message
net/smc/smc_tx.c +5 -17
@@ -496,7 +496,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn,/* Wakeup sndbuf consumers from any context (IRQ or process) * since there is more data to transmit; usable snd_wnd as max transmit */ -static int _smcr_tx_sndbuf_nonempty (struct smc_connection *conn) +static int smcr_tx_sndbuf_nonempty (struct smc_connection *conn) {struct smc_cdc_producer_flags *pflags = &conn->local_tx_ctrl.prod_flags;struct smc_link *link = conn->lnk;
@@ -505,8 +505,11 @@ static int _smcr_tx_sndbuf_nonempty(struct smc_connection *conn)struct smc_wr_buf *wr_buf;int rc; +if (!link || !smc_wr_tx_link_hold (link)) +return -ENOLINK ; rc =smc_cdc_get_free_slot (conn, link, &wr_buf, &wr_rdma_buf, &pend);if (rc <0 ) { +smc_wr_tx_link_put (link);if (rc == -EBUSY ) {struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
@@ -547,22 +550,7 @@ static int _smcr_tx_sndbuf_nonempty(struct smc_connection *conn) out_unlock:spin_unlock_bh (&conn->send_lock); -return rc; -} - -static int smcr_tx_sndbuf_nonempty (struct smc_connection *conn) -{ -struct smc_link *link = conn->lnk; -int rc = -ENOLINK ; - -if (!link) -return rc; - -atomic_inc (&link->wr_tx_refcnt); -if (smc_link_usable (link)) - rc =_smcr_tx_sndbuf_nonempty (conn); -if (atomic_dec_and_test (&link->wr_tx_refcnt)) -wake_up_all (&link->wr_tx_wait); +smc_wr_tx_link_put (link);return rc; }
net/smc/smc_wr.h +14 -0
@@ -60,6 +60,20 @@ static inline void smc_wr_tx_set_wr_id(atomic_long_t *wr_tx_id, long val)atomic_long_set (wr_tx_id, val); } +static inline bool smc_wr_tx_link_hold (struct smc_link *link) +{ +if (!smc_link_usable (link)) +return false; +atomic_inc (&link->wr_tx_refcnt); +return true; +} + +static inline void smc_wr_tx_link_put (struct smc_link *link) +{ +if (atomic_dec_and_test (&link->wr_tx_refcnt)) +wake_up_all (&link->wr_tx_wait); +} +static inline void smc_wr_wakeup_tx_wait (struct smc_link *lnk) {wake_up_all (&lnk->wr_tx_wait);