From b0aa92a229ab9e6de3839e06f3a8494bce5b1cd2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 09:10:07 +0200 Subject: [PATCH] smb: client: make sure smbd_disconnect_rdma_work() doesn't run after smbd_destroy() took over If we're already disconnecting we don't need to queue the disconnect_work again. disable_work() turns the next queue_work() into a no-op. Also let smbd_destroy() cancel(and disable) queued disconnect_work and call smbd_disconnect_rdma_work() inline. The makes it more obvious that disconnect_work is never queued again after smbd_destroy() called smbd_disconnect_rdma_work(). It also means we have a single place to call rdma_disconnect(). While there we better also disable all other [delayed_]work. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index a4508f8b7499..44140fb5f2ad 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -159,6 +159,18 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); + + /* + * 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(&info->post_send_credits_work); + disable_work(&info->mr_recovery_work); + disable_delayed_work(&info->idle_timer_work); switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: @@ -342,11 +354,13 @@ static int smbd_conn_upcall( if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { log_rdma_event(ERR, "event=%s during negotiation\n", event_name); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + smbd_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); break; } sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + smbd_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); wake_up_all(&sc->send_io.credits.wait_queue); @@ -1483,9 +1497,12 @@ void smbd_destroy(struct TCP_Server_Info *server) sc = &info->socket; sp = &sc->parameters; + log_rdma_event(INFO, "cancelling and disable disconnect_work\n"); + disable_work_sync(&sc->disconnect_work); + log_rdma_event(INFO, "destroying rdma session\n"); - if (sc->status != SMBDIRECT_SOCKET_DISCONNECTED) { - rdma_disconnect(sc->rdma.cm_id); + if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) { + smbd_disconnect_rdma_work(&sc->disconnect_work); log_rdma_event(INFO, "wait for transport being disconnected\n"); wait_event_interruptible( sc->status_wait, -- 2.20.1