Skip to content

Commit 46c28db

Browse files
Ursula Braundavem330
authored andcommitted
net/smc: no socket state changes in tasklet context
Several state changes occur during SMC socket closing. Currently state changes triggered locally occur in process context with lock_sock() taken while state changes triggered by peer occur in tasklet context with bh_lock_sock() taken. bh_lock_sock() does not wait till a lock_sock(() task in process context is finished. This may lead to races in socket state transitions resulting in dangling SMC-sockets, or it may lead to duplicate SMC socket freeing. This patch introduces a closing worker to run all state changes under lock_sock(). Signed-off-by: Ursula Braun <[email protected]> Reviewed-by: Thomas Richter <[email protected]> Reported-by: Dave Jones <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 90e9517 commit 46c28db

File tree

6 files changed

+41
-20
lines changed

6 files changed

+41
-20
lines changed

net/smc/af_smc.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,9 @@ static int smc_connect_rdma(struct smc_sock *smc)
451451
goto decline_rdma_unlock;
452452
}
453453

454+
smc_close_init(smc);
455+
smc_rx_init(smc);
456+
454457
if (local_contact == SMC_FIRST_CONTACT) {
455458
rc = smc_ib_ready_link(link);
456459
if (rc) {
@@ -477,7 +480,6 @@ static int smc_connect_rdma(struct smc_sock *smc)
477480

478481
mutex_unlock(&smc_create_lgr_pending);
479482
smc_tx_init(smc);
480-
smc_rx_init(smc);
481483

482484
out_connected:
483485
smc_copy_sock_settings_to_clc(smc);
@@ -800,6 +802,9 @@ static void smc_listen_work(struct work_struct *work)
800802
goto decline_rdma;
801803
}
802804

805+
smc_close_init(new_smc);
806+
smc_rx_init(new_smc);
807+
803808
rc = smc_clc_send_accept(new_smc, local_contact);
804809
if (rc)
805810
goto out_err;
@@ -839,7 +844,6 @@ static void smc_listen_work(struct work_struct *work)
839844
}
840845

841846
smc_tx_init(new_smc);
842-
smc_rx_init(new_smc);
843847

844848
out_connected:
845849
sk_refcnt_debug_inc(newsmcsk);

net/smc/smc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ struct smc_connection {
164164
#ifndef KERNEL_HAS_ATOMIC64
165165
spinlock_t acurs_lock; /* protect cursors */
166166
#endif
167+
struct work_struct close_work; /* peer sent some closing */
167168
};
168169

169170
struct smc_sock { /* smc sock container */

net/smc/smc_cdc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,13 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
217217
smc->sk.sk_err = ECONNRESET;
218218
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
219219
}
220-
if (smc_cdc_rxed_any_close_or_senddone(conn))
221-
smc_close_passive_received(smc);
220+
if (smc_cdc_rxed_any_close_or_senddone(conn)) {
221+
smc->sk.sk_shutdown |= RCV_SHUTDOWN;
222+
if (smc->clcsock && smc->clcsock->sk)
223+
smc->clcsock->sk->sk_shutdown |= RCV_SHUTDOWN;
224+
sock_set_flag(&smc->sk, SOCK_DONE);
225+
schedule_work(&conn->close_work);
226+
}
222227

223228
/* piggy backed tx info */
224229
/* trigger sndbuf consumer: RDMA write into peer RMBE and CDC */

net/smc/smc_close.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ void smc_close_active_abort(struct smc_sock *smc)
117117
struct smc_cdc_conn_state_flags *txflags =
118118
&smc->conn.local_tx_ctrl.conn_state_flags;
119119

120-
bh_lock_sock(&smc->sk);
121120
smc->sk.sk_err = ECONNABORTED;
122121
if (smc->clcsock && smc->clcsock->sk) {
123122
smc->clcsock->sk->sk_err = ECONNABORTED;
124123
smc->clcsock->sk->sk_state_change(smc->clcsock->sk);
125124
}
126125
switch (smc->sk.sk_state) {
127126
case SMC_INIT:
127+
case SMC_ACTIVE:
128128
smc->sk.sk_state = SMC_PEERABORTWAIT;
129129
break;
130130
case SMC_APPCLOSEWAIT1:
@@ -161,7 +161,6 @@ void smc_close_active_abort(struct smc_sock *smc)
161161
}
162162

163163
sock_set_flag(&smc->sk, SOCK_DEAD);
164-
bh_unlock_sock(&smc->sk);
165164
smc->sk.sk_state_change(&smc->sk);
166165
}
167166

