Bluetooth: rfcomm: Fix lost wakeups waiting to accept socket
authorPeter Hurley <peter@hurleysoftware.com>
Sun, 24 Jul 2011 04:10:41 +0000 (00:10 -0400)
committerGustavo F. Padovan <padovan@profusion.mobi>
Thu, 11 Aug 2011 22:50:26 +0000 (19:50 -0300)
Fix race conditions which can cause lost wakeups (or missed
signals) while waiting to accept an rfcomm socket connection.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
net/bluetooth/rfcomm/sock.c

index 8f01e6b11a7037d487c5a32072d460d56760a64a..482722bbc7a052c67053a95ad357463a5bc641bf 100644 (file)
@@ -485,11 +485,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
 
        lock_sock(sk);
 
-       if (sk->sk_state != BT_LISTEN) {
-               err = -EBADFD;
-               goto done;
-       }
-
        if (sk->sk_type != SOCK_STREAM) {
                err = -EINVAL;
                goto done;
@@ -501,19 +496,20 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
 
        /* Wait for an incoming connection. (wake-one). */
        add_wait_queue_exclusive(sk_sleep(sk), &wait);
-       while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+       while (1) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (!timeo) {
-                       err = -EAGAIN;
+
+               if (sk->sk_state != BT_LISTEN) {
+                       err = -EBADFD;
                        break;
                }
 
-               release_sock(sk);
-               timeo = schedule_timeout(timeo);
-               lock_sock(sk);
+               nsk = bt_accept_dequeue(sk, newsock);
+               if (nsk)
+                       break;
 
-               if (sk->sk_state != BT_LISTEN) {
-                       err = -EBADFD;
+               if (!timeo) {
+                       err = -EAGAIN;
                        break;
                }
 
@@ -521,8 +517,12 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
                        err = sock_intr_errno(timeo);
                        break;
                }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
        }
-       set_current_state(TASK_RUNNING);
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)