]> git.hungrycats.org Git - linux/commitdiff
cifs: do all necessary checks for credits within or before locking
authorShyam Prasad N <sprasad@microsoft.com>
Thu, 22 Jun 2023 18:16:04 +0000 (18:16 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Jul 2023 17:39:51 +0000 (19:39 +0200)
[ Upstream commit 326a8d04f147e2bf393f6f9cdb74126ee6900607 ]

All the server credits and in-flight info is protected by req_lock.
Once the req_lock is held, and we've determined that we have enough
credits to continue, this lock cannot be dropped till we've made the
changes to credits and in-flight count.

However, we used to drop the lock in order to avoid deadlock with
the recent srv_lock. This could cause the checks already made to be
invalidated.

Fixed it by moving the server status check to before locking req_lock.

Fixes: d7d7a66aacd6 ("cifs: avoid use of global locks for high contention data")
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/cifs/smb2ops.c
fs/cifs/transport.c

index 5065398665f115359e754054041c19c00f02b7e5..bb41b9bae262dff802bd82158c26d9bb98b8f747 100644 (file)
@@ -208,6 +208,16 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
 
        spin_lock(&server->req_lock);
        while (1) {
+               spin_unlock(&server->req_lock);
+
+               spin_lock(&server->srv_lock);
+               if (server->tcpStatus == CifsExiting) {
+                       spin_unlock(&server->srv_lock);
+                       return -ENOENT;
+               }
+               spin_unlock(&server->srv_lock);
+
+               spin_lock(&server->req_lock);
                if (server->credits <= 0) {
                        spin_unlock(&server->req_lock);
                        cifs_num_waiters_inc(server);
@@ -218,15 +228,6 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
                                return rc;
                        spin_lock(&server->req_lock);
                } else {
-                       spin_unlock(&server->req_lock);
-                       spin_lock(&server->srv_lock);
-                       if (server->tcpStatus == CifsExiting) {
-                               spin_unlock(&server->srv_lock);
-                               return -ENOENT;
-                       }
-                       spin_unlock(&server->srv_lock);
-
-                       spin_lock(&server->req_lock);
                        scredits = server->credits;
                        /* can deadlock with reopen */
                        if (scredits <= 8) {
index 24bdd5f4d3bcc725a9763266270a790f03d00a49..968bfd029b8eb44bde01632533c43410c35d35ab 100644 (file)
@@ -522,6 +522,16 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
        }
 
        while (1) {
+               spin_unlock(&server->req_lock);
+
+               spin_lock(&server->srv_lock);
+               if (server->tcpStatus == CifsExiting) {
+                       spin_unlock(&server->srv_lock);
+                       return -ENOENT;
+               }
+               spin_unlock(&server->srv_lock);
+
+               spin_lock(&server->req_lock);
                if (*credits < num_credits) {
                        scredits = *credits;
                        spin_unlock(&server->req_lock);
@@ -547,15 +557,6 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
                                return -ERESTARTSYS;
                        spin_lock(&server->req_lock);
                } else {
-                       spin_unlock(&server->req_lock);
-
-                       spin_lock(&server->srv_lock);
-                       if (server->tcpStatus == CifsExiting) {
-                               spin_unlock(&server->srv_lock);
-                               return -ENOENT;
-                       }
-                       spin_unlock(&server->srv_lock);
-
                        /*
                         * For normal commands, reserve the last MAX_COMPOUND
                         * credits to compound requests.
@@ -569,7 +570,6 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
                         * for servers that are slow to hand out credits on
                         * new sessions.
                         */
-                       spin_lock(&server->req_lock);
                        if (!optype && num_credits == 1 &&
                            server->in_flight > 2 * MAX_COMPOUND &&
                            *credits <= MAX_COMPOUND) {