aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUrsula Braun <ubraun@linux.vnet.ibm.com>2018-01-24 04:28:16 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-24 10:52:57 -0500
commitbbb96bf2366e502fd16a8082f723c570e50269e8 (patch)
tree529859340dd23cffd08c57ef5547790c92e1f0f2
parent86e780d3a312faad967d2cfd5281f6bae81c0e55 (diff)
net/smc: improve state change handling after close wait
When a socket is closed or shutdown, smc waits for data being transmitted in certain states. If the state changes during this wait, the close switch depending on state should be reentered. In addition, state change is avoided if sending of close or shutdown fails. Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/smc/smc_close.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c
index bc539ccb8fa0..1468a2a3cdf4 100644
--- a/net/smc/smc_close.c
+++ b/net/smc/smc_close.c
@@ -165,9 +165,9 @@ int smc_close_active(struct smc_sock *smc)
165 0 : sock_flag(sk, SOCK_LINGER) ? 165 0 : sock_flag(sk, SOCK_LINGER) ?
166 sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT; 166 sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT;
167 167
168again:
169 old_state = sk->sk_state; 168 old_state = sk->sk_state;
170 switch (old_state) { 169again:
170 switch (sk->sk_state) {
171 case SMC_INIT: 171 case SMC_INIT:
172 sk->sk_state = SMC_CLOSED; 172 sk->sk_state = SMC_CLOSED;
173 if (smc->smc_listen_work.func) 173 if (smc->smc_listen_work.func)
@@ -194,6 +194,8 @@ again:
194 if (sk->sk_state == SMC_ACTIVE) { 194 if (sk->sk_state == SMC_ACTIVE) {
195 /* send close request */ 195 /* send close request */
196 rc = smc_close_final(conn); 196 rc = smc_close_final(conn);
197 if (rc)
198 break;
197 sk->sk_state = SMC_PEERCLOSEWAIT1; 199 sk->sk_state = SMC_PEERCLOSEWAIT1;
198 } else { 200 } else {
199 /* peer event has changed the state */ 201 /* peer event has changed the state */
@@ -206,6 +208,8 @@ again:
206 !smc_close_sent_any_close(conn)) { 208 !smc_close_sent_any_close(conn)) {
207 /* just shutdown wr done, send close request */ 209 /* just shutdown wr done, send close request */
208 rc = smc_close_final(conn); 210 rc = smc_close_final(conn);
211 if (rc)
212 break;
209 } 213 }
210 sk->sk_state = SMC_CLOSED; 214 sk->sk_state = SMC_CLOSED;
211 break; 215 break;
@@ -216,12 +220,13 @@ again:
216 release_sock(sk); 220 release_sock(sk);
217 cancel_delayed_work_sync(&conn->tx_work); 221 cancel_delayed_work_sync(&conn->tx_work);
218 lock_sock(sk); 222 lock_sock(sk);
219 if (sk->sk_err != ECONNABORTED) { 223 if (sk->sk_state != SMC_APPCLOSEWAIT1 &&
220 /* confirm close from peer */ 224 sk->sk_state != SMC_APPCLOSEWAIT2)
221 rc = smc_close_final(conn); 225 goto again;
222 if (rc) 226 /* confirm close from peer */
223 break; 227 rc = smc_close_final(conn);
224 } 228 if (rc)
229 break;
225 if (smc_cdc_rxed_any_close(conn)) 230 if (smc_cdc_rxed_any_close(conn))
226 /* peer has closed the socket already */ 231 /* peer has closed the socket already */
227 sk->sk_state = SMC_CLOSED; 232 sk->sk_state = SMC_CLOSED;
@@ -235,6 +240,8 @@ again:
235 !smc_close_sent_any_close(conn)) { 240 !smc_close_sent_any_close(conn)) {
236 /* just shutdown wr done, send close request */ 241 /* just shutdown wr done, send close request */
237 rc = smc_close_final(conn); 242 rc = smc_close_final(conn);
243 if (rc)
244 break;
238 } 245 }
239 /* peer sending PeerConnectionClosed will cause transition */ 246 /* peer sending PeerConnectionClosed will cause transition */
240 break; 247 break;
@@ -401,20 +408,21 @@ int smc_close_shutdown_write(struct smc_sock *smc)
401 0 : sock_flag(sk, SOCK_LINGER) ? 408 0 : sock_flag(sk, SOCK_LINGER) ?
402 sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT; 409 sk->sk_lingertime : SMC_MAX_STREAM_WAIT_TIMEOUT;
403 410
404again:
405 old_state = sk->sk_state; 411 old_state = sk->sk_state;
406 switch (old_state) { 412again:
413 switch (sk->sk_state) {
407 case SMC_ACTIVE: 414 case SMC_ACTIVE:
408 smc_close_stream_wait(smc, timeout); 415 smc_close_stream_wait(smc, timeout);
409 release_sock(sk); 416 release_sock(sk);
410 cancel_delayed_work_sync(&conn->tx_work); 417 cancel_delayed_work_sync(&conn->tx_work);
411 lock_sock(sk); 418 lock_sock(sk);
419 if (sk->sk_state != SMC_ACTIVE)
420 goto again;
412 /* send close wr request */ 421 /* send close wr request */
413 rc = smc_close_wr(conn); 422 rc = smc_close_wr(conn);
414 if (sk->sk_state == SMC_ACTIVE) 423 if (rc)
415 sk->sk_state = SMC_PEERCLOSEWAIT1; 424 break;
416 else 425 sk->sk_state = SMC_PEERCLOSEWAIT1;
417 goto again;
418 break; 426 break;
419 case SMC_APPCLOSEWAIT1: 427 case SMC_APPCLOSEWAIT1:
420 /* passive close */ 428 /* passive close */
@@ -423,8 +431,12 @@ again:
423 release_sock(sk); 431 release_sock(sk);
424 cancel_delayed_work_sync(&conn->tx_work); 432 cancel_delayed_work_sync(&conn->tx_work);
425 lock_sock(sk); 433 lock_sock(sk);
434 if (sk->sk_state != SMC_APPCLOSEWAIT1)
435 goto again;
426 /* confirm close from peer */ 436 /* confirm close from peer */
427 rc = smc_close_wr(conn); 437 rc = smc_close_wr(conn);
438 if (rc)
439 break;
428 sk->sk_state = SMC_APPCLOSEWAIT2; 440 sk->sk_state = SMC_APPCLOSEWAIT2;
429 break; 441 break;
430 case SMC_APPCLOSEWAIT2: 442 case SMC_APPCLOSEWAIT2: