summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2019-01-31 01:58:09 +0100
committerSteve French <stfrench@microsoft.com>2019-03-06 01:10:04 +0100
commit7091bcaba9f34c83e1e6f418b6de5c6d987571da (patch)
tree44efa04e6ea14bb7f6eec84495cbda05f9ee0bc8 /fs/cifs
parentCIFS: Return error code when getting file handle for writeback (diff)
downloadlinux-7091bcaba9f34c83e1e6f418b6de5c6d987571da.tar.xz
linux-7091bcaba9f34c83e1e6f418b6de5c6d987571da.zip
CIFS: Try to acquire credits at once for compound requests
Currently we get one credit per compound part of the request individually. This may lead to being stuck on waiting for credits if multiple compounded operations happen in parallel. Try acquire credits for all compound parts at once. Return immediately if not enough credits and too few requests are in flight currently thus narrowing the possibility of infinite waiting for credits. The more advance fix is to return right away if not enough credits for the compound request and do not look at the number of requests in flight. The caller should handle such situations by falling back to sequential execution of SMB commands instead of compounding. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/transport.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 2045f886546c..9c3a6809194c 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -860,13 +860,41 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
if (ses->server->tcpStatus == CifsExiting)
return -ENOENT;
+ spin_lock(&ses->server->req_lock);
+ if (ses->server->credits < num_rqst) {
+ /*
+ * Return immediately if not too many requests in flight since
+ * we will likely be stuck on waiting for credits.
+ */
+ if (ses->server->in_flight < num_rqst - ses->server->credits) {
+ spin_unlock(&ses->server->req_lock);
+ return -ENOTSUPP;
+ }
+ } else {
+ /* enough credits to send the whole compounded request */
+ ses->server->credits -= num_rqst;
+ ses->server->in_flight += num_rqst;
+ first_instance = ses->server->reconnect_instance;
+ }
+ spin_unlock(&ses->server->req_lock);
+
+ if (first_instance) {
+ cifs_dbg(FYI, "Acquired %d credits at once\n", num_rqst);
+ for (i = 0; i < num_rqst; i++) {
+ credits[i].value = 1;
+ credits[i].instance = first_instance;
+ }
+ goto setup_rqsts;
+ }
+
/*
+ * There are not enough credits to send the whole compound request but
+ * there are requests in flight that may bring credits from the server.
+ * This approach still leaves the possibility to be stuck waiting for
+ * credits if the server doesn't grant credits to the outstanding
+ * requests. This should be fixed by returning immediately and letting
+ * a caller fallback to sequential commands instead of compounding.
* Ensure we obtain 1 credit per request in the compound chain.
- * It can be optimized further by waiting for all the credits
- * at once but this can wait long enough if we don't have enough
- * credits due to some heavy operations in progress or the server
- * not granting us much, so a fallback to the current approach is
- * needed anyway.
*/
for (i = 0; i < num_rqst; i++) {
rc = wait_for_free_request(ses->server, timeout, optype,
@@ -906,6 +934,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
}
}
+setup_rqsts:
/*
* Make sure that we sign in the same order that we send on this socket
* and avoid races inside tcp sendmsg code that could cause corruption