All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ronnie Sahlberg <lsahlber@redhat.com>
To: linux-cifs <linux-cifs@vger.kernel.org>
Cc: Steve French <smfrench@gmail.com>,
	Pavel Shilovsky <pshilov@microsoft.com>,
	Ronnie Sahlberg <lsahlber@redhat.com>
Subject: [PATCH 6/6] cifs: simplify how we handle credits in compond_send_recv()
Date: Fri,  8 Mar 2019 12:58:23 +1000	[thread overview]
Message-ID: <20190308025823.24382-7-lsahlber@redhat.com> (raw)
In-Reply-To: <20190308025823.24382-1-lsahlber@redhat.com>

Since we can now wait for multiple requests atomically in
wait_for_free_request() we can now greatly simplify the handling
of the credits in this function.

This fixes a potential deadlock where many concurrent compound requests
could each have reserved 1 or 2 credits each but are all blocked
waiting for the final credits they need to be able to issue the requests
to the server.

Set a default timeout of 60 seconds for compounded requests.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 fs/cifs/transport.c | 106 +++++++++++++++++-----------------------------------
 1 file changed, 34 insertions(+), 72 deletions(-)

diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 62c58ce80123..3e30b6f9d7c6 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -592,6 +592,27 @@ wait_for_free_request(struct TCP_Server_Info *server, const int flags,
 				     instance);
 }
 
+static int
+wait_for_compound_request(struct TCP_Server_Info *server, int num,
+			  const int flags, unsigned int *instance)
+{
+	spin_lock(&server->req_lock);
+	if (server->credits < num) {
+		/*
+		 * Return immediately if not too many requests in flight since
+		 * we will likely be stuck on waiting for credits.
+		 */
+		if (server->in_flight < num - server->credits) {
+			spin_unlock(&server->req_lock);
+			return -ENOTSUPP;
+		}
+	}
+	spin_unlock(&server->req_lock);
+
+	return wait_for_free_credits(server, num, 60000, flags,
+				     instance);
+}
+
 int
 cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
 		      unsigned int *num, struct cifs_credits *credits)
@@ -920,7 +941,6 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		{ .value = 0, .instance = 0 }
 	};
 	unsigned int instance;
-	unsigned int first_instance = 0;
 	char *buf;
 
 	optype = flags & CIFS_OP_MASK;
@@ -936,80 +956,24 @@ 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.
+	 * Wait for all the requests to become available.
 	 * 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.
+	 * requests and if the client is completely idle, not generating any
+	 * other requests.
+	 * This can be handled by the eventual session reconnect.
 	 */
-	for (i = 0; i < num_rqst; i++) {
-		rc = wait_for_free_request(ses->server, flags, &instance);
-
-		if (rc == 0) {
-			credits[i].value = 1;
-			credits[i].instance = instance;
-			/*
-			 * All parts of the compound chain must get credits from
-			 * the same session, otherwise we may end up using more
-			 * credits than the server granted. If there were
-			 * reconnects in between, return -EAGAIN and let callers
-			 * handle it.
-			 */
-			if (i == 0)
-				first_instance = instance;
-			else if (first_instance != instance) {
-				i++;
-				rc = -EAGAIN;
-			}
-		}
+	rc = wait_for_compound_request(ses->server, num_rqst, flags,
+				       &instance);
+	if (rc)
+		return rc;
 
-		if (rc) {
-			/*
-			 * We haven't sent an SMB packet to the server yet but
-			 * we already obtained credits for i requests in the
-			 * compound chain - need to return those credits back
-			 * for future use. Note that we need to call add_credits
-			 * multiple times to match the way we obtained credits
-			 * in the first place and to account for in flight
-			 * requests correctly.
-			 */
-			for (j = 0; j < i; j++)
-				add_credits(ses->server, &credits[j], optype);
-			return rc;
-		}
+	for (i = 0; i < num_rqst; i++) {
+		credits[i].value = 1;
+		credits[i].instance = instance;
 	}
 
-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
@@ -1020,14 +984,12 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 
 	/*
 	 * All the parts of the compound chain belong obtained credits from the
-	 * same session (see the appropriate checks above). In the same time
-	 * there might be reconnects after those checks but before we acquired
-	 * the srv_mutex. We can not use credits obtained from the previous
+	 * same session. We can not use credits obtained from the previous
 	 * session to send this request. Check if there were reconnects after
 	 * we obtained credits and return -EAGAIN in such cases to let callers
 	 * handle it.
 	 */
-	if (first_instance != ses->server->reconnect_instance) {
+	if (instance != ses->server->reconnect_instance) {
 		mutex_unlock(&ses->server->srv_mutex);
 		for (j = 0; j < num_rqst; j++)
 			add_credits(ses->server, &credits[j], optype);
-- 
2.13.6


  parent reply	other threads:[~2019-03-08  3:34 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-08  2:58 [PATCH 0/6] cifs: simplify handling of credits for compounds Ronnie Sahlberg
2019-03-08  2:58 ` [PATCH 1/6] cifs: change wait_for_free_request() to take flags as argument Ronnie Sahlberg
2019-03-09  0:53   ` Pavel Shilovsky
2019-03-08  2:58 ` [PATCH 2/6] cifs: pass flags down into wait_for_free_credits() Ronnie Sahlberg
2019-03-09  0:54   ` Pavel Shilovsky
2019-03-08  2:58 ` [PATCH 3/6] cifs: wait_for_free_credits() make it possible to wait for >=1 credits Ronnie Sahlberg
2019-03-09  0:54   ` Pavel Shilovsky
2019-03-08  2:58 ` [PATCH 4/6] cifs: prevent starvation in wait_for_free_credits for multi-credit requests Ronnie Sahlberg
2019-03-09  0:55   ` Pavel Shilovsky
2019-03-08  2:58 ` [PATCH 5/6] cifs: add a timeout argument to wait_for_free_credits Ronnie Sahlberg
2019-03-09  0:58   ` Pavel Shilovsky
     [not found]     ` <CAH2r5ms3METKgX9sMet44r0RKdVAEe_x=vuB_6JZobJn95x4_Q@mail.gmail.com>
2019-03-09  1:06       ` Pavel Shilovsky
2019-03-10  2:21     ` Steve French
2019-03-08  2:58 ` Ronnie Sahlberg [this message]
2019-03-09  0:53   ` [PATCH 6/6] cifs: simplify how we handle credits in compond_send_recv() Pavel Shilovsky
2019-03-09 22:04     ` Steve French
  -- strict thread matches above, loose matches on Subject: below --
2019-03-11  2:18 Ronnie Sahlberg
2019-03-11 17:54 ` Pavel Shilovsky
2019-03-06  4:15 [PATCH 0/6] cifs: simplify handling of credits for compounds Ronnie Sahlberg
2019-03-06  4:15 ` [PATCH 6/6] cifs: simplify how we handle credits in compond_send_recv() Ronnie Sahlberg
2019-03-06 17:26   ` Pavel Shilovsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190308025823.24382-7-lsahlber@redhat.com \
    --to=lsahlber@redhat.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=pshilov@microsoft.com \
    --cc=smfrench@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.