diff options
author | Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com> | 2016-11-01 09:02:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-01 11:53:25 -0400 |
commit | 6f00089c7372ba9732c046fe242301dfb0a13233 (patch) | |
tree | 39064e06ccdb8a69f2bc8cf4da38f2739f42e14e /net/tipc/socket.c | |
parent | 9fd4b070f6311faa7ba1ae746e955fedfbe3e045 (diff) |
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: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 132 |
1 files changed, 52 insertions, 80 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index a48c0c0676cf..e732b1fe7eab 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -442,6 +442,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
442 | } | 442 | } |
443 | msg_set_origport(msg, tsk->portid); | 443 | msg_set_origport(msg, tsk->portid); |
444 | setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk); | 444 | setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk); |
445 | sk->sk_shutdown = 0; | ||
445 | sk->sk_backlog_rcv = tipc_backlog_rcv; | 446 | sk->sk_backlog_rcv = tipc_backlog_rcv; |
446 | sk->sk_rcvbuf = sysctl_tipc_rmem[1]; | 447 | sk->sk_rcvbuf = sysctl_tipc_rmem[1]; |
447 | sk->sk_data_ready = tipc_data_ready; | 448 | sk->sk_data_ready = tipc_data_ready; |
@@ -470,6 +471,44 @@ static void tipc_sk_callback(struct rcu_head *head) | |||
470 | sock_put(&tsk->sk); | 471 | sock_put(&tsk->sk); |
471 | } | 472 | } |
472 | 473 | ||
474 | /* Caller should hold socket lock for the socket. */ | ||
475 | static void __tipc_shutdown(struct socket *sock, int error) | ||
476 | { | ||
477 | struct sock *sk = sock->sk; | ||
478 | struct tipc_sock *tsk = tipc_sk(sk); | ||
479 | struct net *net = sock_net(sk); | ||
480 | u32 dnode = tsk_peer_node(tsk); | ||
481 | struct sk_buff *skb; | ||
482 | |||
483 | /* Reject all unreceived messages, except on an active connection | ||
484 | * (which disconnects locally & sends a 'FIN+' to peer). | ||
485 | */ | ||
486 | while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { | ||
487 | if (TIPC_SKB_CB(skb)->bytes_read) { | ||
488 | kfree_skb(skb); | ||
489 | } else { | ||
490 | if (!tipc_sk_type_connectionless(sk) && | ||
491 | sk->sk_state != TIPC_DISCONNECTING) { | ||
492 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | ||
493 | tipc_node_remove_conn(net, dnode, tsk->portid); | ||
494 | } | ||
495 | tipc_sk_respond(sk, skb, error); | ||
496 | } | ||
497 | } | ||
498 | if (sk->sk_state != TIPC_DISCONNECTING) { | ||
499 | skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, | ||
500 | TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, | ||
501 | tsk_own_node(tsk), tsk_peer_port(tsk), | ||
502 | tsk->portid, error); | ||
503 | if (skb) | ||
504 | tipc_node_xmit_skb(net, skb, dnode, tsk->portid); | ||
505 | if (!tipc_sk_type_connectionless(sk)) { | ||
506 | tipc_node_remove_conn(net, dnode, tsk->portid); | ||
507 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | |||
473 | /** | 512 | /** |
474 | * tipc_release - destroy a TIPC socket | 513 | * tipc_release - destroy a TIPC socket |
475 | * @sock: socket to destroy | 514 | * @sock: socket to destroy |
@@ -489,10 +528,7 @@ static void tipc_sk_callback(struct rcu_head *head) | |||
489 | static int tipc_release(struct socket *sock) | 528 | static int tipc_release(struct socket *sock) |
490 | { | 529 | { |
491 | struct sock *sk = sock->sk; | 530 | struct sock *sk = sock->sk; |
492 | struct net *net; | ||
493 | struct tipc_sock *tsk; | 531 | struct tipc_sock *tsk; |
494 | struct sk_buff *skb; | ||
495 | u32 dnode; | ||
496 | 532 | ||
497 | /* | 533 | /* |
498 | * Exit if socket isn't fully initialized (occurs when a failed accept() | 534 | * Exit if socket isn't fully initialized (occurs when a failed accept() |
@@ -501,46 +537,16 @@ static int tipc_release(struct socket *sock) | |||
501 | if (sk == NULL) | 537 | if (sk == NULL) |
502 | return 0; | 538 | return 0; |
503 | 539 | ||
504 | net = sock_net(sk); | ||
505 | tsk = tipc_sk(sk); | 540 | tsk = tipc_sk(sk); |
506 | lock_sock(sk); | 541 | lock_sock(sk); |
507 | 542 | ||
508 | /* | 543 | __tipc_shutdown(sock, TIPC_ERR_NO_PORT); |
509 | * Reject all unreceived messages, except on an active connection | 544 | sk->sk_shutdown = SHUTDOWN_MASK; |
510 | * (which disconnects locally & sends a 'FIN+' to peer) | ||
511 | */ | ||
512 | dnode = tsk_peer_node(tsk); | ||
513 | while (sock->state != SS_DISCONNECTING) { | ||
514 | skb = __skb_dequeue(&sk->sk_receive_queue); | ||
515 | if (skb == NULL) | ||
516 | break; | ||
517 | if (TIPC_SKB_CB(skb)->bytes_read) | ||
518 | kfree_skb(skb); | ||
519 | else { | ||
520 | if ((sock->state == SS_CONNECTING) || | ||
521 | (sock->state == SS_CONNECTED)) { | ||
522 | sock->state = SS_DISCONNECTING; | ||
523 | tipc_node_remove_conn(net, dnode, tsk->portid); | ||
524 | } | ||
525 | tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | tipc_sk_withdraw(tsk, 0, NULL); | 545 | tipc_sk_withdraw(tsk, 0, NULL); |
530 | sk_stop_timer(sk, &sk->sk_timer); | 546 | sk_stop_timer(sk, &sk->sk_timer); |
531 | tipc_sk_remove(tsk); | 547 | tipc_sk_remove(tsk); |
532 | if (tipc_sk_connected(sk)) { | ||
533 | skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, | ||
534 | TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, | ||
535 | tsk_own_node(tsk), tsk_peer_port(tsk), | ||
536 | tsk->portid, TIPC_ERR_NO_PORT); | ||
537 | if (skb) | ||
538 | tipc_node_xmit_skb(net, skb, dnode, tsk->portid); | ||
539 | tipc_node_remove_conn(net, dnode, tsk->portid); | ||
540 | } | ||
541 | 548 | ||
542 | /* Reject any messages that accumulated in backlog queue */ | 549 | /* Reject any messages that accumulated in backlog queue */ |
543 | sock->state = SS_DISCONNECTING; | ||
544 | release_sock(sk); | 550 | release_sock(sk); |
545 | 551 | ||
546 | call_rcu(&tsk->rcu, tipc_sk_callback); | 552 | call_rcu(&tsk->rcu, tipc_sk_callback); |
@@ -678,6 +684,11 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
678 | 684 | ||
679 | sock_poll_wait(file, sk_sleep(sk), wait); | 685 | sock_poll_wait(file, sk_sleep(sk), wait); |
680 | 686 | ||
687 | if (sk->sk_shutdown & RCV_SHUTDOWN) | ||
688 | mask |= POLLRDHUP | POLLIN | POLLRDNORM; | ||
689 | if (sk->sk_shutdown == SHUTDOWN_MASK) | ||
690 | mask |= POLLHUP; | ||
691 | |||
681 | switch ((int)sock->state) { | 692 | switch ((int)sock->state) { |
682 | case SS_CONNECTED: | 693 | case SS_CONNECTED: |
683 | if (!tsk->link_cong && !tsk_conn_cong(tsk)) | 694 | if (!tsk->link_cong && !tsk_conn_cong(tsk)) |
@@ -687,9 +698,6 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
687 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 698 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
688 | mask |= (POLLIN | POLLRDNORM); | 699 | mask |= (POLLIN | POLLRDNORM); |
689 | break; | 700 | break; |
690 | case SS_DISCONNECTING: | ||
691 | mask = (POLLIN | POLLRDNORM | POLLHUP); | ||
692 | break; | ||
693 | default: | 701 | default: |
694 | switch (sk->sk_state) { | 702 | switch (sk->sk_state) { |
695 | case TIPC_OPEN: | 703 | case TIPC_OPEN: |
@@ -882,7 +890,7 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | |||
882 | int err = sock_error(sk); | 890 | int err = sock_error(sk); |
883 | if (err) | 891 | if (err) |
884 | return err; | 892 | return err; |
885 | if (sock->state == SS_DISCONNECTING) | 893 | if (sk->sk_shutdown & SEND_SHUTDOWN) |
886 | return -EPIPE; | 894 | return -EPIPE; |
887 | if (!*timeo_p) | 895 | if (!*timeo_p) |
888 | return -EAGAIN; | 896 | return -EAGAIN; |
@@ -1335,7 +1343,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | |||
1335 | for (;;) { | 1343 | for (;;) { |
1336 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 1344 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
1337 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { | 1345 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
1338 | if (sock->state == SS_DISCONNECTING) { | 1346 | if (sk->sk_shutdown & RCV_SHUTDOWN) { |
1339 | err = -ENOTCONN; | 1347 | err = -ENOTCONN; |
1340 | break; | 1348 | break; |
1341 | } | 1349 | } |
@@ -1676,9 +1684,6 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
1676 | /* 'ACK-' message is neither accepted nor rejected: */ | 1684 | /* 'ACK-' message is neither accepted nor rejected: */ |
1677 | msg_set_dest_droppable(hdr, 1); | 1685 | msg_set_dest_droppable(hdr, 1); |
1678 | return false; | 1686 | return false; |
1679 | |||
1680 | case SS_DISCONNECTING: | ||
1681 | break; | ||
1682 | } | 1687 | } |
1683 | 1688 | ||
1684 | switch (sk->sk_state) { | 1689 | switch (sk->sk_state) { |
@@ -2191,13 +2196,6 @@ exit: | |||
2191 | static int tipc_shutdown(struct socket *sock, int how) | 2196 | static int tipc_shutdown(struct socket *sock, int how) |
2192 | { | 2197 | { |
2193 | struct sock *sk = sock->sk; | 2198 | struct sock *sk = sock->sk; |
2194 | struct net *net = sock_net(sk); | ||
2195 | struct tipc_sock *tsk = tipc_sk(sk); | ||
2196 | struct sk_buff *skb; | ||
2197 | u32 dnode = tsk_peer_node(tsk); | ||
2198 | u32 dport = tsk_peer_port(tsk); | ||
2199 | u32 onode = tipc_own_addr(net); | ||
2200 | u32 oport = tsk->portid; | ||
2201 | int res; | 2199 | int res; |
2202 | 2200 | ||
2203 | if (how != SHUT_RDWR) | 2201 | if (how != SHUT_RDWR) |
@@ -2205,43 +2203,17 @@ static int tipc_shutdown(struct socket *sock, int how) | |||
2205 | 2203 | ||
2206 | lock_sock(sk); | 2204 | lock_sock(sk); |
2207 | 2205 | ||
2208 | if (sock->state == SS_CONNECTING || sock->state == SS_CONNECTED) { | 2206 | __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN); |
2209 | 2207 | sk->sk_shutdown = SEND_SHUTDOWN; | |
2210 | restart: | ||
2211 | dnode = tsk_peer_node(tsk); | ||
2212 | |||
2213 | /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ | ||
2214 | skb = __skb_dequeue(&sk->sk_receive_queue); | ||
2215 | if (skb) { | ||
2216 | if (TIPC_SKB_CB(skb)->bytes_read) { | ||
2217 | kfree_skb(skb); | ||
2218 | goto restart; | ||
2219 | } | ||
2220 | tipc_sk_respond(sk, skb, TIPC_CONN_SHUTDOWN); | ||
2221 | } else { | ||
2222 | skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, | ||
2223 | TIPC_CONN_MSG, SHORT_H_SIZE, | ||
2224 | 0, dnode, onode, dport, oport, | ||
2225 | TIPC_CONN_SHUTDOWN); | ||
2226 | if (skb) | ||
2227 | tipc_node_xmit_skb(net, skb, dnode, tsk->portid); | ||
2228 | } | ||
2229 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | ||
2230 | tipc_node_remove_conn(net, dnode, tsk->portid); | ||
2231 | } | ||
2232 | |||
2233 | switch (sk->sk_state) { | ||
2234 | case TIPC_DISCONNECTING: | ||
2235 | 2208 | ||
2209 | if (sk->sk_state == TIPC_DISCONNECTING) { | ||
2236 | /* Discard any unreceived messages */ | 2210 | /* Discard any unreceived messages */ |
2237 | __skb_queue_purge(&sk->sk_receive_queue); | 2211 | __skb_queue_purge(&sk->sk_receive_queue); |
2238 | 2212 | ||
2239 | /* Wake up anyone sleeping in poll */ | 2213 | /* Wake up anyone sleeping in poll */ |
2240 | sk->sk_state_change(sk); | 2214 | sk->sk_state_change(sk); |
2241 | res = 0; | 2215 | res = 0; |
2242 | break; | 2216 | } else { |
2243 | |||
2244 | default: | ||
2245 | res = -ENOTCONN; | 2217 | res = -ENOTCONN; |
2246 | } | 2218 | } |
2247 | 2219 | ||