From 9c36d4d5633a33172c964e4589f7a438e695192b Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 29 Apr 2025 10:38:05 +0800 Subject: [PATCH 1/3] net/smc: propagate file from SMC to TCP socket mainline inclusion from mainline-v5.1-rc6 commit 07603b230895a74ebb1e2a1231ac45c29c2a8cd3 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC4DSN Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=07603b230895a74ebb1e2a1231ac45c29c2a8cd3 -------------------------------- fcntl(fd, F_SETOWN, getpid()) selects the recipient of SIGURG signals that are delivered when out-of-band data arrives on socket fd. If an SMC socket program makes use of such an fcntl() call, it fails in case of fallback to TCP-mode. In case of fallback the traffic is processed with the internal TCP socket. Propagating field "file" from the SMC socket to the internal TCP socket fixes the issue. Reviewed-by: Karsten Graul Signed-off-by: Ursula Braun Signed-off-by: David S. Miller Signed-off-by: Wang Liang --- include/net/sock.h | 6 ------ net/smc/af_smc.c | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index cdb991e633cf2..1840303a5539b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2172,12 +2172,6 @@ static inline bool skwq_has_sleeper(struct socket_wq *wq) * @p: poll_table * * See the comments in the wq_has_sleeper function. - * - * Do not derive sock from filp->private_data here. An SMC socket establishes - * an internal TCP socket that is used in the fallback case. All socket - * operations on the SMC socket are then forwarded to the TCP socket. In case of - * poll, the filp->private_data pointer references the SMC socket because the - * TCP socket has no file assigned. */ static inline void sock_poll_wait(struct file *filp, struct socket *sock, poll_table *p) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 26dcd02b2d0ce..13b9f4cfb45af 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -432,10 +432,19 @@ static void smc_link_save_peer_info(struct smc_link *link, link->peer_mtu = clc->qp_mtu; } +static void smc_switch_to_fallback(struct smc_sock *smc) +{ + smc->use_fallback = true; + if (smc->sk.sk_socket && smc->sk.sk_socket->file) { + smc->clcsock->file = smc->sk.sk_socket->file; + smc->clcsock->file->private_data = smc->clcsock; + } +} + /* fall back during connect */ static int smc_connect_fallback(struct smc_sock *smc, int reason_code) { - smc->use_fallback = true; + smc_switch_to_fallback(smc); smc->fallback_rsn = reason_code; smc_copy_sock_settings_to_clc(smc); if (smc->sk.sk_state == SMC_INIT) @@ -751,10 +760,14 @@ static void smc_connect_work(struct work_struct *work) smc->sk.sk_err = -rc; out: - if (smc->sk.sk_err) - smc->sk.sk_state_change(&smc->sk); - else - smc->sk.sk_write_space(&smc->sk); + if (!sock_flag(&smc->sk, SOCK_DEAD)) { + if (smc->sk.sk_err) { + smc->sk.sk_state_change(&smc->sk); + } else { /* allow polling before and after fallback decision */ + smc->clcsock->sk->sk_write_space(smc->clcsock->sk); + smc->sk.sk_write_space(&smc->sk); + } + } kfree(smc->connect_info); smc->connect_info = NULL; release_sock(&smc->sk); @@ -911,8 +924,13 @@ struct sock *smc_accept_dequeue(struct sock *parent, sock_put(new_sk); /* final */ continue; } - if (new_sock) + if (new_sock) { sock_graft(new_sk, new_sock); + if (isk->use_fallback) { + smc_sk(new_sk)->clcsock->file = new_sock->file; + isk->clcsock->file->private_data = isk->clcsock; + } + } return new_sk; } return NULL; @@ -1063,7 +1081,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code, return; } smc_conn_free(&new_smc->conn); - new_smc->use_fallback = true; + smc_switch_to_fallback(new_smc); new_smc->fallback_rsn = reason_code; if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) { if (smc_clc_send_decline(new_smc, reason_code) < 0) { @@ -1223,7 +1241,7 @@ static void smc_listen_work(struct work_struct *work) /* check if peer is smc capable */ if (!tcp_sk(newclcsock->sk)->syn_smc) { - new_smc->use_fallback = true; + smc_switch_to_fallback(new_smc); new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC; smc_listen_out_connected(new_smc); return; @@ -1475,7 +1493,7 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (msg->msg_flags & MSG_FASTOPEN) { if (sk->sk_state == SMC_INIT) { - smc->use_fallback = true; + smc_switch_to_fallback(smc); smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; } else { rc = -EINVAL; @@ -1672,7 +1690,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, case TCP_FASTOPEN_NO_COOKIE: /* option not supported by SMC */ if (sk->sk_state == SMC_INIT) { - smc->use_fallback = true; + smc_switch_to_fallback(smc); smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; } else { if (!smc->use_fallback) -- Gitee From 900973c88183f941dc7fb9438916ef516f4e1d1b Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 29 Apr 2025 10:38:06 +0800 Subject: [PATCH 2/3] net/smc: fix closing of fallback SMC sockets mainline inclusion from mainline-v5.4-rc6 commit f536dffc0b79738c3104af999318279dccbaa261 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC4DSN Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f536dffc0b79738c3104af999318279dccbaa261 -------------------------------- For SMC sockets forced to fallback to TCP, the file is propagated from the outer SMC to the internal TCP socket. When closing the SMC socket, the internal TCP socket file pointer must be restored to the original NULL value, otherwise memory leaks may show up (found with CONFIG_DEBUG_KMEMLEAK). The internal TCP socket is released in smc_clcsock_release(), which calls __sock_release() function in net/socket.c. This calls the needed iput(SOCK_INODE(sock)) only, if the file pointer has been reset to the original NULL-value. Fixes: 07603b230895 ("net/smc: propagate file from SMC to TCP socket") Signed-off-by: Ursula Braun Signed-off-by: Karsten Graul Signed-off-by: David S. Miller Conflicts: net/smc/af_smc.c [conflicts due to not merge 39f41f367b08 ("net/smc: common release code for non-accepted sockets")] Signed-off-by: Wang Liang --- net/smc/af_smc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 13b9f4cfb45af..e10ec8564fe00 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -115,6 +115,12 @@ struct proto smc_proto6 = { }; EXPORT_SYMBOL_GPL(smc_proto6); +static void smc_restore_fallback_changes(struct smc_sock *smc) +{ + smc->clcsock->file->private_data = smc->sk.sk_socket; + smc->clcsock->file = NULL; +} + static int smc_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -162,6 +168,7 @@ static int smc_release(struct socket *sock) sock_put(sk); /* passive closing */ sk->sk_state = SMC_CLOSED; sk->sk_state_change(sk); + smc_restore_fallback_changes(smc); } /* detach socket */ -- Gitee From bf1b52e4bb0aeb262dcefbf65c4cec69bbee98a7 Mon Sep 17 00:00:00 2001 From: Karsten Graul Date: Tue, 29 Apr 2025 10:38:07 +0800 Subject: [PATCH 3/3] net/smc: fix restoring of fallback changes mainline inclusion from mainline-v5.8-rc7 commit 1ad24058335427d046b2e5666bcd15a62ad9e242 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC4DSN Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1ad24058335427d046b2e5666bcd15a62ad9e242 -------------------------------- When a listen socket is closed then all non-accepted sockets in its accept queue are to be released. Inside __smc_release() the helper smc_restore_fallback_changes() restores the changes done to the socket without to check if the clcsocket has a file set. This can result in a crash. Fix this by checking the file pointer first. Reviewed-by: Ursula Braun Fixes: f536dffc0b79 ("net/smc: fix closing of fallback SMC sockets") Signed-off-by: Karsten Graul Signed-off-by: David S. Miller Signed-off-by: Wang Liang --- net/smc/af_smc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index e10ec8564fe00..754ec7d24a4f6 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -117,8 +117,10 @@ EXPORT_SYMBOL_GPL(smc_proto6); static void smc_restore_fallback_changes(struct smc_sock *smc) { - smc->clcsock->file->private_data = smc->sk.sk_socket; - smc->clcsock->file = NULL; + if (smc->clcsock->file) { /* non-accepted sockets have no file yet */ + smc->clcsock->file->private_data = smc->sk.sk_socket; + smc->clcsock->file = NULL; + } } static int smc_release(struct socket *sock) -- Gitee