aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2021-06-18 23:15:50 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2021-06-22 23:09:54 +0000
commitabc273a2901b116cc98a1fb506c75ac1b0a14cd3 (patch)
treeccf0efefb6a92239c25d24ca63a1d5c4f825ad4c
parentc4804b6b0b94f1c7228b62114bf294d63f6db2b7 (diff)
downloadsrc-abc273a2901b116cc98a1fb506c75ac1b0a14cd3.tar.gz
src-abc273a2901b116cc98a1fb506c75ac1b0a14cd3.zip
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.
-rw-r--r--sys/dev/cxgbe/cxgbei/icl_cxgbei.c14
1 files changed, 14 insertions, 0 deletions
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);