diff options
author | Tony Lu <tonylu@linux.alibaba.com> | 2021-11-26 10:41:35 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-12-01 09:27:43 +0100 |
commit | 7d0354c9a1736593fc2d32d26ae898dfc3089c87 (patch) | |
tree | b73169b6d60d5de45808be4122f135d32fcdeb45 | |
parent | fd25bc47e641970cb365f5fd80915e20646d0ae7 (diff) | |
download | linux-stable-7d0354c9a1736593fc2d32d26ae898dfc3089c87.tar.gz linux-stable-7d0354c9a1736593fc2d32d26ae898dfc3089c87.tar.bz2 linux-stable-7d0354c9a1736593fc2d32d26ae898dfc3089c87.zip |
net/smc: Don't call clcsock shutdown twice when smc shutdown
[ Upstream commit bacb6c1e47691cda4a95056c21b5487fb7199fcc ]
When applications call shutdown() with SHUT_RDWR in userspace,
smc_close_active() calls kernel_sock_shutdown(), and it is called
twice in smc_shutdown().
This fixes this by checking sk_state before do clcsock shutdown, and
avoids missing the application's call of smc_shutdown().
Link: https://lore.kernel.org/linux-s390/1f67548e-cbf6-0dce-82b5-10288a4583bd@linux.ibm.com/
Fixes: 606a63c9783a ("net/smc: Ensure the active closing peer first closes clcsock")
Signed-off-by: Tony Lu <tonylu@linux.alibaba.com>
Reviewed-by: Wen Gu <guwen@linux.alibaba.com>
Acked-by: Karsten Graul <kgraul@linux.ibm.com>
Link: https://lore.kernel.org/r/20211126024134.45693-1-tonylu@linux.alibaba.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | net/smc/af_smc.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 9aab4ab8161b..4c904ab29e0e 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1589,8 +1589,10 @@ static __poll_t smc_poll(struct file *file, struct socket *sock, static int smc_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + bool do_shutdown = true; struct smc_sock *smc; int rc = -EINVAL; + int old_state; int rc1 = 0; smc = smc_sk(sk); @@ -1617,7 +1619,11 @@ static int smc_shutdown(struct socket *sock, int how) } switch (how) { case SHUT_RDWR: /* shutdown in both directions */ + old_state = sk->sk_state; rc = smc_close_active(smc); + if (old_state == SMC_ACTIVE && + sk->sk_state == SMC_PEERCLOSEWAIT1) + do_shutdown = false; break; case SHUT_WR: rc = smc_close_shutdown_write(smc); @@ -1627,7 +1633,7 @@ static int smc_shutdown(struct socket *sock, int how) /* nothing more to do because peer is not involved */ break; } - if (smc->clcsock) + if (do_shutdown && smc->clcsock) rc1 = kernel_sock_shutdown(smc->clcsock, how); /* map sock_shutdown_cmd constants to sk_shutdown value range */ sk->sk_shutdown |= how + 1; |