]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: make sure smbd_disconnect_rdma_work() doesn't run after smbd_destroy...
authorStefan Metzmacher <metze@samba.org>
Tue, 12 Aug 2025 07:10:07 +0000 (09:10 +0200)
committerSteve French <stfrench@microsoft.com>
Sun, 28 Sep 2025 23:29:49 +0000 (18:29 -0500)
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 <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smbdirect.c

index a4508f8b7499cc0d6f29f60cfd1e3a239a55af8f..44140fb5f2ad322ff27d7dee376425a0c4f95aff 100644 (file)
@@ -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,