From: Stefan Metzmacher Date: Tue, 26 Aug 2025 14:01:15 +0000 (+0200) Subject: smb: smbdirect: introduce smbdirect_socket_cleanup_work() X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=1be83fad0c74b288d3664ff0677da19a997bcbf3;p=thirdparty%2Fkernel%2Flinux.git smb: smbdirect: introduce smbdirect_socket_cleanup_work() This is basically a copy of smbd_disconnect_rdma_work() and smb_direct_disconnect_rdma_work() and will replace them in the next steps. Differences is that a message is logged if first error is still 0, which makes it easier to analyze problems. And also disable any complex work from recv_io objects, currently these are not used and the work is always disabled anyway, but this prepares future changes. It also makes sure it's never used in an interrupt, which is not expected anyway... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- diff --git a/fs/smb/common/smbdirect/smbdirect_socket.c b/fs/smb/common/smbdirect/smbdirect_socket.c index 30a4e973ce775..a851b874b8193 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.c +++ b/fs/smb/common/smbdirect/smbdirect_socket.c @@ -6,6 +6,8 @@ #include "smbdirect_internal.h" +static void smbdirect_socket_cleanup_work(struct work_struct *work); + __maybe_unused /* this is temporary while this file is included in others */ static void smbdirect_socket_prepare_create(struct smbdirect_socket *sc, const struct smbdirect_socket_parameters *sp, @@ -23,6 +25,8 @@ static void smbdirect_socket_prepare_create(struct smbdirect_socket *sc, * Remember the callers workqueue */ sc->workqueue = workqueue; + + INIT_WORK(&sc->disconnect_work, smbdirect_socket_cleanup_work); } __maybe_unused /* this is temporary while this file is included in others */ @@ -45,7 +49,6 @@ static void smbdirect_socket_set_logging(struct smbdirect_socket *sc, sc->logging.vaprintf = vaprintf; } -__maybe_unused /* this is temporary while this file is included in others */ static void smbdirect_socket_wake_up_all(struct smbdirect_socket *sc) { /* @@ -63,3 +66,73 @@ static void smbdirect_socket_wake_up_all(struct smbdirect_socket *sc) wake_up_all(&sc->mr_io.ready.wait_queue); wake_up_all(&sc->mr_io.cleanup.wait_queue); } + +static void smbdirect_socket_cleanup_work(struct work_struct *work) +{ + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, disconnect_work); + + /* + * This should not never be called in an interrupt! + */ + WARN_ON_ONCE(in_interrupt()); + + if (!sc->first_error) { + smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_ERR, + "%s called with first_error==0\n", + smbdirect_socket_status_string(sc->status)); + + sc->first_error = -ECONNABORTED; + } + + /* + * make sure this and other work is not queued again + * but here we don't block and avoid + * disable[_delayed]_work_sync() + */ + disable_work(&sc->disconnect_work); + disable_work(&sc->connect.work); + disable_work(&sc->recv_io.posted.refill_work); + disable_work(&sc->mr_io.recovery_work); + disable_work(&sc->idle.immediate_work); + disable_delayed_work(&sc->idle.timer_work); + + switch (sc->status) { + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + case SMBDIRECT_SOCKET_CONNECTED: + case SMBDIRECT_SOCKET_ERROR: + sc->status = SMBDIRECT_SOCKET_DISCONNECTING; + rdma_disconnect(sc->rdma.cm_id); + break; + + case SMBDIRECT_SOCKET_CREATED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + /* + * rdma_{accept,connect}() never reached + * RDMA_CM_EVENT_ESTABLISHED + */ + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + break; + + case SMBDIRECT_SOCKET_DISCONNECTING: + case SMBDIRECT_SOCKET_DISCONNECTED: + case SMBDIRECT_SOCKET_DESTROYED: + break; + } + + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + smbdirect_socket_wake_up_all(sc); +}