diff mbox series

[net,2/2] net/smc: Ensure the active closing peer first closes clcsock

Message ID 20211123082515.65956-3-tonylu@linux.alibaba.com (mailing list archive)
State Not Applicable
Headers show
Series Fixes for closing process and minor cleanup | expand

Commit Message

Tony Lu Nov. 23, 2021, 8:25 a.m. UTC
The side that actively closed socket, it's clcsock doesn't enter
TIME_WAIT state, but the passive side does it. It should show the same
behavior as TCP sockets.

Consider this, when client actively closes the socket, the clcsock in
server enters TIME_WAIT state, which means the address is occupied and
won't be reused before TIME_WAIT dismissing. If we restarted server, the
service would be unavailable for a long time.

To solve this issue, shutdown the clcsock in [A], perform the TCP active
close progress first, before the passive closed side closing it. So that
the actively closed side enters TIME_WAIT, not the passive one.

Client                                            |  Server
close() // client actively close                  |
  smc_release()                                   |
      smc_close_active() // PEERCLOSEWAIT1        |
          smc_close_final() // abort or closed = 1|
              smc_cdc_get_slot_and_msg_send()     |
          [A]                                     |
                                                  |smc_cdc_msg_recv_action() // ACTIVE
                                                  |  queue_work(smc_close_wq, &conn->close_work)
                                                  |    smc_close_passive_work() // PROCESSABORT or APPCLOSEWAIT1
                                                  |      smc_close_passive_abort_received() // only in abort
                                                  |
                                                  |close() // server recv zero, close
                                                  |  smc_release() // PROCESSABORT or APPCLOSEWAIT1
                                                  |    smc_close_active()
                                                  |      smc_close_abort() or smc_close_final() // CLOSED
                                                  |        smc_cdc_get_slot_and_msg_send() // abort or closed = 1
smc_cdc_msg_recv_action()                         |    smc_clcsock_release()
  queue_work(smc_close_wq, &conn->close_work)     |      sock_release(tcp) // actively close clc, enter TIME_WAIT
    smc_close_passive_work() // PEERCLOSEWAIT1    |    smc_conn_free()
      smc_close_passive_abort_received() // CLOSED|
      smc_conn_free()                             |
      smc_clcsock_release()                       |
        sock_release(tcp) // passive close clc    |

Link: https://www.spinics.net/lists/netdev/msg780407.html
Fixes: b38d732477e4 ("smc: socket closing and linkgroup cleanup")
Signed-off-by: Tony Lu <tonylu@linux.alibaba.com>
Reviewed-by: Wen Gu <guwen@linux.alibaba.com>
---
 net/smc/smc_close.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

Karsten Graul Nov. 23, 2021, 8:36 a.m. UTC | #1
On 23/11/2021 09:25, Tony Lu wrote:
> The side that actively closed socket, it's clcsock doesn't enter
> TIME_WAIT state, but the passive side does it. It should show the same
> behavior as TCP sockets.
> 
> Consider this, when client actively closes the socket, the clcsock in
> server enters TIME_WAIT state, which means the address is occupied and
> won't be reused before TIME_WAIT dismissing. If we restarted server, the
> service would be unavailable for a long time.
> 
> To solve this issue, shutdown the clcsock in [A], perform the TCP active
> close progress first, before the passive closed side closing it. So that
> the actively closed side enters TIME_WAIT, not the passive one.
> 

Thank you, I will pick this up for our next submission to the net tree.
diff mbox series

Patch

diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c
index 9b235fbb089a..3715d2f5ad55 100644
--- a/net/smc/smc_close.c
+++ b/net/smc/smc_close.c
@@ -228,6 +228,12 @@  int smc_close_active(struct smc_sock *smc)
 			/* send close request */
 			rc = smc_close_final(conn);
 			sk->sk_state = SMC_PEERCLOSEWAIT1;
+
+			/* actively shutdown clcsock before peer close it,
+			 * prevent peer from entering TIME_WAIT state.
+			 */
+			if (smc->clcsock && smc->clcsock->sk)
+				rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
 		} else {
 			/* peer event has changed the state */
 			goto again;