mirror of https://gitee.com/openkylin/linux.git
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 <kgraul@linux.ibm.com> Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
988dc4a9a3
commit
fd57770dd1
|
@ -167,10 +167,9 @@ static int smc_release(struct socket *sock)
|
|||
|
||||
if (sk->sk_state == SMC_CLOSED) {
|
||||
if (smc->clcsock) {
|
||||
mutex_lock(&smc->clcsock_release_lock);
|
||||
sock_release(smc->clcsock);
|
||||
smc->clcsock = NULL;
|
||||
mutex_unlock(&smc->clcsock_release_lock);
|
||||
release_sock(sk);
|
||||
smc_clcsock_release(smc);
|
||||
lock_sock(sk);
|
||||
}
|
||||
if (!smc->use_fallback)
|
||||
smc_conn_free(&smc->conn);
|
||||
|
@ -1037,13 +1036,13 @@ static void smc_listen_out(struct smc_sock *new_smc)
|
|||
struct smc_sock *lsmc = new_smc->listen_smc;
|
||||
struct sock *newsmcsk = &new_smc->sk;
|
||||
|
||||
lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
|
||||
if (lsmc->sk.sk_state == SMC_LISTEN) {
|
||||
lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
|
||||
smc_accept_enqueue(&lsmc->sk, newsmcsk);
|
||||
release_sock(&lsmc->sk);
|
||||
} else { /* no longer listening */
|
||||
smc_close_non_accepted(newsmcsk);
|
||||
}
|
||||
release_sock(&lsmc->sk);
|
||||
|
||||
/* Wake up accept */
|
||||
lsmc->sk.sk_data_ready(&lsmc->sk);
|
||||
|
@ -1237,6 +1236,9 @@ static void smc_listen_work(struct work_struct *work)
|
|||
int rc = 0;
|
||||
u8 ibport;
|
||||
|
||||
if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
|
||||
return smc_listen_out_err(new_smc);
|
||||
|
||||
if (new_smc->use_fallback) {
|
||||
smc_listen_out_connected(new_smc);
|
||||
return;
|
||||
|
|
|
@ -21,6 +21,22 @@
|
|||
|
||||
#define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ)
|
||||
|
||||
/* release the clcsock that is assigned to the smc_sock */
|
||||
void smc_clcsock_release(struct smc_sock *smc)
|
||||
{
|
||||
struct socket *tcp;
|
||||
|
||||
if (smc->listen_smc && current_work() != &smc->smc_listen_work)
|
||||
cancel_work_sync(&smc->smc_listen_work);
|
||||
mutex_lock(&smc->clcsock_release_lock);
|
||||
if (smc->clcsock) {
|
||||
tcp = smc->clcsock;
|
||||
smc->clcsock = NULL;
|
||||
sock_release(tcp);
|
||||
}
|
||||
mutex_unlock(&smc->clcsock_release_lock);
|
||||
}
|
||||
|
||||
static void smc_close_cleanup_listen(struct sock *parent)
|
||||
{
|
||||
struct sock *sk;
|
||||
|
@ -321,6 +337,7 @@ static void smc_close_passive_work(struct work_struct *work)
|
|||
close_work);
|
||||
struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
|
||||
struct smc_cdc_conn_state_flags *rxflags;
|
||||
bool release_clcsock = false;
|
||||
struct sock *sk = &smc->sk;
|
||||
int old_state;
|
||||
|
||||
|
@ -400,13 +417,13 @@ static void smc_close_passive_work(struct work_struct *work)
|
|||
if ((sk->sk_state == SMC_CLOSED) &&
|
||||
(sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) {
|
||||
smc_conn_free(conn);
|
||||
if (smc->clcsock) {
|
||||
sock_release(smc->clcsock);
|
||||
smc->clcsock = NULL;
|
||||
}
|
||||
if (smc->clcsock)
|
||||
release_clcsock = true;
|
||||
}
|
||||
}
|
||||
release_sock(sk);
|
||||
if (release_clcsock)
|
||||
smc_clcsock_release(smc);
|
||||
sock_put(sk); /* sock_hold done by schedulers of close_work */
|
||||
}
|
||||
|
||||
|
|
|
@ -23,5 +23,6 @@ void smc_close_wake_tx_prepared(struct smc_sock *smc);
|
|||
int smc_close_active(struct smc_sock *smc);
|
||||
int smc_close_shutdown_write(struct smc_sock *smc);
|
||||
void smc_close_init(struct smc_sock *smc);
|
||||
void smc_clcsock_release(struct smc_sock *smc);
|
||||
|
||||
#endif /* SMC_CLOSE_H */
|
||||
|
|
Loading…
Reference in New Issue