[PATCH v4 013/145] smb: smbdirect: introduce smbdirect_socket_cleanup_work()
Stefan Metzmacher
metze at samba.org
Tue Nov 25 17:54:19 UTC 2025
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 <smfrench at gmail.com>
Cc: Tom Talpey <tom at talpey.com>
Cc: Long Li <longli at microsoft.com>
Cc: Namjae Jeon <linkinjeon at kernel.org>
Cc: linux-cifs at vger.kernel.org
Cc: samba-technical at lists.samba.org
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Steve French <stfrench at microsoft.com>
---
fs/smb/common/smbdirect/smbdirect_socket.c | 90 +++++++++++++++++++++-
1 file changed, 89 insertions(+), 1 deletion(-)
diff --git a/fs/smb/common/smbdirect/smbdirect_socket.c b/fs/smb/common/smbdirect/smbdirect_socket.c
index a249e758379f..2688866fffe6 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)
{
/*
@@ -62,3 +65,88 @@ 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);
+ struct smbdirect_recv_io *recv_io, *recv_tmp;
+ unsigned long flags;
+
+ /*
+ * 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->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);
+
+ /*
+ * If any complex work was scheduled we
+ * should disable it (only happens during
+ * negotiation)...
+ *
+ * Note that sc->first_error is set before,
+ * so any future smbdirect_connection_get_recv_io()
+ * will see it and return NULL.
+ */
+ spin_lock_irqsave(&sc->recv_io.free.lock, flags);
+ list_for_each_entry_safe(recv_io, recv_tmp, &sc->recv_io.free.list, list)
+ disable_work(&recv_io->complex_work);
+ spin_unlock_irqrestore(&sc->recv_io.free.lock, flags);
+
+ 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);
+}
--
2.43.0
More information about the samba-technical
mailing list