From: Amir Vadai Date: Tue, 18 Nov 2008 13:41:15 +0000 (+0200) Subject: SDP: BUG1343 - Polygraph test crashes machine X-Git-Tag: v4.1.12-92~264^2~5^2~306 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=f1e1cd00f15cc80585832d9db14003a5ff6f1c52;p=users%2Fjedix%2Flinux-maple.git SDP: BUG1343 - Polygraph test crashes machine No socket reference was taken before starting DREQ timeout. cancel delayed work only remove the work if it is in the timer stage before entered to the workqueue. Because of that, sdp_dreq_timeout_work could be in the work queue after the socket was destructed. and when the socket was reused and the inlined work structre was resetted things went wrong. Signed-off-by: Amir Vadai --- diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 0e7794e4cf206..b2b51e047409e 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -66,6 +66,7 @@ extern int sdp_data_debug_level; #define SOCK_REF_CLONE "CLONE" #define SOCK_REF_CM_TW "CM_TW" /* TIMEWAIT_ENTER -> TIMEWAIT_EXIT */ #define SOCK_REF_SEQ "SEQ" /* during proc read */ +#define SOCK_REF_DREQ_TO "DREQ_TO" /* dreq timeout is pending */ #define sock_hold(sk, msg) sock_ref(sk, msg, sock_hold) #define sock_put(sk, msg) sock_ref(sk, msg, sock_put) diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c index cbd1adb4e9dde..0d34aa00bf35d 100644 --- a/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/drivers/infiniband/ulp/sdp/sdp_main.c @@ -443,6 +443,7 @@ done: static void sdp_send_disconnect(struct sock *sk) { + sock_hold(sk, SOCK_REF_DREQ_TO); queue_delayed_work(sdp_workqueue, &sdp_sk(sk)->dreq_wait_work, SDP_FIN_WAIT_TIMEOUT); sdp_sk(sk)->dreq_wait_timeout = 1; @@ -843,7 +844,10 @@ void sdp_cancel_dreq_wait_timeout(struct sdp_sock *ssk) sdp_dbg(&ssk->isk.sk, "cancelling dreq wait timeout #####\n"); ssk->dreq_wait_timeout = 0; - cancel_delayed_work(&ssk->dreq_wait_work); + if (cancel_delayed_work(&ssk->dreq_wait_work)) { + /* The timeout hasn't reached - need to clean ref count */ + sock_put(&ssk->isk.sk, SOCK_REF_DREQ_TO); + } atomic_dec(ssk->isk.sk.sk_prot->orphan_count); } @@ -876,7 +880,7 @@ void sdp_dreq_wait_timeout_work(struct work_struct *work) if (!sdp_sk(sk)->dreq_wait_timeout || !((1 << sk->sk_state) & (TCPF_FIN_WAIT1 | TCPF_LAST_ACK))) { release_sock(sk); - return; + goto out; } sdp_warn(sk, "timed out waiting for FIN/DREQ. " @@ -893,14 +897,20 @@ void sdp_dreq_wait_timeout_work(struct work_struct *work) if (sdp_sk(sk)->id) rdma_disconnect(sdp_sk(sk)->id); + +out: + sock_put(sk, SOCK_REF_DREQ_TO); } static int sdp_init_sock(struct sock *sk) { struct sdp_sock *ssk = sdp_sk(sk); + struct inet_sock *isk = (struct inet_sock *)sk; sdp_dbg(sk, "%s\n", __func__); + memset(isk + 1, 0, sizeof(struct sdp_sock) - sizeof(*isk)); + INIT_LIST_HEAD(&ssk->accept_queue); INIT_LIST_HEAD(&ssk->backlog_queue); INIT_DELAYED_WORK(&ssk->dreq_wait_work, sdp_dreq_wait_timeout_work);