Skip to content

Commit fd57770

Browse files
karstengrdavem330
authored andcommitted
net/smc: wait for pending work before clcsock release_sock
When the clcsock is already released using sock_release() and a pending smc_listen_work accesses the clcsock than that will fail. Solve this by canceling and waiting for the work to complete first. Because the work holds the sock_lock it must make sure that the lock is not hold before the new helper smc_clcsock_release() is invoked. And before the smc_listen_work starts working check if the parent listen socket is still valid, otherwise stop the work early. Signed-off-by: Karsten Graul <[email protected]> Signed-off-by: Ursula Braun <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 988dc4a commit fd57770

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

net/smc/af_smc.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,9 @@ static int smc_release(struct socket *sock)
167167

168168
if (sk->sk_state == SMC_CLOSED) {
169169
if (smc->clcsock) {
170-
mutex_lock(&smc->clcsock_release_lock);
171-
sock_release(smc->clcsock);
172-
smc->clcsock = NULL;
173-
mutex_unlock(&smc->clcsock_release_lock);
170+
release_sock(sk);
171+
smc_clcsock_release(smc);
172+
lock_sock(sk);
174173
}
175174
if (!smc->use_fallback)
176175
smc_conn_free(&smc->conn);
@@ -1037,13 +1036,13 @@ static void smc_listen_out(struct smc_sock *new_smc)
10371036
struct smc_sock *lsmc = new_smc->listen_smc;
10381037
struct sock *newsmcsk = &new_smc->sk;
10391038

1040-
lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
10411039
if (lsmc->sk.sk_state == SMC_LISTEN) {
1040+
lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
10421041
smc_accept_enqueue(&lsmc->sk, newsmcsk);
1042+
release_sock(&lsmc->sk);
10431043
} else { /* no longer listening */
10441044
smc_close_non_accepted(newsmcsk);
10451045
}
1046-
release_sock(&lsmc->sk);
10471046

10481047
/* Wake up accept */
10491048
lsmc->sk.sk_data_ready(&lsmc->sk);
@@ -1237,6 +1236,9 @@ static void smc_listen_work(struct work_struct *work)
12371236
int rc = 0;
12381237
u8 ibport;
12391238

1239+
if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
1240+
return smc_listen_out_err(new_smc);
1241+
12401242
if (new_smc->use_fallback) {
12411243
smc_listen_out_connected(new_smc);
12421244
return;

net/smc/smc_close.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@
2121

2222
#define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ)
2323

24+
/* release the clcsock that is assigned to the smc_sock */
25+
void smc_clcsock_release(struct smc_sock *smc)
26+
{
27+
struct socket *tcp;
28+
29+
if (smc->listen_smc && current_work() != &smc->smc_listen_work)
30+
cancel_work_sync(&smc->smc_listen_work);
31+
mutex_lock(&smc->clcsock_release_lock);
32+
if (smc->clcsock) {
33+
tcp = smc->clcsock;
34+
smc->clcsock = NULL;
35+
sock_release(tcp);
36+
}
37+
mutex_unlock(&smc->clcsock_release_lock);
38+
}
39+
2440
static void smc_close_cleanup_listen(struct sock *parent)
2541
{
2642
struct sock *sk;
@@ -321,6 +337,7 @@ static void smc_close_passive_work(struct work_struct *work)
321337
close_work);
322338
struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
323339
struct smc_cdc_conn_state_flags *rxflags;
340+
bool release_clcsock = false;
324341
struct sock *sk = &smc->sk;
325342
int old_state;
326343

@@ -400,13 +417,13 @@ static void smc_close_passive_work(struct work_struct *work)
400417
if ((sk->sk_state == SMC_CLOSED) &&
401418
(sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) {
402419
smc_conn_free(conn);
403-
if (smc->clcsock) {
404-
sock_release(smc->clcsock);
405-
smc->clcsock = NULL;
406-
}
420+
if (smc->clcsock)
421+
release_clcsock = true;
407422
}
408423
}
409424
release_sock(sk);
425+
if (release_clcsock)
426+
smc_clcsock_release(smc);
410427
sock_put(sk); /* sock_hold done by schedulers of close_work */
411428
}
412429

net/smc/smc_close.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ void smc_close_wake_tx_prepared(struct smc_sock *smc);
2323
int smc_close_active(struct smc_sock *smc);
2424
int smc_close_shutdown_write(struct smc_sock *smc);
2525
void smc_close_init(struct smc_sock *smc);
26+
void smc_clcsock_release(struct smc_sock *smc);
2627

2728
#endif /* SMC_CLOSE_H */

0 commit comments

Comments
 (0)