net/smc: smc_poll improvements
authorUrsula Braun <ubraun@linux.vnet.ibm.com>
Fri, 26 Jan 2018 08:28:47 +0000 (09:28 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 Jan 2018 15:41:56 +0000 (10:41 -0500)
Increase the socket refcount during poll wait.
Take the socket lock before checking socket state.
For a listening socket return a mask independent of state SMC_ACTIVE and
cover errors or closed state as well.
Get rid of the accept_q loop in smc_accept_poll().

Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/af_smc.c

index cf0e119..90c22a8 100644 (file)
@@ -1122,21 +1122,15 @@ out:
 
 static unsigned int smc_accept_poll(struct sock *parent)
 {
-       struct smc_sock *isk;
-       struct sock *sk;
-
-       lock_sock(parent);
-       list_for_each_entry(isk, &smc_sk(parent)->accept_q, accept_q) {
-               sk = (struct sock *)isk;
+       struct smc_sock *isk = smc_sk(parent);
+       int mask = 0;
 
-               if (sk->sk_state == SMC_ACTIVE) {
-                       release_sock(parent);
-                       return POLLIN | POLLRDNORM;
-               }
-       }
-       release_sock(parent);
+       spin_lock(&isk->accept_q_lock);
+       if (!list_empty(&isk->accept_q))
+               mask = POLLIN | POLLRDNORM;
+       spin_unlock(&isk->accept_q_lock);
 
-       return 0;
+       return mask;
 }
 
 static unsigned int smc_poll(struct file *file, struct socket *sock,
@@ -1147,9 +1141,15 @@ static unsigned int smc_poll(struct file *file, struct socket *sock,
        struct smc_sock *smc;
        int rc;
 
+       if (!sk)
+               return POLLNVAL;
+
        smc = smc_sk(sock->sk);
+       sock_hold(sk);
+       lock_sock(sk);
        if ((sk->sk_state == SMC_INIT) || smc->use_fallback) {
                /* delegate to CLC child sock */
+               release_sock(sk);
                mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
                /* if non-blocking connect finished ... */
                lock_sock(sk);
@@ -1161,37 +1161,43 @@ static unsigned int smc_poll(struct file *file, struct socket *sock,
                                rc = smc_connect_rdma(smc);
                                if (rc < 0)
                                        mask |= POLLERR;
-                               else
-                                       /* success cases including fallback */
-                                       mask |= POLLOUT | POLLWRNORM;
+                               /* success cases including fallback */
+                               mask |= POLLOUT | POLLWRNORM;
                        }
                }
-               release_sock(sk);
        } else {
-               sock_poll_wait(file, sk_sleep(sk), wait);
-               if (sk->sk_state == SMC_LISTEN)
-                       /* woken up by sk_data_ready in smc_listen_work() */
-                       mask |= smc_accept_poll(sk);
+               if (sk->sk_state != SMC_CLOSED) {
+                       release_sock(sk);
+                       sock_poll_wait(file, sk_sleep(sk), wait);
+                       lock_sock(sk);
+               }
                if (sk->sk_err)
                        mask |= POLLERR;
-               if (atomic_read(&smc->conn.sndbuf_space) ||
-                   (sk->sk_shutdown & SEND_SHUTDOWN)) {
-                       mask |= POLLOUT | POLLWRNORM;
-               } else {
-                       sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
-                       set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
-               }
-               if (atomic_read(&smc->conn.bytes_to_rcv))
-                       mask |= POLLIN | POLLRDNORM;
                if ((sk->sk_shutdown == SHUTDOWN_MASK) ||
                    (sk->sk_state == SMC_CLOSED))
                        mask |= POLLHUP;
-               if (sk->sk_shutdown & RCV_SHUTDOWN)
-                       mask |= POLLIN | POLLRDNORM | POLLRDHUP;
-               if (sk->sk_state == SMC_APPCLOSEWAIT1)
-                       mask |= POLLIN;
+               if (sk->sk_state == SMC_LISTEN) {
+                       /* woken up by sk_data_ready in smc_listen_work() */
+                       mask = smc_accept_poll(sk);
+               } else {
+                       if (atomic_read(&smc->conn.sndbuf_space) ||
+                           sk->sk_shutdown & SEND_SHUTDOWN) {
+                               mask |= POLLOUT | POLLWRNORM;
+                       } else {
+                               sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
+                               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+                       }
+                       if (atomic_read(&smc->conn.bytes_to_rcv))
+                               mask |= POLLIN | POLLRDNORM;
+                       if (sk->sk_shutdown & RCV_SHUTDOWN)
+                               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
+                       if (sk->sk_state == SMC_APPCLOSEWAIT1)
+                               mask |= POLLIN;
+               }
 
        }
+       release_sock(sk);
+       sock_put(sk);
 
        return mask;
 }