sctp: Prevent soft lockup when sctp_accept() is called during a timeout event
[pandora-kernel.git] / net / sctp / sm_sideeffect.c
index 76388b0..5437b33 100644 (file)
@@ -249,11 +249,12 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
        int error;
        struct sctp_transport *transport = (struct sctp_transport *) peer;
        struct sctp_association *asoc = transport->asoc;
+       struct sock *sk = asoc->base.sk;
 
        /* Check whether a task is in the sock.  */
 
-       sctp_bh_lock_sock(asoc->base.sk);
-       if (sock_owned_by_user(asoc->base.sk)) {
+       sctp_bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
                SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
 
                /* Try again later.  */
@@ -276,10 +277,10 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
                           transport, GFP_ATOMIC);
 
        if (error)
-               asoc->base.sk->sk_err = -error;
+               sk->sk_err = -error;
 
 out_unlock:
-       sctp_bh_unlock_sock(asoc->base.sk);
+       sctp_bh_unlock_sock(sk);
        sctp_transport_put(transport);
 }
 
@@ -289,10 +290,11 @@ out_unlock:
 static void sctp_generate_timeout_event(struct sctp_association *asoc,
                                        sctp_event_timeout_t timeout_type)
 {
+       struct sock *sk = asoc->base.sk;
        int error = 0;
 
-       sctp_bh_lock_sock(asoc->base.sk);
-       if (sock_owned_by_user(asoc->base.sk)) {
+       sctp_bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
                SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
                                  __func__,
                                  timeout_type);
@@ -316,10 +318,10 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
                           (void *)timeout_type, GFP_ATOMIC);
 
        if (error)
-               asoc->base.sk->sk_err = -error;
+               sk->sk_err = -error;
 
 out_unlock:
-       sctp_bh_unlock_sock(asoc->base.sk);
+       sctp_bh_unlock_sock(sk);
        sctp_association_put(asoc);
 }
 
@@ -369,9 +371,10 @@ void sctp_generate_heartbeat_event(unsigned long data)
        int error = 0;
        struct sctp_transport *transport = (struct sctp_transport *) data;
        struct sctp_association *asoc = transport->asoc;
+       struct sock *sk = asoc->base.sk;
 
-       sctp_bh_lock_sock(asoc->base.sk);
-       if (sock_owned_by_user(asoc->base.sk)) {
+       sctp_bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
                SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
 
                /* Try again later.  */
@@ -392,10 +395,10 @@ void sctp_generate_heartbeat_event(unsigned long data)
                           transport, GFP_ATOMIC);
 
         if (error)
-                asoc->base.sk->sk_err = -error;
+               sk->sk_err = -error;
 
 out_unlock:
-       sctp_bh_unlock_sock(asoc->base.sk);
+       sctp_bh_unlock_sock(sk);
        sctp_transport_put(transport);
 }
 
@@ -406,9 +409,10 @@ void sctp_generate_proto_unreach_event(unsigned long data)
 {
        struct sctp_transport *transport = (struct sctp_transport *) data;
        struct sctp_association *asoc = transport->asoc;
+       struct sock *sk = asoc->base.sk;
        
-       sctp_bh_lock_sock(asoc->base.sk);
-       if (sock_owned_by_user(asoc->base.sk)) {
+       sctp_bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
                SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
 
                /* Try again later.  */
@@ -429,7 +433,7 @@ void sctp_generate_proto_unreach_event(unsigned long data)
                   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
 
 out_unlock:
-       sctp_bh_unlock_sock(asoc->base.sk);
+       sctp_bh_unlock_sock(sk);
        sctp_association_put(asoc);
 }
 
@@ -681,7 +685,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
         * outstanding data and rely on the retransmission limit be reached
         * to shutdown the association.
         */
-       if (t->asoc->state != SCTP_STATE_SHUTDOWN_PENDING)
+       if (t->asoc->state < SCTP_STATE_SHUTDOWN_PENDING)
                t->asoc->overall_error_count = 0;
 
        /* Clear the hb_sent flag to signal that we had a good