tipc: remove SS_DISCONNECTING state
authorParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Tue, 1 Nov 2016 13:02:47 +0000 (14:02 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Nov 2016 15:53:25 +0000 (11:53 -0400)
In this commit, we replace the references to SS_DISCONNECTING with
the combination of sk_state TIPC_DISCONNECTING and flags set in
sk_shutdown.
We introduce a new function _tipc_shutdown(), which provides
the common code required by tipc_release() and tipc_shutdown().

Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/socket.c

index a48c0c0676cf0587bc177b3507556a8610fce2f9..e732b1fe7eab9945388cc16fbb9b0df88c1ea36e 100644 (file)
@@ -442,6 +442,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        }
        msg_set_origport(msg, tsk->portid);
        setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk);
+       sk->sk_shutdown = 0;
        sk->sk_backlog_rcv = tipc_backlog_rcv;
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
@@ -470,6 +471,44 @@ static void tipc_sk_callback(struct rcu_head *head)
        sock_put(&tsk->sk);
 }
 
+/* Caller should hold socket lock for the socket. */
+static void __tipc_shutdown(struct socket *sock, int error)
+{
+       struct sock *sk = sock->sk;
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct net *net = sock_net(sk);
+       u32 dnode = tsk_peer_node(tsk);
+       struct sk_buff *skb;
+
+       /* Reject all unreceived messages, except on an active connection
+        * (which disconnects locally & sends a 'FIN+' to peer).
+        */
+       while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+               if (TIPC_SKB_CB(skb)->bytes_read) {
+                       kfree_skb(skb);
+               } else {
+                       if (!tipc_sk_type_connectionless(sk) &&
+                           sk->sk_state != TIPC_DISCONNECTING) {
+                               tipc_set_sk_state(sk, TIPC_DISCONNECTING);
+                               tipc_node_remove_conn(net, dnode, tsk->portid);
+                       }
+                       tipc_sk_respond(sk, skb, error);
+               }
+       }
+       if (sk->sk_state != TIPC_DISCONNECTING) {
+               skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
+                                     TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode,
+                                     tsk_own_node(tsk), tsk_peer_port(tsk),
+                                     tsk->portid, error);
+               if (skb)
+                       tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
+               if (!tipc_sk_type_connectionless(sk)) {
+                       tipc_node_remove_conn(net, dnode, tsk->portid);
+                       tipc_set_sk_state(sk, TIPC_DISCONNECTING);
+               }
+       }
+}
+
 /**
  * tipc_release - destroy a TIPC socket
  * @sock: socket to destroy
@@ -489,10 +528,7 @@ static void tipc_sk_callback(struct rcu_head *head)
 static int tipc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct net *net;
        struct tipc_sock *tsk;
-       struct sk_buff *skb;
-       u32 dnode;
 
        /*
         * Exit if socket isn't fully initialized (occurs when a failed accept()
@@ -501,46 +537,16 @@ static int tipc_release(struct socket *sock)
        if (sk == NULL)
                return 0;
 
-       net = sock_net(sk);
        tsk = tipc_sk(sk);
        lock_sock(sk);
 
-       /*
-        * Reject all unreceived messages, except on an active connection
-        * (which disconnects locally & sends a 'FIN+' to peer)
-        */
-       dnode = tsk_peer_node(tsk);
-       while (sock->state != SS_DISCONNECTING) {
-               skb = __skb_dequeue(&sk->sk_receive_queue);
-               if (skb == NULL)
-                       break;
-               if (TIPC_SKB_CB(skb)->bytes_read)
-                       kfree_skb(skb);
-               else {
-                       if ((sock->state == SS_CONNECTING) ||
-                           (sock->state == SS_CONNECTED)) {
-                               sock->state = SS_DISCONNECTING;
-                               tipc_node_remove_conn(net, dnode, tsk->portid);
-                       }
-                       tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT);
-               }
-       }
-
+       __tipc_shutdown(sock, TIPC_ERR_NO_PORT);
+       sk->sk_shutdown = SHUTDOWN_MASK;
        tipc_sk_withdraw(tsk, 0, NULL);
        sk_stop_timer(sk, &sk->sk_timer);
        tipc_sk_remove(tsk);
