Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/smc: Don't call clcsock shutdown twice when smc shutdown

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>

authored by

Tony Lu and committed by
Jakub Kicinski
bacb6c1e 01d9cc2d

+7 -1
+7 -1
net/smc/af_smc.c
··· 2370 2370 static int smc_shutdown(struct socket *sock, int how) 2371 2371 { 2372 2372 struct sock *sk = sock->sk; 2373 + bool do_shutdown = true; 2373 2374 struct smc_sock *smc; 2374 2375 int rc = -EINVAL; 2376 + int old_state; 2375 2377 int rc1 = 0; 2376 2378 2377 2379 smc = smc_sk(sk); ··· 2400 2398 } 2401 2399 switch (how) { 2402 2400 case SHUT_RDWR: /* shutdown in both directions */ 2401 + old_state = sk->sk_state; 2403 2402 rc = smc_close_active(smc); 2403 + if (old_state == SMC_ACTIVE && 2404 + sk->sk_state == SMC_PEERCLOSEWAIT1) 2405 + do_shutdown = false; 2404 2406 break; 2405 2407 case SHUT_WR: 2406 2408 rc = smc_close_shutdown_write(smc); ··· 2414 2408 /* nothing more to do because peer is not involved */ 2415 2409 break; 2416 2410 } 2417 - if (smc->clcsock) 2411 + if (do_shutdown && smc->clcsock) 2418 2412 rc1 = kernel_sock_shutdown(smc->clcsock, how); 2419 2413 /* map sock_shutdown_cmd constants to sk_shutdown value range */ 2420 2414 sk->sk_shutdown |= how + 1;