Commit 326a8d04 authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French
Browse files

cifs: do all necessary checks for credits within or before locking



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: d7d7a66a ("cifs: avoid use of global locks for high contention data")
Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 33f73618
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -215,6 +215,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);
@@ -225,15 +235,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) {
+10 −10
Original line number Diff line number Diff line
@@ -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) {