| .. | .. |
|---|
| 13 | 13 | #include <linux/sched/signal.h> |
|---|
| 14 | 14 | |
|---|
| 15 | 15 | #include <net/sock.h> |
|---|
| 16 | +#include <net/tcp.h> |
|---|
| 16 | 17 | |
|---|
| 17 | 18 | #include "smc.h" |
|---|
| 18 | 19 | #include "smc_tx.h" |
|---|
| 19 | 20 | #include "smc_cdc.h" |
|---|
| 20 | 21 | #include "smc_close.h" |
|---|
| 21 | 22 | |
|---|
| 22 | | -#define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ) |
|---|
| 23 | +/* release the clcsock that is assigned to the smc_sock */ |
|---|
| 24 | +void smc_clcsock_release(struct smc_sock *smc) |
|---|
| 25 | +{ |
|---|
| 26 | + struct socket *tcp; |
|---|
| 27 | + |
|---|
| 28 | + if (smc->listen_smc && current_work() != &smc->smc_listen_work) |
|---|
| 29 | + cancel_work_sync(&smc->smc_listen_work); |
|---|
| 30 | + mutex_lock(&smc->clcsock_release_lock); |
|---|
| 31 | + if (smc->clcsock) { |
|---|
| 32 | + tcp = smc->clcsock; |
|---|
| 33 | + smc->clcsock = NULL; |
|---|
| 34 | + sock_release(tcp); |
|---|
| 35 | + } |
|---|
| 36 | + mutex_unlock(&smc->clcsock_release_lock); |
|---|
| 37 | +} |
|---|
| 23 | 38 | |
|---|
| 24 | 39 | static void smc_close_cleanup_listen(struct sock *parent) |
|---|
| 25 | 40 | { |
|---|
| .. | .. |
|---|
| 49 | 64 | |
|---|
| 50 | 65 | rc = sk_wait_event(sk, &timeout, |
|---|
| 51 | 66 | !smc_tx_prepared_sends(&smc->conn) || |
|---|
| 52 | | - (sk->sk_err == ECONNABORTED) || |
|---|
| 53 | | - (sk->sk_err == ECONNRESET), |
|---|
| 67 | + sk->sk_err == ECONNABORTED || |
|---|
| 68 | + sk->sk_err == ECONNRESET || |
|---|
| 69 | + smc->conn.killed, |
|---|
| 54 | 70 | &wait); |
|---|
| 55 | 71 | if (rc) |
|---|
| 56 | 72 | break; |
|---|
| .. | .. |
|---|
| 79 | 95 | conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; |
|---|
| 80 | 96 | else |
|---|
| 81 | 97 | conn->local_tx_ctrl.conn_state_flags.peer_conn_closed = 1; |
|---|
| 98 | + if (conn->killed) |
|---|
| 99 | + return -EPIPE; |
|---|
| 82 | 100 | |
|---|
| 83 | 101 | return smc_cdc_get_slot_and_msg_send(conn); |
|---|
| 84 | 102 | } |
|---|
| 85 | 103 | |
|---|
| 86 | | -static int smc_close_abort(struct smc_connection *conn) |
|---|
| 104 | +int smc_close_abort(struct smc_connection *conn) |
|---|
| 87 | 105 | { |
|---|
| 88 | 106 | conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; |
|---|
| 89 | 107 | |
|---|
| 90 | 108 | return smc_cdc_get_slot_and_msg_send(conn); |
|---|
| 91 | 109 | } |
|---|
| 92 | 110 | |
|---|
| 93 | | -/* terminate smc socket abnormally - active abort |
|---|
| 94 | | - * link group is terminated, i.e. RDMA communication no longer possible |
|---|
| 95 | | - */ |
|---|
| 96 | | -static void smc_close_active_abort(struct smc_sock *smc) |
|---|
| 111 | +static void smc_close_cancel_work(struct smc_sock *smc) |
|---|
| 97 | 112 | { |
|---|
| 98 | 113 | struct sock *sk = &smc->sk; |
|---|
| 99 | 114 | |
|---|
| 100 | | - struct smc_cdc_conn_state_flags *txflags = |
|---|
| 101 | | - &smc->conn.local_tx_ctrl.conn_state_flags; |
|---|
| 115 | + release_sock(sk); |
|---|
| 116 | + cancel_work_sync(&smc->conn.close_work); |
|---|
| 117 | + cancel_delayed_work_sync(&smc->conn.tx_work); |
|---|
| 118 | + lock_sock(sk); |
|---|
| 119 | +} |
|---|
| 120 | + |
|---|
| 121 | +/* terminate smc socket abnormally - active abort |
|---|
| 122 | + * link group is terminated, i.e. RDMA communication no longer possible |
|---|
| 123 | + */ |
|---|
| 124 | +void smc_close_active_abort(struct smc_sock *smc) |
|---|
| 125 | +{ |
|---|
| 126 | + struct sock *sk = &smc->sk; |
|---|
| 127 | + bool release_clcsock = false; |
|---|
| 102 | 128 | |
|---|
| 103 | 129 | if (sk->sk_state != SMC_INIT && smc->clcsock && smc->clcsock->sk) { |
|---|
| 104 | 130 | sk->sk_err = ECONNABORTED; |
|---|
| 105 | | - if (smc->clcsock && smc->clcsock->sk) { |
|---|
| 106 | | - smc->clcsock->sk->sk_err = ECONNABORTED; |
|---|
| 107 | | - smc->clcsock->sk->sk_state_change(smc->clcsock->sk); |
|---|
| 108 | | - } |
|---|
| 131 | + if (smc->clcsock && smc->clcsock->sk) |
|---|
| 132 | + tcp_abort(smc->clcsock->sk, ECONNABORTED); |
|---|
| 109 | 133 | } |
|---|
| 110 | 134 | switch (sk->sk_state) { |
|---|
| 111 | 135 | case SMC_ACTIVE: |
|---|
| 112 | | - sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 113 | | - release_sock(sk); |
|---|
| 114 | | - cancel_delayed_work_sync(&smc->conn.tx_work); |
|---|
| 115 | | - lock_sock(sk); |
|---|
| 116 | | - sock_put(sk); /* passive closing */ |
|---|
| 117 | | - break; |
|---|
| 118 | 136 | case SMC_APPCLOSEWAIT1: |
|---|
| 119 | 137 | case SMC_APPCLOSEWAIT2: |
|---|
| 120 | | - if (!smc_cdc_rxed_any_close(&smc->conn)) |
|---|
| 121 | | - sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 122 | | - else |
|---|
| 123 | | - sk->sk_state = SMC_CLOSED; |
|---|
| 124 | | - release_sock(sk); |
|---|
| 125 | | - cancel_delayed_work_sync(&smc->conn.tx_work); |
|---|
| 126 | | - lock_sock(sk); |
|---|
| 138 | + sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 139 | + smc_close_cancel_work(smc); |
|---|
| 140 | + if (sk->sk_state != SMC_PEERABORTWAIT) |
|---|
| 141 | + break; |
|---|
| 142 | + sk->sk_state = SMC_CLOSED; |
|---|
| 143 | + sock_put(sk); /* (postponed) passive closing */ |
|---|
| 127 | 144 | break; |
|---|
| 128 | 145 | case SMC_PEERCLOSEWAIT1: |
|---|
| 129 | 146 | case SMC_PEERCLOSEWAIT2: |
|---|
| 130 | | - if (!txflags->peer_conn_closed) { |
|---|
| 131 | | - /* just SHUTDOWN_SEND done */ |
|---|
| 132 | | - sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 133 | | - } else { |
|---|
| 134 | | - sk->sk_state = SMC_CLOSED; |
|---|
| 135 | | - } |
|---|
| 147 | + case SMC_PEERFINCLOSEWAIT: |
|---|
| 148 | + sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 149 | + smc_close_cancel_work(smc); |
|---|
| 150 | + if (sk->sk_state != SMC_PEERABORTWAIT) |
|---|
| 151 | + break; |
|---|
| 152 | + sk->sk_state = SMC_CLOSED; |
|---|
| 153 | + smc_conn_free(&smc->conn); |
|---|
| 154 | + release_clcsock = true; |
|---|
| 136 | 155 | sock_put(sk); /* passive closing */ |
|---|
| 137 | 156 | break; |
|---|
| 138 | 157 | case SMC_PROCESSABORT: |
|---|
| 139 | 158 | case SMC_APPFINCLOSEWAIT: |
|---|
| 159 | + sk->sk_state = SMC_PEERABORTWAIT; |
|---|
| 160 | + smc_close_cancel_work(smc); |
|---|
| 161 | + if (sk->sk_state != SMC_PEERABORTWAIT) |
|---|
| 162 | + break; |
|---|
| 140 | 163 | sk->sk_state = SMC_CLOSED; |
|---|
| 141 | | - break; |
|---|
| 142 | | - case SMC_PEERFINCLOSEWAIT: |
|---|
| 143 | | - sock_put(sk); /* passive closing */ |
|---|
| 164 | + smc_conn_free(&smc->conn); |
|---|
| 165 | + release_clcsock = true; |
|---|
| 144 | 166 | break; |
|---|
| 145 | 167 | case SMC_INIT: |
|---|
| 146 | 168 | case SMC_PEERABORTWAIT: |
|---|
| .. | .. |
|---|
| 150 | 172 | |
|---|
| 151 | 173 | sock_set_flag(sk, SOCK_DEAD); |
|---|
| 152 | 174 | sk->sk_state_change(sk); |
|---|
| 175 | + |
|---|
| 176 | + if (release_clcsock) { |
|---|
| 177 | + release_sock(sk); |
|---|
| 178 | + smc_clcsock_release(smc); |
|---|
| 179 | + lock_sock(sk); |
|---|
| 180 | + } |
|---|
| 153 | 181 | } |
|---|
| 154 | 182 | |
|---|
| 155 | 183 | static inline bool smc_close_sent_any_close(struct smc_connection *conn) |
|---|
| .. | .. |
|---|
| 183 | 211 | sk->sk_state = SMC_CLOSED; |
|---|
| 184 | 212 | sk->sk_state_change(sk); /* wake up accept */ |
|---|
| 185 | 213 | if (smc->clcsock && smc->clcsock->sk) { |
|---|
| 214 | + smc->clcsock->sk->sk_data_ready = smc->clcsk_data_ready; |
|---|
| 215 | + smc->clcsock->sk->sk_user_data = NULL; |
|---|
| 186 | 216 | rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR); |
|---|
| 187 | | - /* wake up kernel_accept of smc_tcp_listen_worker */ |
|---|
| 188 | | - smc->clcsock->sk->sk_data_ready(smc->clcsock->sk); |
|---|
| 189 | 217 | } |
|---|
| 190 | 218 | smc_close_cleanup_listen(sk); |
|---|
| 191 | 219 | release_sock(sk); |
|---|
| .. | .. |
|---|
| 200 | 228 | if (sk->sk_state == SMC_ACTIVE) { |
|---|
| 201 | 229 | /* send close request */ |
|---|
| 202 | 230 | rc = smc_close_final(conn); |
|---|
| 203 | | - if (rc) |
|---|
| 204 | | - break; |
|---|
| 205 | 231 | sk->sk_state = SMC_PEERCLOSEWAIT1; |
|---|
| 206 | 232 | |
|---|
| 207 | 233 | /* actively shutdown clcsock before peer close it, |
|---|
| .. | .. |
|---|
| 223 | 249 | !smc_close_sent_any_close(conn)) { |
|---|
| 224 | 250 | /* just shutdown wr done, send close request */ |
|---|
| 225 | 251 | rc = smc_close_final(conn); |
|---|
| 226 | | - if (rc) |
|---|
| 227 | | - break; |
|---|
| 228 | 252 | } |
|---|
| 229 | 253 | sk->sk_state = SMC_CLOSED; |
|---|
| 230 | 254 | break; |
|---|
| .. | .. |
|---|
| 240 | 264 | goto again; |
|---|
| 241 | 265 | /* confirm close from peer */ |
|---|
| 242 | 266 | rc = smc_close_final(conn); |
|---|
| 243 | | - if (rc) |
|---|
| 244 | | - break; |
|---|
| 245 | 267 | if (smc_cdc_rxed_any_close(conn)) { |
|---|
| 246 | 268 | /* peer has closed the socket already */ |
|---|
| 247 | 269 | sk->sk_state = SMC_CLOSED; |
|---|
| .. | .. |
|---|
| 257 | 279 | !smc_close_sent_any_close(conn)) { |
|---|
| 258 | 280 | /* just shutdown wr done, send close request */ |
|---|
| 259 | 281 | rc = smc_close_final(conn); |
|---|
| 260 | | - if (rc) |
|---|
| 261 | | - break; |
|---|
| 262 | 282 | } |
|---|
| 263 | 283 | /* peer sending PeerConnectionClosed will cause transition */ |
|---|
| 264 | 284 | break; |
|---|
| .. | .. |
|---|
| 266 | 286 | /* peer sending PeerConnectionClosed will cause transition */ |
|---|
| 267 | 287 | break; |
|---|
| 268 | 288 | case SMC_PROCESSABORT: |
|---|
| 269 | | - smc_close_abort(conn); |
|---|
| 289 | + rc = smc_close_abort(conn); |
|---|
| 270 | 290 | sk->sk_state = SMC_CLOSED; |
|---|
| 271 | 291 | break; |
|---|
| 272 | 292 | case SMC_PEERABORTWAIT: |
|---|
| 293 | + sk->sk_state = SMC_CLOSED; |
|---|
| 294 | + break; |
|---|
| 273 | 295 | case SMC_CLOSED: |
|---|
| 274 | 296 | /* nothing to do, add tracing in future patch */ |
|---|
| 275 | 297 | break; |
|---|
| .. | .. |
|---|
| 331 | 353 | close_work); |
|---|
| 332 | 354 | struct smc_sock *smc = container_of(conn, struct smc_sock, conn); |
|---|
| 333 | 355 | struct smc_cdc_conn_state_flags *rxflags; |
|---|
| 356 | + bool release_clcsock = false; |
|---|
| 334 | 357 | struct sock *sk = &smc->sk; |
|---|
| 335 | 358 | int old_state; |
|---|
| 336 | 359 | |
|---|
| 337 | 360 | lock_sock(sk); |
|---|
| 338 | 361 | old_state = sk->sk_state; |
|---|
| 339 | | - |
|---|
| 340 | | - if (!conn->alert_token_local) { |
|---|
| 341 | | - /* abnormal termination */ |
|---|
| 342 | | - smc_close_active_abort(smc); |
|---|
| 343 | | - goto wakeup; |
|---|
| 344 | | - } |
|---|
| 345 | 362 | |
|---|
| 346 | 363 | rxflags = &conn->local_rx_ctrl.conn_state_flags; |
|---|
| 347 | 364 | if (rxflags->peer_conn_abort) { |
|---|
| .. | .. |
|---|
| 355 | 372 | |
|---|
| 356 | 373 | switch (sk->sk_state) { |
|---|
| 357 | 374 | case SMC_INIT: |
|---|
| 358 | | - if (atomic_read(&conn->bytes_to_rcv) || |
|---|
| 359 | | - (rxflags->peer_done_writing && |
|---|
| 360 | | - !smc_cdc_rxed_any_close(conn))) { |
|---|
| 361 | | - sk->sk_state = SMC_APPCLOSEWAIT1; |
|---|
| 362 | | - } else { |
|---|
| 363 | | - sk->sk_state = SMC_CLOSED; |
|---|
| 364 | | - sock_put(sk); /* passive closing */ |
|---|
| 365 | | - } |
|---|
| 375 | + sk->sk_state = SMC_APPCLOSEWAIT1; |
|---|
| 366 | 376 | break; |
|---|
| 367 | 377 | case SMC_ACTIVE: |
|---|
| 368 | 378 | sk->sk_state = SMC_APPCLOSEWAIT1; |
|---|
| .. | .. |
|---|
| 373 | 383 | case SMC_PEERCLOSEWAIT1: |
|---|
| 374 | 384 | if (rxflags->peer_done_writing) |
|---|
| 375 | 385 | sk->sk_state = SMC_PEERCLOSEWAIT2; |
|---|
| 376 | | - /* fall through */ |
|---|
| 386 | + fallthrough; |
|---|
| 377 | 387 | /* to check for closing */ |
|---|
| 378 | 388 | case SMC_PEERCLOSEWAIT2: |
|---|
| 379 | 389 | if (!smc_cdc_rxed_any_close(conn)) |
|---|
| .. | .. |
|---|
| 415 | 425 | if (old_state != sk->sk_state) { |
|---|
| 416 | 426 | sk->sk_state_change(sk); |
|---|
| 417 | 427 | if ((sk->sk_state == SMC_CLOSED) && |
|---|
| 418 | | - (sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) |
|---|
| 428 | + (sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) { |
|---|
| 419 | 429 | smc_conn_free(conn); |
|---|
| 430 | + if (smc->clcsock) |
|---|
| 431 | + release_clcsock = true; |
|---|
| 432 | + } |
|---|
| 420 | 433 | } |
|---|
| 421 | 434 | release_sock(sk); |
|---|
| 435 | + if (release_clcsock) |
|---|
| 436 | + smc_clcsock_release(smc); |
|---|
| 422 | 437 | sock_put(sk); /* sock_hold done by schedulers of close_work */ |
|---|
| 423 | 438 | } |
|---|
| 424 | 439 | |
|---|
| .. | .. |
|---|
| 446 | 461 | goto again; |
|---|
| 447 | 462 | /* send close wr request */ |
|---|
| 448 | 463 | rc = smc_close_wr(conn); |
|---|
| 449 | | - if (rc) |
|---|
| 450 | | - break; |
|---|
| 451 | 464 | sk->sk_state = SMC_PEERCLOSEWAIT1; |
|---|
| 452 | 465 | break; |
|---|
| 453 | 466 | case SMC_APPCLOSEWAIT1: |
|---|
| .. | .. |
|---|
| 461 | 474 | goto again; |
|---|
| 462 | 475 | /* confirm close from peer */ |
|---|
| 463 | 476 | rc = smc_close_wr(conn); |
|---|
| 464 | | - if (rc) |
|---|
| 465 | | - break; |
|---|
| 466 | 477 | sk->sk_state = SMC_APPCLOSEWAIT2; |
|---|
| 467 | 478 | break; |
|---|
| 468 | 479 | case SMC_APPCLOSEWAIT2: |
|---|