18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared Memory Communications over RDMA (SMC-R) and RoCE 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Socket Closing - normal and abnormal 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2016 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <net/sock.h> 168c2ecf20Sopenharmony_ci#include <net/tcp.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "smc.h" 198c2ecf20Sopenharmony_ci#include "smc_tx.h" 208c2ecf20Sopenharmony_ci#include "smc_cdc.h" 218c2ecf20Sopenharmony_ci#include "smc_close.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* release the clcsock that is assigned to the smc_sock */ 248c2ecf20Sopenharmony_civoid smc_clcsock_release(struct smc_sock *smc) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct socket *tcp; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (smc->listen_smc && current_work() != &smc->smc_listen_work) 298c2ecf20Sopenharmony_ci cancel_work_sync(&smc->smc_listen_work); 308c2ecf20Sopenharmony_ci mutex_lock(&smc->clcsock_release_lock); 318c2ecf20Sopenharmony_ci if (smc->clcsock) { 328c2ecf20Sopenharmony_ci tcp = smc->clcsock; 338c2ecf20Sopenharmony_ci smc->clcsock = NULL; 348c2ecf20Sopenharmony_ci sock_release(tcp); 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci mutex_unlock(&smc->clcsock_release_lock); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void smc_close_cleanup_listen(struct sock *parent) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct sock *sk; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Close non-accepted connections */ 448c2ecf20Sopenharmony_ci while ((sk = smc_accept_dequeue(parent, NULL))) 458c2ecf20Sopenharmony_ci smc_close_non_accepted(sk); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* wait for sndbuf data being transmitted */ 498c2ecf20Sopenharmony_cistatic void smc_close_stream_wait(struct smc_sock *smc, long timeout) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 528c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (!timeout) 558c2ecf20Sopenharmony_ci return; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!smc_tx_prepared_sends(&smc->conn)) 588c2ecf20Sopenharmony_ci return; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci smc->wait_close_tx_prepared = 1; 618c2ecf20Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 628c2ecf20Sopenharmony_ci while (!signal_pending(current) && timeout) { 638c2ecf20Sopenharmony_ci int rc; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci rc = sk_wait_event(sk, &timeout, 668c2ecf20Sopenharmony_ci !smc_tx_prepared_sends(&smc->conn) || 678c2ecf20Sopenharmony_ci READ_ONCE(sk->sk_err) == ECONNABORTED || 688c2ecf20Sopenharmony_ci READ_ONCE(sk->sk_err) == ECONNRESET || 698c2ecf20Sopenharmony_ci smc->conn.killed, 708c2ecf20Sopenharmony_ci &wait); 718c2ecf20Sopenharmony_ci if (rc) 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 758c2ecf20Sopenharmony_ci smc->wait_close_tx_prepared = 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid smc_close_wake_tx_prepared(struct smc_sock *smc) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci if (smc->wait_close_tx_prepared) 818c2ecf20Sopenharmony_ci /* wake up socket closing */ 828c2ecf20Sopenharmony_ci smc->sk.sk_state_change(&smc->sk); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int smc_close_wr(struct smc_connection *conn) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci conn->local_tx_ctrl.conn_state_flags.peer_done_writing = 1; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return smc_cdc_get_slot_and_msg_send(conn); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int smc_close_final(struct smc_connection *conn) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci if (atomic_read(&conn->bytes_to_rcv)) 958c2ecf20Sopenharmony_ci conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci conn->local_tx_ctrl.conn_state_flags.peer_conn_closed = 1; 988c2ecf20Sopenharmony_ci if (conn->killed) 998c2ecf20Sopenharmony_ci return -EPIPE; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return smc_cdc_get_slot_and_msg_send(conn); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciint smc_close_abort(struct smc_connection *conn) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return smc_cdc_get_slot_and_msg_send(conn); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void smc_close_cancel_work(struct smc_sock *smc) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci release_sock(sk); 1168c2ecf20Sopenharmony_ci if (cancel_work_sync(&smc->conn.close_work)) 1178c2ecf20Sopenharmony_ci sock_put(sk); 1188c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&smc->conn.tx_work); 1198c2ecf20Sopenharmony_ci lock_sock(sk); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* terminate smc socket abnormally - active abort 1238c2ecf20Sopenharmony_ci * link group is terminated, i.e. RDMA communication no longer possible 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_civoid smc_close_active_abort(struct smc_sock *smc) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 1288c2ecf20Sopenharmony_ci bool release_clcsock = false; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_INIT && smc->clcsock && smc->clcsock->sk) { 1318c2ecf20Sopenharmony_ci sk->sk_err = ECONNABORTED; 1328c2ecf20Sopenharmony_ci if (smc->clcsock && smc->clcsock->sk) 1338c2ecf20Sopenharmony_ci tcp_abort(smc->clcsock->sk, ECONNABORTED); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci switch (sk->sk_state) { 1368c2ecf20Sopenharmony_ci case SMC_ACTIVE: 1378c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT1: 1388c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT2: 1398c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERABORTWAIT; 1408c2ecf20Sopenharmony_ci smc_close_cancel_work(smc); 1418c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_PEERABORTWAIT) 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 1448c2ecf20Sopenharmony_ci sock_put(sk); /* (postponed) passive closing */ 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT1: 1478c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT2: 1488c2ecf20Sopenharmony_ci case SMC_PEERFINCLOSEWAIT: 1498c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERABORTWAIT; 1508c2ecf20Sopenharmony_ci smc_close_cancel_work(smc); 1518c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_PEERABORTWAIT) 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 1548c2ecf20Sopenharmony_ci smc_conn_free(&smc->conn); 1558c2ecf20Sopenharmony_ci release_clcsock = true; 1568c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case SMC_PROCESSABORT: 1598c2ecf20Sopenharmony_ci case SMC_APPFINCLOSEWAIT: 1608c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERABORTWAIT; 1618c2ecf20Sopenharmony_ci smc_close_cancel_work(smc); 1628c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_PEERABORTWAIT) 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 1658c2ecf20Sopenharmony_ci smc_conn_free(&smc->conn); 1668c2ecf20Sopenharmony_ci release_clcsock = true; 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case SMC_INIT: 1698c2ecf20Sopenharmony_ci case SMC_PEERABORTWAIT: 1708c2ecf20Sopenharmony_ci case SMC_CLOSED: 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci smc_sock_set_flag(sk, SOCK_DEAD); 1758c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (release_clcsock) { 1788c2ecf20Sopenharmony_ci release_sock(sk); 1798c2ecf20Sopenharmony_ci smc_clcsock_release(smc); 1808c2ecf20Sopenharmony_ci lock_sock(sk); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic inline bool smc_close_sent_any_close(struct smc_connection *conn) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return conn->local_tx_ctrl.conn_state_flags.peer_conn_abort || 1878c2ecf20Sopenharmony_ci conn->local_tx_ctrl.conn_state_flags.peer_conn_closed; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciint smc_close_active(struct smc_sock *smc) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct smc_cdc_conn_state_flags *txflags = 1938c2ecf20Sopenharmony_ci &smc->conn.local_tx_ctrl.conn_state_flags; 1948c2ecf20Sopenharmony_ci struct smc_connection *conn = &smc->conn; 1958c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 1968c2ecf20Sopenharmony_ci int old_state; 1978c2ecf20Sopenharmony_ci long timeout; 1988c2ecf20Sopenharmony_ci int rc = 0; 1998c2ecf20Sopenharmony_ci int rc1 = 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci timeout = current->flags & PF_EXITING ? 2028c2ecf20Sopenharmony_ci 0 : sock_flag(sk, SOCK_LINGER) ? 2038c2ecf20Sopenharmony_ci sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci old_state = sk->sk_state; 2068c2ecf20Sopenharmony_ciagain: 2078c2ecf20Sopenharmony_ci switch (sk->sk_state) { 2088c2ecf20Sopenharmony_ci case SMC_INIT: 2098c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case SMC_LISTEN: 2128c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2138c2ecf20Sopenharmony_ci sk->sk_state_change(sk); /* wake up accept */ 2148c2ecf20Sopenharmony_ci if (smc->clcsock && smc->clcsock->sk) { 2158c2ecf20Sopenharmony_ci smc->clcsock->sk->sk_data_ready = smc->clcsk_data_ready; 2168c2ecf20Sopenharmony_ci smc->clcsock->sk->sk_user_data = NULL; 2178c2ecf20Sopenharmony_ci rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci smc_close_cleanup_listen(sk); 2208c2ecf20Sopenharmony_ci release_sock(sk); 2218c2ecf20Sopenharmony_ci flush_work(&smc->tcp_listen_work); 2228c2ecf20Sopenharmony_ci lock_sock(sk); 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case SMC_ACTIVE: 2258c2ecf20Sopenharmony_ci smc_close_stream_wait(smc, timeout); 2268c2ecf20Sopenharmony_ci release_sock(sk); 2278c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->tx_work); 2288c2ecf20Sopenharmony_ci lock_sock(sk); 2298c2ecf20Sopenharmony_ci if (sk->sk_state == SMC_ACTIVE) { 2308c2ecf20Sopenharmony_ci /* send close request */ 2318c2ecf20Sopenharmony_ci rc = smc_close_final(conn); 2328c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERCLOSEWAIT1; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* actively shutdown clcsock before peer close it, 2358c2ecf20Sopenharmony_ci * prevent peer from entering TIME_WAIT state. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci if (smc->clcsock && smc->clcsock->sk) { 2388c2ecf20Sopenharmony_ci rc1 = kernel_sock_shutdown(smc->clcsock, 2398c2ecf20Sopenharmony_ci SHUT_RDWR); 2408c2ecf20Sopenharmony_ci rc = rc ? rc : rc1; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } else { 2438c2ecf20Sopenharmony_ci /* peer event has changed the state */ 2448c2ecf20Sopenharmony_ci goto again; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case SMC_APPFINCLOSEWAIT: 2488c2ecf20Sopenharmony_ci /* socket already shutdown wr or both (active close) */ 2498c2ecf20Sopenharmony_ci if (txflags->peer_done_writing && 2508c2ecf20Sopenharmony_ci !smc_close_sent_any_close(conn)) { 2518c2ecf20Sopenharmony_ci /* just shutdown wr done, send close request */ 2528c2ecf20Sopenharmony_ci rc = smc_close_final(conn); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT1: 2578c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT2: 2588c2ecf20Sopenharmony_ci if (!smc_cdc_rxed_any_close(conn)) 2598c2ecf20Sopenharmony_ci smc_close_stream_wait(smc, timeout); 2608c2ecf20Sopenharmony_ci release_sock(sk); 2618c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->tx_work); 2628c2ecf20Sopenharmony_ci lock_sock(sk); 2638c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_APPCLOSEWAIT1 && 2648c2ecf20Sopenharmony_ci sk->sk_state != SMC_APPCLOSEWAIT2) 2658c2ecf20Sopenharmony_ci goto again; 2668c2ecf20Sopenharmony_ci /* confirm close from peer */ 2678c2ecf20Sopenharmony_ci rc = smc_close_final(conn); 2688c2ecf20Sopenharmony_ci if (smc_cdc_rxed_any_close(conn)) { 2698c2ecf20Sopenharmony_ci /* peer has closed the socket already */ 2708c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2718c2ecf20Sopenharmony_ci sock_put(sk); /* postponed passive closing */ 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci /* peer has just issued a shutdown write */ 2748c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERFINCLOSEWAIT; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT1: 2788c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT2: 2798c2ecf20Sopenharmony_ci if (txflags->peer_done_writing && 2808c2ecf20Sopenharmony_ci !smc_close_sent_any_close(conn)) { 2818c2ecf20Sopenharmony_ci /* just shutdown wr done, send close request */ 2828c2ecf20Sopenharmony_ci rc = smc_close_final(conn); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci /* peer sending PeerConnectionClosed will cause transition */ 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci case SMC_PEERFINCLOSEWAIT: 2878c2ecf20Sopenharmony_ci /* peer sending PeerConnectionClosed will cause transition */ 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case SMC_PROCESSABORT: 2908c2ecf20Sopenharmony_ci rc = smc_close_abort(conn); 2918c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci case SMC_PEERABORTWAIT: 2948c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case SMC_CLOSED: 2978c2ecf20Sopenharmony_ci /* nothing to do, add tracing in future patch */ 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (old_state != sk->sk_state) 3028c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 3038c2ecf20Sopenharmony_ci return rc; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void smc_close_passive_abort_received(struct smc_sock *smc) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct smc_cdc_conn_state_flags *txflags = 3098c2ecf20Sopenharmony_ci &smc->conn.local_tx_ctrl.conn_state_flags; 3108c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci switch (sk->sk_state) { 3138c2ecf20Sopenharmony_ci case SMC_INIT: 3148c2ecf20Sopenharmony_ci case SMC_ACTIVE: 3158c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT1: 3168c2ecf20Sopenharmony_ci sk->sk_state = SMC_PROCESSABORT; 3178c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci case SMC_APPFINCLOSEWAIT: 3208c2ecf20Sopenharmony_ci sk->sk_state = SMC_PROCESSABORT; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT1: 3238c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT2: 3248c2ecf20Sopenharmony_ci if (txflags->peer_done_writing && 3258c2ecf20Sopenharmony_ci !smc_close_sent_any_close(&smc->conn)) 3268c2ecf20Sopenharmony_ci /* just shutdown, but not yet closed locally */ 3278c2ecf20Sopenharmony_ci sk->sk_state = SMC_PROCESSABORT; 3288c2ecf20Sopenharmony_ci else 3298c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 3308c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT2: 3338c2ecf20Sopenharmony_ci case SMC_PEERFINCLOSEWAIT: 3348c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 3358c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci case SMC_PEERABORTWAIT: 3388c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci case SMC_PROCESSABORT: 3418c2ecf20Sopenharmony_ci /* nothing to do, add tracing in future patch */ 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* Either some kind of closing has been received: peer_conn_closed, 3478c2ecf20Sopenharmony_ci * peer_conn_abort, or peer_done_writing 3488c2ecf20Sopenharmony_ci * or the link group of the connection terminates abnormally. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistatic void smc_close_passive_work(struct work_struct *work) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct smc_connection *conn = container_of(work, 3538c2ecf20Sopenharmony_ci struct smc_connection, 3548c2ecf20Sopenharmony_ci close_work); 3558c2ecf20Sopenharmony_ci struct smc_sock *smc = container_of(conn, struct smc_sock, conn); 3568c2ecf20Sopenharmony_ci struct smc_cdc_conn_state_flags *rxflags; 3578c2ecf20Sopenharmony_ci bool release_clcsock = false; 3588c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 3598c2ecf20Sopenharmony_ci int old_state; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci lock_sock(sk); 3628c2ecf20Sopenharmony_ci old_state = sk->sk_state; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci rxflags = &conn->local_rx_ctrl.conn_state_flags; 3658c2ecf20Sopenharmony_ci if (rxflags->peer_conn_abort) { 3668c2ecf20Sopenharmony_ci /* peer has not received all data */ 3678c2ecf20Sopenharmony_ci smc_close_passive_abort_received(smc); 3688c2ecf20Sopenharmony_ci release_sock(&smc->sk); 3698c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->tx_work); 3708c2ecf20Sopenharmony_ci lock_sock(&smc->sk); 3718c2ecf20Sopenharmony_ci goto wakeup; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci switch (sk->sk_state) { 3758c2ecf20Sopenharmony_ci case SMC_INIT: 3768c2ecf20Sopenharmony_ci sk->sk_state = SMC_APPCLOSEWAIT1; 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci case SMC_ACTIVE: 3798c2ecf20Sopenharmony_ci sk->sk_state = SMC_APPCLOSEWAIT1; 3808c2ecf20Sopenharmony_ci /* postpone sock_put() for passive closing to cover 3818c2ecf20Sopenharmony_ci * received SEND_SHUTDOWN as well 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT1: 3858c2ecf20Sopenharmony_ci if (rxflags->peer_done_writing) 3868c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERCLOSEWAIT2; 3878c2ecf20Sopenharmony_ci fallthrough; 3888c2ecf20Sopenharmony_ci /* to check for closing */ 3898c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT2: 3908c2ecf20Sopenharmony_ci if (!smc_cdc_rxed_any_close(conn)) 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD) && 3938c2ecf20Sopenharmony_ci smc_close_sent_any_close(conn)) { 3948c2ecf20Sopenharmony_ci /* smc_release has already been called locally */ 3958c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 3968c2ecf20Sopenharmony_ci } else { 3978c2ecf20Sopenharmony_ci /* just shutdown, but not yet closed locally */ 3988c2ecf20Sopenharmony_ci sk->sk_state = SMC_APPFINCLOSEWAIT; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci case SMC_PEERFINCLOSEWAIT: 4038c2ecf20Sopenharmony_ci if (smc_cdc_rxed_any_close(conn)) { 4048c2ecf20Sopenharmony_ci sk->sk_state = SMC_CLOSED; 4058c2ecf20Sopenharmony_ci sock_put(sk); /* passive closing */ 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT1: 4098c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT2: 4108c2ecf20Sopenharmony_ci /* postpone sock_put() for passive closing to cover 4118c2ecf20Sopenharmony_ci * received SEND_SHUTDOWN as well 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case SMC_APPFINCLOSEWAIT: 4158c2ecf20Sopenharmony_ci case SMC_PEERABORTWAIT: 4168c2ecf20Sopenharmony_ci case SMC_PROCESSABORT: 4178c2ecf20Sopenharmony_ci case SMC_CLOSED: 4188c2ecf20Sopenharmony_ci /* nothing to do, add tracing in future patch */ 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ciwakeup: 4238c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); /* wakeup blocked rcvbuf consumers */ 4248c2ecf20Sopenharmony_ci sk->sk_write_space(sk); /* wakeup blocked sndbuf producers */ 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (old_state != sk->sk_state) { 4278c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 4288c2ecf20Sopenharmony_ci if ((sk->sk_state == SMC_CLOSED) && 4298c2ecf20Sopenharmony_ci (sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) { 4308c2ecf20Sopenharmony_ci smc_conn_free(conn); 4318c2ecf20Sopenharmony_ci if (smc->clcsock) 4328c2ecf20Sopenharmony_ci release_clcsock = true; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci release_sock(sk); 4368c2ecf20Sopenharmony_ci if (release_clcsock) 4378c2ecf20Sopenharmony_ci smc_clcsock_release(smc); 4388c2ecf20Sopenharmony_ci sock_put(sk); /* sock_hold done by schedulers of close_work */ 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciint smc_close_shutdown_write(struct smc_sock *smc) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct smc_connection *conn = &smc->conn; 4448c2ecf20Sopenharmony_ci struct sock *sk = &smc->sk; 4458c2ecf20Sopenharmony_ci int old_state; 4468c2ecf20Sopenharmony_ci long timeout; 4478c2ecf20Sopenharmony_ci int rc = 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci timeout = current->flags & PF_EXITING ? 4508c2ecf20Sopenharmony_ci 0 : sock_flag(sk, SOCK_LINGER) ? 4518c2ecf20Sopenharmony_ci sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci old_state = sk->sk_state; 4548c2ecf20Sopenharmony_ciagain: 4558c2ecf20Sopenharmony_ci switch (sk->sk_state) { 4568c2ecf20Sopenharmony_ci case SMC_ACTIVE: 4578c2ecf20Sopenharmony_ci smc_close_stream_wait(smc, timeout); 4588c2ecf20Sopenharmony_ci release_sock(sk); 4598c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->tx_work); 4608c2ecf20Sopenharmony_ci lock_sock(sk); 4618c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_ACTIVE) 4628c2ecf20Sopenharmony_ci goto again; 4638c2ecf20Sopenharmony_ci /* send close wr request */ 4648c2ecf20Sopenharmony_ci rc = smc_close_wr(conn); 4658c2ecf20Sopenharmony_ci sk->sk_state = SMC_PEERCLOSEWAIT1; 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT1: 4688c2ecf20Sopenharmony_ci /* passive close */ 4698c2ecf20Sopenharmony_ci if (!smc_cdc_rxed_any_close(conn)) 4708c2ecf20Sopenharmony_ci smc_close_stream_wait(smc, timeout); 4718c2ecf20Sopenharmony_ci release_sock(sk); 4728c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->tx_work); 4738c2ecf20Sopenharmony_ci lock_sock(sk); 4748c2ecf20Sopenharmony_ci if (sk->sk_state != SMC_APPCLOSEWAIT1) 4758c2ecf20Sopenharmony_ci goto again; 4768c2ecf20Sopenharmony_ci /* confirm close from peer */ 4778c2ecf20Sopenharmony_ci rc = smc_close_wr(conn); 4788c2ecf20Sopenharmony_ci sk->sk_state = SMC_APPCLOSEWAIT2; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case SMC_APPCLOSEWAIT2: 4818c2ecf20Sopenharmony_ci case SMC_PEERFINCLOSEWAIT: 4828c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT1: 4838c2ecf20Sopenharmony_ci case SMC_PEERCLOSEWAIT2: 4848c2ecf20Sopenharmony_ci case SMC_APPFINCLOSEWAIT: 4858c2ecf20Sopenharmony_ci case SMC_PROCESSABORT: 4868c2ecf20Sopenharmony_ci case SMC_PEERABORTWAIT: 4878c2ecf20Sopenharmony_ci /* nothing to do, add tracing in future patch */ 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (old_state != sk->sk_state) 4928c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 4938c2ecf20Sopenharmony_ci return rc; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/* Initialize close properties on connection establishment. */ 4978c2ecf20Sopenharmony_civoid smc_close_init(struct smc_sock *smc) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci INIT_WORK(&smc->conn.close_work, smc_close_passive_work); 5008c2ecf20Sopenharmony_ci} 501