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@xxxxxxxxxxxxx> --- fs/smb/client/cifsglob.h | 13 +++++++++++++ fs/smb/client/transport.c | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) 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) { -- 2.40.1