Commit 6f00089c authored by Parthasarathy Bhuvaragan's avatar Parthasarathy Bhuvaragan Committed by David S. Miller

tipc: remove SS_DISCONNECTING state

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: default avatarParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9fd4b070
...@@ -442,6 +442,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, ...@@ -442,6 +442,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
} }
msg_set_origport(msg, tsk->portid); msg_set_origport(msg, tsk->portid);
setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk); setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk);
sk->sk_shutdown = 0;
sk->sk_backlog_rcv = tipc_backlog_rcv; sk->sk_backlog_rcv = tipc_backlog_rcv;
sk->sk_rcvbuf = sysctl_tipc_rmem[1]; sk->sk_rcvbuf = sysctl_tipc_rmem[1];
sk->sk_data_ready = tipc_data_ready; sk->sk_data_ready = tipc_data_ready;
...@@ -470,6 +471,44 @@ static void tipc_sk_callback(struct rcu_head *head) ...@@ -470,6 +471,44 @@ static void tipc_sk_callback(struct rcu_head *head)
sock_put(&tsk->sk); 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 * tipc_release - destroy a TIPC socket
* @sock: socket to destroy * @sock: socket to destroy
...@@ -489,10 +528,7 @@ static void tipc_sk_callback(struct rcu_head *head) ...@@ -489,10 +528,7 @@ static void tipc_sk_callback(struct rcu_head *head)
static int tipc_release(struct socket *sock) static int tipc_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct net *net;
struct tipc_sock *tsk; struct tipc_sock *tsk;
struct sk_buff *skb;
u32 dnode;
/* /*
* Exit if socket isn't fully initialized (occurs when a failed accept() * Exit if socket isn't fully initialized (occurs when a failed accept()
...@@ -501,46 +537,16 @@ static int tipc_release(struct socket *sock) ...@@ -501,46 +537,16 @@ static int tipc_release(struct socket *sock)
if (sk == NULL) if (sk == NULL)
return 0; return 0;
net = sock_net(sk);
tsk = tipc_sk(sk); tsk = tipc_sk(sk);
lock_sock(sk); lock_sock(sk);
/* __tipc_shutdown(sock, TIPC_ERR_NO_PORT);
* Reject all unreceived messages, except on an active connection sk->sk_shutdown = SHUTDOWN_MASK;
* (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_sk_withdraw(tsk, 0, NULL); tipc_sk_withdraw(tsk, 0, NULL);
sk_stop_timer(sk, &sk->sk_timer); sk_stop_timer(sk, &sk->sk_timer);
tipc_sk_remove(tsk); 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 */ /* Reject any messages that accumulated in backlog queue */
sock->state = SS_DISCONNECTING;
release_sock(sk); release_sock(sk);
call_rcu(&tsk->rcu, tipc_sk_callback); call_rcu(&tsk->rcu, tipc_sk_callback);
...@@ -678,6 +684,11 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, ...@@ -678,6 +684,11 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
sock_poll_wait(file, sk_sleep(sk), wait); 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) { switch ((int)sock->state) {
case SS_CONNECTED: case SS_CONNECTED:
if (!tsk->link_cong && !tsk_conn_cong(tsk)) if (!tsk->link_cong && !tsk_conn_cong(tsk))
...@@ -687,9 +698,6 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, ...@@ -687,9 +698,6 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
if (!skb_queue_empty(&sk->sk_receive_queue)) if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= (POLLIN | POLLRDNORM); mask |= (POLLIN | POLLRDNORM);
break; break;
case SS_DISCONNECTING:
mask = (POLLIN | POLLRDNORM | POLLHUP);
break;
default: default:
switch (sk->sk_state) { switch (sk->sk_state) {
case TIPC_OPEN: case TIPC_OPEN:
...@@ -882,7 +890,7 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) ...@@ -882,7 +890,7 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
int err = sock_error(sk); int err = sock_error(sk);
if (err) if (err)
return err; return err;
if (sock->state == SS_DISCONNECTING) if (sk->sk_shutdown & SEND_SHUTDOWN)
return -EPIPE; return -EPIPE;
if (!*timeo_p) if (!*timeo_p)
return -EAGAIN; return -EAGAIN;
...@@ -1335,7 +1343,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) ...@@ -1335,7 +1343,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
for (;;) { for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
if (sock->state == SS_DISCONNECTING) { if (sk->sk_shutdown & RCV_SHUTDOWN) {
err = -ENOTCONN; err = -ENOTCONN;
break; break;
} }
...@@ -1676,9 +1684,6 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) ...@@ -1676,9 +1684,6 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
/* 'ACK-' message is neither accepted nor rejected: */ /* 'ACK-' message is neither accepted nor rejected: */
msg_set_dest_droppable(hdr, 1); msg_set_dest_droppable(hdr, 1);
return false; return false;
case SS_DISCONNECTING:
break;
} }
switch (sk->sk_state) { switch (sk->sk_state) {
...@@ -2191,13 +2196,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags) ...@@ -2191,13 +2196,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
static int tipc_shutdown(struct socket *sock, int how) static int tipc_shutdown(struct socket *sock, int how)
{ {
struct sock *sk = sock->sk; 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; int res;
if (how != SHUT_RDWR) if (how != SHUT_RDWR)
...@@ -2205,43 +2203,17 @@ static int tipc_shutdown(struct socket *sock, int how) ...@@ -2205,43 +2203,17 @@ static int tipc_shutdown(struct socket *sock, int how)
lock_sock(sk); lock_sock(sk);
if (sock->state == SS_CONNECTING || sock->state == SS_CONNECTED) { __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
sk->sk_shutdown = SEND_SHUTDOWN;
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:
if (sk->sk_state == TIPC_DISCONNECTING) {
/* Discard any unreceived messages */ /* Discard any unreceived messages */
__skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_receive_queue);
/* Wake up anyone sleeping in poll */ /* Wake up anyone sleeping in poll */
sk->sk_state_change(sk); sk->sk_state_change(sk);
res = 0; res = 0;
break; } else {
default:
res = -ENOTCONN; res = -ENOTCONN;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment