diff mbox series

[2/3] cifs: stop waiting for credits if there are no more requests in flight

Message ID 20230629085858.2834937-2-wentao@uniontech.com (mailing list archive)
State New, archived
Headers show
Series [1/3] cifs: fix credit leaks in async callback | expand

Commit Message

Winston Wen June 29, 2023, 8:58 a.m. UTC
A compound request will wait for credits if free credits are not enough
now but there are in flight requests which might bring back some credits
to meet our needs in the near future.

But if the in-flight requests don't bring back enough credits, the
compound request will continue to wait unnecessarily until it times out
(60s now).

So add a helper has_credits_or_insufficient() to check if we should stop
waiting for credits in the loop to return faster.

Signed-off-by: Winston Wen <wentao@uniontech.com>
---
 fs/smb/client/cifsglob.h  | 13 +++++++++++++
 fs/smb/client/transport.c | 16 +++++++++++++---
 2 files changed, 26 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index cb38c29b9a73..43d0a675b543 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -800,6 +800,19 @@  has_credits(struct TCP_Server_Info *server, int *credits, int num_credits)
 	return num >= num_credits;
 }
 
+static inline bool
+has_credits_or_insufficient(struct TCP_Server_Info *server, int *credits, int num_credits)
+{
+	int scredits;
+	int in_flight;
+
+	spin_lock(&server->req_lock);
+	scredits = *credits;
+	in_flight = server->in_flight;
+	spin_unlock(&server->req_lock);
+	return scredits >= num_credits || in_flight == 0;
+}
+
 static inline void
 add_credits(struct TCP_Server_Info *server, const struct cifs_credits *credits,
 	    const int optype)
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index f280502a2aee..82071142d72b 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -534,11 +534,21 @@  wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
 		spin_lock(&server->req_lock);
 		if (*credits < num_credits) {
 			scredits = *credits;
+			in_flight = server->in_flight;
+			if (in_flight == 0) {
+				spin_unlock(&server->req_lock);
+				trace_smb3_insufficient_credits(server->CurrentMid,
+						server->conn_id, server->hostname, scredits,
+						num_credits, in_flight);
+				cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n",
+						__func__, in_flight, num_credits, scredits);
+				return -EDEADLK;
+			}
 			spin_unlock(&server->req_lock);
 
 			cifs_num_waiters_inc(server);
 			rc = wait_event_killable_timeout(server->request_q,
-				has_credits(server, credits, num_credits), t);
+				has_credits_or_insufficient(server, credits, num_credits), t);
 			cifs_num_waiters_dec(server);
 			if (!rc) {
 				spin_lock(&server->req_lock);
@@ -578,8 +588,8 @@  wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
 				cifs_num_waiters_inc(server);
 				rc = wait_event_killable_timeout(
 					server->request_q,
-					has_credits(server, credits,
-						    MAX_COMPOUND + 1),
+					has_credits_or_insufficient(server, credits,
+								MAX_COMPOUND + 1),
 					t);
 				cifs_num_waiters_dec(server);
 				if (!rc) {