-       if (tipc_sk_connected(sk)) {
-               skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
-                                     TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode,
-                                     tsk_own_node(tsk), tsk_peer_port(tsk),
-                                     tsk->portid, TIPC_ERR_NO_PORT);
-               if (skb)
-                       tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
-               tipc_node_remove_conn(net, dnode, tsk->portid);
-       }
 
        /* Reject any messages that accumulated in backlog queue */
-       sock->state = SS_DISCONNECTING;
        release_sock(sk);
 
        call_rcu(&tsk->rcu, tipc_sk_callback);
@@ -678,6 +684,11 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
 
        sock_poll_wait(file, sk_sleep(sk), wait);
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
+       if (sk->sk_shutdown == SHUTDOWN_MASK)
+               mask |= POLLHUP;
+
        switch ((int)sock->state) {
        case SS_CONNECTED:
                if (!tsk->link_cong && !tsk_conn_cong(tsk))
@@ -687,9 +698,6 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
                if (!skb_queue_empty(&sk->sk_receive_queue))
                        mask |= (POLLIN | POLLRDNORM);
                break;
-       case SS_DISCONNECTING:
-               mask = (POLLIN | POLLRDNORM | POLLHUP);
-               break;
        default:
                switch (sk->sk_state) {
                case TIPC_OPEN:
@@ -882,7 +890,7 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
                int err = sock_error(sk);
                if (err)
                        return err;
-               if (sock->state == SS_DISCONNECTING)
+               if (sk->sk_shutdown & SEND_SHUTDOWN)
                        return -EPIPE;
                if (!*timeo_p)
                        return -EAGAIN;
@@ -1335,7 +1343,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
        for (;;) {
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
-                       if (sock->state == SS_DISCONNECTING) {
+                       if (sk->sk_shutdown & RCV_SHUTDOWN) {
                                err = -ENOTCONN;
                                break;
                        }
@@ -1676,9 +1684,6 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
                /* 'ACK-' message is neither accepted nor rejected: */
                msg_set_dest_droppable(hdr, 1);
                return false;
-
-       case SS_DISCONNECTING:
-               break;
        }
 
        switch (sk->sk_state) {
@@ -2191,13 +2196,6 @@ exit:
 static int tipc_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
-       struct net *net = sock_net(sk);
-       struct tipc_sock *tsk = tipc_sk(sk);
-       struct sk_buff *skb;
-       u32 dnode = tsk_peer_node(tsk);
-       u32 dport = tsk_peer_port(tsk);
-       u32 onode = tipc_own_addr(net);
-       u32 oport = tsk->portid;
        int res;
 
        if (how != SHUT_RDWR)
@@ -2205,43 +2203,17 @@ static int tipc_shutdown(struct socket *sock, int how)
 
        lock_sock(sk);
 
-       if (sock->state == SS_CONNECTING || sock->state == SS_CONNECTED) {
-
-restart:
-               dnode = tsk_peer_node(tsk);
-
-               /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */
-               skb = __skb_dequeue(&sk->sk_receive_queue);
-               if (skb) {
-                       if (TIPC_SKB_CB(skb)->bytes_read) {
-                               kfree_skb(skb);
-                               goto restart;
-                       }
-                       tipc_sk_respond(sk, skb, TIPC_CONN_SHUTDOWN);
-               } else {
-                       skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
-                                             TIPC_CONN_MSG, SHORT_H_SIZE,
-                                             0, dnode, onode, dport, oport,
-                                             TIPC_CONN_SHUTDOWN);
-                       if (skb)
-                               tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
-               }
-               tipc_set_sk_state(sk, TIPC_DISCONNECTING);
-               tipc_node_remove_conn(net, dnode, tsk->portid);
-       }
-
-       switch (sk->sk_state) {
-       case TIPC_DISCONNECTING:
+       __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
+       sk->sk_shutdown = SEND_SHUTDOWN;
 
+       if (sk->sk_state == TIPC_DISCONNECTING) {
                /* Discard any unreceived messages */
                __skb_queue_purge(&sk->sk_receive_queue);
 
                /* Wake up anyone sleeping in poll */
                sk->sk_state_change(sk);
                res = 0;
-               break;
-
-       default:
+       } else {
                res = -ENOTCONN;
        }