]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
SDP: BUG1343 - Polygraph test crashes machine
authorAmir Vadai <amirv@mellanox.co.il>
Tue, 18 Nov 2008 13:41:15 +0000 (15:41 +0200)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Tue, 6 Oct 2015 12:04:20 +0000 (05:04 -0700)
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 <amirv@mellanox.co.il>
drivers/infiniband/ulp/sdp/sdp.h
drivers/infiniband/ulp/sdp/sdp_main.c

index 0e7794e4cf206d2c34806b8f25476b4fecb89494..b2b51e047409ea9a7f2c1d5d468fcd19669bc714 100644 (file)
@@ -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)
index cbd1adb4e9dde6e2111550e4efc1c4e1cdb41fdd..0d34aa00bf35d86abed0012d3a3f07e0e66ffe0b 100644 (file)
@@ -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);