net/smc: fix dangling sock under state SMC_APPFINCLOSEWAIT
[ Upstream commit 5211c9729484c923f8d2e06bd29f9322cc42bb8f ]
Considering scenario:
smc_cdc_rx_handler
__smc_release
sock_set_flag
smc_close_active()
sock_set_flag
__set_bit(DEAD) __set_bit(DONE)
Dues to __set_bit is not atomic, the DEAD or DONE might be lost.
if the DEAD flag lost, the state SMC_CLOSED will be never be reached
in smc_close_passive_work:
if (sock_flag(sk, SOCK_DEAD) &&
smc_close_sent_any_close(conn)) {
sk->sk_state = SMC_CLOSED;
} else {
/* just shutdown, but not yet closed locally */
sk->sk_state = SMC_APPFINCLOSEWAIT;
}
Replace sock_set_flags or __set_bit to set_bit will fix this problem.
Since set_bit is atomic.
Fixes: b38d732477
("smc: socket closing and linkgroup cleanup")
Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
592f934b7a
commit
f8065cde49
@ -136,7 +136,7 @@ static int __smc_release(struct smc_sock *smc)
|
||||
|
||||
if (!smc->use_fallback) {
|
||||
rc = smc_close_active(smc);
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
smc_sock_set_flag(sk, SOCK_DEAD);
|
||||
sk->sk_shutdown |= SHUTDOWN_MASK;
|
||||
} else {
|
||||
if (sk->sk_state != SMC_CLOSED) {
|
||||
@ -928,7 +928,7 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
|
||||
if (new_clcsock)
|
||||
sock_release(new_clcsock);
|
||||
new_sk->sk_state = SMC_CLOSED;
|
||||
sock_set_flag(new_sk, SOCK_DEAD);
|
||||
smc_sock_set_flag(new_sk, SOCK_DEAD);
|
||||
sock_put(new_sk); /* final */
|
||||
*new_smc = NULL;
|
||||
goto out;
|
||||
|
@ -265,4 +265,9 @@ static inline bool using_ipsec(struct smc_sock *smc)
|
||||
struct sock *smc_accept_dequeue(struct sock *parent, struct socket *new_sock);
|
||||
void smc_close_non_accepted(struct sock *sk);
|
||||
|
||||
static inline void smc_sock_set_flag(struct sock *sk, enum sock_flags flag)
|
||||
{
|
||||
set_bit(flag, &sk->sk_flags);
|
||||
}
|
||||
|
||||
#endif /* __SMC_H */
|
||||
|
@ -298,7 +298,7 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
|
||||
smc->sk.sk_shutdown |= RCV_SHUTDOWN;
|
||||
if (smc->clcsock && smc->clcsock->sk)
|
||||
smc->clcsock->sk->sk_shutdown |= RCV_SHUTDOWN;
|
||||
sock_set_flag(&smc->sk, SOCK_DONE);
|
||||
smc_sock_set_flag(&smc->sk, SOCK_DONE);
|
||||
sock_hold(&smc->sk); /* sock_put in close_work */
|
||||
if (!schedule_work(&conn->close_work))
|
||||
sock_put(&smc->sk);
|
||||
|
@ -164,7 +164,7 @@ static void smc_close_active_abort(struct smc_sock *smc)
|
||||
break;
|
||||
}
|
||||
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
smc_sock_set_flag(sk, SOCK_DEAD);
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user