@@ -185,7 +184,7 @@ int smc_close_active(struct smc_sock *smc)
185184
case SMC_INIT:
186185
sk->sk_state = SMC_CLOSED;
187186
if (smc->smc_listen_work.func)
188-
flush_work(&smc->smc_listen_work);
187+
cancel_work_sync(&smc->smc_listen_work);
189188
sock_put(sk);
190189
break;
191190
case SMC_LISTEN:
@@ -198,7 +197,7 @@ int smc_close_active(struct smc_sock *smc)
198197
}
199198
release_sock(sk);
200199
smc_close_cleanup_listen(sk);
201-
flush_work(&smc->tcp_listen_work);
200+
cancel_work_sync(&smc->smc_listen_work);
202201
lock_sock(sk);
203202
break;
204203
case SMC_ACTIVE:
@@ -306,22 +305,27 @@ static void smc_close_passive_abort_received(struct smc_sock *smc)
306305

307306
/* Some kind of closing has been received: peer_conn_closed, peer_conn_abort,
308307
* or peer_done_writing.
309-
* Called under tasklet context.
310308
*/
311-
void smc_close_passive_received(struct smc_sock *smc)
309+
static void smc_close_passive_work(struct work_struct *work)
312310
{
313-
struct smc_cdc_conn_state_flags *rxflags =
314-
&smc->conn.local_rx_ctrl.conn_state_flags;
311+
struct smc_connection *conn = container_of(work,
312+
struct smc_connection,
313+
close_work);
314+
struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
315+
struct smc_cdc_conn_state_flags *rxflags;
315316
struct sock *sk = &smc->sk;
316317
int old_state;
317318

318-
sk->sk_shutdown |= RCV_SHUTDOWN;
319-
if (smc->clcsock && smc->clcsock->sk)
320-
smc->clcsock->sk->sk_shutdown |= RCV_SHUTDOWN;
321-
sock_set_flag(&smc->sk, SOCK_DONE);
322-
319+
lock_sock(&smc->sk);
323320
old_state = sk->sk_state;
324321

322+
if (!conn->alert_token_local) {
323+
/* abnormal termination */
324+
smc_close_active_abort(smc);
325+
goto wakeup;
326+
}
327+
328+
rxflags = &smc->conn.local_rx_ctrl.conn_state_flags;
325329
if (rxflags->peer_conn_abort) {
326330
smc_close_passive_abort_received(smc);
327331
goto wakeup;
@@ -373,11 +377,12 @@ void smc_close_passive_received(struct smc_sock *smc)
373377
sk->sk_write_space(sk); /* wakeup blocked sndbuf producers */
374378

375379
if ((sk->sk_state == SMC_CLOSED) &&
376-
(sock_flag(sk, SOCK_DEAD) || (old_state == SMC_INIT))) {
380+
(sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) {
377381
smc_conn_free(&smc->conn);
378382
schedule_delayed_work(&smc->sock_put_work,
379383
SMC_CLOSE_SOCK_PUT_DELAY);
380384
}
385+
release_sock(&smc->sk);
381386
}
382387

383388
void smc_close_sock_put_work(struct work_struct *work)
@@ -442,3 +447,9 @@ int smc_close_shutdown_write(struct smc_sock *smc)
442447
sk->sk_state_change(&smc->sk);
443448
return rc;
444449
}
450+
451+
/* Initialize close properties on connection establishment. */
452+
void smc_close_init(struct smc_sock *smc)
453+
{
454+
INIT_WORK(&smc->conn.close_work, smc_close_passive_work);
455+
}

net/smc/smc_close.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
void smc_close_wake_tx_prepared(struct smc_sock *smc);
2222
void smc_close_active_abort(struct smc_sock *smc);
2323
int smc_close_active(struct smc_sock *smc);
24-
void smc_close_passive_received(struct smc_sock *smc);
2524
void smc_close_sock_put_work(struct work_struct *work);
2625
int smc_close_shutdown_write(struct smc_sock *smc);
26+
void smc_close_init(struct smc_sock *smc);
2727

2828
#endif /* SMC_CLOSE_H */

net/smc/smc_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ void smc_lgr_terminate(struct smc_link_group *lgr)
316316
smc = container_of(conn, struct smc_sock, conn);
317317
sock_hold(&smc->sk);
318318
__smc_lgr_unregister_conn(conn);
319-
smc_close_active_abort(smc);
319+
schedule_work(&conn->close_work);
320320
sock_put(&smc->sk);
321321
node = rb_first(&lgr->conns_all);
322322
}

0 commit comments

Comments
 (0)