git: f0334cb8d345 - stable/13 - cxgbei: Better handle new tasks and transfers when disconnecting.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 29 Oct 2021 23:58:22 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=f0334cb8d345da6039d76ed6be9790aba0e94b34

commit f0334cb8d345da6039d76ed6be9790aba0e94b34
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2021-06-18 23:15:50 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2021-10-29 23:10:14 +0000

    cxgbei: Better handle new tasks and transfers when disconnecting.
    
    If the connection is in the process of disconnecting, ic_socket can be
    NULL.  For icl_cxgbei_conn_transfer_setup(), lock the connection and
    check ic_socket before using it.  For icl_cxgbei_conn_task_setup(),
    the caller already holds the connection lock, so assert it and bail
    early with ECONNRESET if the connection is disconnecting.
    
    Reported by:    Jithesh Arakkan @ Chelsio
    Fixes:          f949967c8eb3 cxgbei: Fix a race between transfer setup and a peer reset.
    
    (cherry picked from commit abc273a2901b116cc98a1fb506c75ac1b0a14cd3)
---
 sys/dev/cxgbe/cxgbei/icl_cxgbei.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
index 01759d929c0e..e974ad73a935 100644
--- a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
+++ b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
@@ -988,10 +988,15 @@ icl_cxgbei_conn_task_setup(struct icl_conn *ic, struct icl_pdu *ip,
 	uint32_t itt;
 	int rc = 0;
 
+	ICL_CONN_LOCK_ASSERT(ic);
+
 	/* This is for the offload driver's state.  Must not be set already. */
 	MPASS(arg != NULL);
 	MPASS(*arg == NULL);
 
+	if (ic->ic_disconnecting || ic->ic_socket == NULL)
+		return (ECONNRESET);
+
 	if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_IN ||
 	    csio->dxfer_len < ci->ddp_threshold) {
 no_ddp:
@@ -1209,8 +1214,17 @@ no_ddp:
 		 * Do not get inp from toep->inp as the toepcb might
 		 * have detached already.
 		 */
+		ICL_CONN_LOCK(ic);
+		if (ic->ic_disconnecting || ic->ic_socket == NULL) {
+			ICL_CONN_UNLOCK(ic);
+			mbufq_drain(&mq);
+			t4_free_page_pods(prsv);
+			free(ddp, M_CXGBEI);
+			return (ECONNRESET);
+		}
 		inp = sotoinpcb(ic->ic_socket);
 		INP_WLOCK(inp);
+		ICL_CONN_UNLOCK(ic);
 		if ((inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT)) != 0) {
 			INP_WUNLOCK(inp);
 			mbufq_drain(&mq);