]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cifs: Fix negotiate retry functionality
authorPali Rohár <pali@kernel.org>
Sat, 2 Nov 2024 19:06:50 +0000 (20:06 +0100)
committerSteve French <stfrench@microsoft.com>
Tue, 1 Apr 2025 06:54:17 +0000 (01:54 -0500)
SMB negotiate retry functionality in cifs_negotiate() is currently broken
and does not work when doing socket reconnect. Caller of this function,
which is cifs_negotiate_protocol() requires that tcpStatus after successful
execution of negotiate callback stay in CifsInNegotiate. But if the
CIFSSMBNegotiate() called from cifs_negotiate() fails due to connection
issues then tcpStatus is changed as so repeated CIFSSMBNegotiate() call
does not help.

Fix this problem by moving retrying code from negotiate callback (which is
either cifs_negotiate() or smb2_negotiate()) to cifs_negotiate_protocol()
which is caller of those callbacks. This allows to properly handle and
implement correct transistions between tcpStatus states as function
cifs_negotiate_protocol() already handles it.

With this change, cifs_negotiate_protocol() now handles also -EAGAIN error
set by the RFC1002_NEGATIVE_SESSION_RESPONSE processing after reconnecting
with NetBIOS session.

Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/connect.c
fs/smb/client/smb1ops.c
fs/smb/client/smb2ops.c

index 69274d6ed2e12b0f43d97b74b93def7a27fa92af..f298e86a3c1fdb7b1143e8755a49d234e8f0874a 100644 (file)
@@ -4202,11 +4202,13 @@ int
 cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
                        struct TCP_Server_Info *server)
 {
+       bool in_retry = false;
        int rc = 0;
 
        if (!server->ops->need_neg || !server->ops->negotiate)
                return -ENOSYS;
 
+retry:
        /* only send once per connect */
        spin_lock(&server->srv_lock);
        if (server->tcpStatus != CifsGood &&
@@ -4226,6 +4228,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
        spin_unlock(&server->srv_lock);
 
        rc = server->ops->negotiate(xid, ses, server);
+       if (rc == -EAGAIN) {
+               /* Allow one retry attempt */
+               if (!in_retry) {
+                       in_retry = true;
+                       goto retry;
+               }
+               rc = -EHOSTDOWN;
+       }
        if (rc == 0) {
                spin_lock(&server->srv_lock);
                if (server->tcpStatus == CifsInNegotiate)
index 06b28da60a2d450b1960a575935c29f9c8a02618..ad89f60207ab714d2f5bbf0cdeeb96b599e39035 100644 (file)
@@ -426,13 +426,6 @@ cifs_negotiate(const unsigned int xid,
 {
        int rc;
        rc = CIFSSMBNegotiate(xid, ses, server);
-       if (rc == -EAGAIN) {
-               /* retry only once on 1st time connection */
-               set_credits(server, 1);
-               rc = CIFSSMBNegotiate(xid, ses, server);
-               if (rc == -EAGAIN)
-                       rc = -EHOSTDOWN;
-       }
        return rc;
 }
 
index 98643a546c680395328427c7b51c07f50343e052..374d65cc8123ac43a344f4f7c3e48340bad39a04 100644 (file)
@@ -464,9 +464,6 @@ smb2_negotiate(const unsigned int xid,
        server->CurrentMid = 0;
        spin_unlock(&server->mid_lock);
        rc = SMB2_negotiate(xid, ses, server);
-       /* BB we probably don't need to retry with modern servers */
-       if (rc == -EAGAIN)
-               rc = -EHOSTDOWN;
        return rc;
 }