Commit 080dc5e5 authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French
Browse files

cifs: take cifs_tcp_ses_lock for status checks



While checking/updating status for tcp ses, smb ses or tcon,
we take GlobalMid_Lock. This doesn't make any sense.
Replaced it with cifs_tcp_ses_lock.

Ideally, we should take a spin lock per struct.
But since tcp ses, smb ses and tcon objects won't add up to a lot,
I think there should not be too much contention.

Also, in few other places, these are checked without locking.
Added locking for these.

Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 183eea2e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -498,10 +498,10 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
		goto unlock;
	}

	spin_lock(&GlobalMid_Lock);
	spin_lock(&cifs_tcp_ses_lock);
	if (tcon->ses->server->tcpStatus != CifsExiting)
		tcon->ses->server->tcpStatus = CifsNeedReconnect;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&cifs_tcp_ses_lock);

unlock:
	mutex_unlock(&tcon->ses->server->srv_mutex);
+5 −1
Original line number Diff line number Diff line
@@ -141,9 +141,13 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
	if ((cifs_pdu == NULL) || (server == NULL))
		return -EINVAL;

	spin_lock(&cifs_tcp_ses_lock);
	if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
	    server->tcpStatus == CifsNeedNegotiate)
	    server->tcpStatus == CifsNeedNegotiate) {
		spin_unlock(&cifs_tcp_ses_lock);
		return rc;
	}
	spin_unlock(&cifs_tcp_ses_lock);

	if (!server->session_estab) {
		memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+2 −2
Original line number Diff line number Diff line
@@ -586,7 +586,7 @@ struct TCP_Server_Info {
	char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
	struct smb_version_operations	*ops;
	struct smb_version_values	*vals;
	/* updates to tcpStatus protected by GlobalMid_Lock */
	/* updates to tcpStatus protected by cifs_tcp_ses_lock */
	enum statusEnum tcpStatus; /* what we think the status is */
	char *hostname; /* hostname portion of UNC string */
	struct socket *ssocket;
@@ -924,7 +924,7 @@ struct cifs_ses {
	struct mutex session_mutex;
	struct TCP_Server_Info *server;	/* pointer to server info */
	int ses_count;		/* reference counter */
	enum statusEnum status;  /* updates protected by GlobalMid_Lock */
	enum statusEnum status;  /* updates protected by cifs_tcp_ses_lock */
	unsigned overrideSecFlg;  /* if non-zero override global sec flags */
	char *serverOS;		/* name of operating system underlying server */
	char *serverNOS;	/* name of network operating system of server */
+11 −1
Original line number Diff line number Diff line
@@ -120,15 +120,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
	 * only tree disconnect, open, and write, (and ulogoff which does not
	 * have tcon) are allowed as we start force umount
	 */
	spin_lock(&cifs_tcp_ses_lock);
	if (tcon->tidStatus == CifsExiting) {
		if (smb_command != SMB_COM_WRITE_ANDX &&
		    smb_command != SMB_COM_OPEN_ANDX &&
		    smb_command != SMB_COM_TREE_DISCONNECT) {
			spin_unlock(&cifs_tcp_ses_lock);
			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
				 smb_command);
			return -ENODEV;
		}
	}
	spin_unlock(&cifs_tcp_ses_lock);

	retries = server->nr_targets;

@@ -148,8 +151,12 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
		}

		/* are we still trying to reconnect? */
		if (server->tcpStatus != CifsNeedReconnect)
		spin_lock(&cifs_tcp_ses_lock);
		if (server->tcpStatus != CifsNeedReconnect) {
			spin_unlock(&cifs_tcp_ses_lock);
			break;
		}
		spin_unlock(&cifs_tcp_ses_lock);

		if (retries && --retries)
			continue;
@@ -186,11 +193,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
	 * and the server never sends an answer the socket will be closed
	 * and tcpStatus set to reconnect.
	 */
	spin_lock(&cifs_tcp_ses_lock);
	if (server->tcpStatus == CifsNeedReconnect) {
		spin_unlock(&cifs_tcp_ses_lock);
		rc = -EHOSTDOWN;
		mutex_unlock(&ses->session_mutex);
		goto out;
	}
	spin_unlock(&cifs_tcp_ses_lock);

	/*
	 * need to prevent multiple threads trying to simultaneously
+26 −10
Original line number Diff line number Diff line
@@ -467,9 +467,12 @@ reconnect_dfs_server(struct TCP_Server_Info *server,
	dfs_cache_free_tgts(&tl);

	/* Need to set up echo worker again once connection has been established */
	spin_lock(&cifs_tcp_ses_lock);
	if (server->tcpStatus == CifsNeedNegotiate)
		mod_delayed_work(cifsiod_wq, &server->echo, 0);

	spin_unlock(&cifs_tcp_ses_lock);

	wake_up(&server->response_q);
	return rc;
}
@@ -571,15 +574,18 @@ server_unresponsive(struct TCP_Server_Info *server)
	 * 65s kernel_recvmsg times out, and we see that we haven't gotten
	 *     a response in >60s.
	 */
	spin_lock(&cifs_tcp_ses_lock);
	if ((server->tcpStatus == CifsGood ||
	    server->tcpStatus == CifsNeedNegotiate) &&
	    (!server->ops->can_echo || server->ops->can_echo(server)) &&
	    time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
		spin_unlock(&cifs_tcp_ses_lock);
		cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
			 (3 * server->echo_interval) / HZ);
		cifs_reconnect(server, false);
		return true;
	}
	spin_unlock(&cifs_tcp_ses_lock);

	return false;
}
@@ -624,13 +630,18 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
		else
			length = sock_recvmsg(server->ssocket, smb_msg, 0);

		if (server->tcpStatus == CifsExiting)
		spin_lock(&cifs_tcp_ses_lock);
		if (server->tcpStatus == CifsExiting) {
			spin_unlock(&cifs_tcp_ses_lock);
			return -ESHUTDOWN;
		}

		if (server->tcpStatus == CifsNeedReconnect) {
			spin_unlock(&cifs_tcp_ses_lock);
			cifs_reconnect(server, false);
			return -ECONNABORTED;
		}
		spin_unlock(&cifs_tcp_ses_lock);

		if (length == -ERESTARTSYS ||
		    length == -EAGAIN ||
@@ -808,9 +819,9 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
	cancel_delayed_work_sync(&server->echo);
	cancel_delayed_work_sync(&server->resolve);

	spin_lock(&GlobalMid_Lock);
	spin_lock(&cifs_tcp_ses_lock);
	server->tcpStatus = CifsExiting;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&cifs_tcp_ses_lock);
	wake_up_all(&server->response_q);

	/* check if we have blocked requests that need to free */
@@ -1427,9 +1438,9 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
	else
		cancel_delayed_work_sync(&server->reconnect);

	spin_lock(&GlobalMid_Lock);
	spin_lock(&cifs_tcp_ses_lock);
	server->tcpStatus = CifsExiting;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&cifs_tcp_ses_lock);

	cifs_crypto_secmech_release(server);

@@ -1582,7 +1593,9 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
	 * to the struct since the kernel thread not created yet
	 * no need to spinlock this update of tcpStatus
	 */
	spin_lock(&cifs_tcp_ses_lock);
	tcp_ses->tcpStatus = CifsNeedNegotiate;
	spin_unlock(&cifs_tcp_ses_lock);

	if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
		tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
@@ -1799,15 +1812,13 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
		spin_unlock(&cifs_tcp_ses_lock);
		return;
	}
	spin_unlock(&cifs_tcp_ses_lock);

	/* ses_count can never go negative */
	WARN_ON(ses->ses_count < 0);

	spin_lock(&GlobalMid_Lock);
	if (ses->status == CifsGood)
		ses->status = CifsExiting;
	spin_unlock(&GlobalMid_Lock);
	spin_unlock(&cifs_tcp_ses_lock);

	cifs_free_ipc(ses);

@@ -3075,12 +3086,15 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
		 * for just this mount.
		 */
		reset_cifs_unix_caps(xid, tcon, cifs_sb, ctx);
		spin_lock(&cifs_tcp_ses_lock);
		if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
		    (le64_to_cpu(tcon->fsUnixInfo.Capability) &
		     CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
			spin_unlock(&cifs_tcp_ses_lock);
			rc = -EACCES;
			goto out;
		}
		spin_unlock(&cifs_tcp_ses_lock);
	} else
		tcon->unix_ext = 0; /* server does not support them */

@@ -3755,7 +3769,9 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
	if (rc == 0) {
		bool is_unicode;

		spin_lock(&cifs_tcp_ses_lock);
		tcon->tidStatus = CifsGood;
		spin_unlock(&cifs_tcp_ses_lock);
		tcon->need_reconnect = false;
		tcon->tid = smb_buffer_response->Tid;
		bcc_ptr = pByteArea(smb_buffer_response);
@@ -3859,12 +3875,12 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,

	rc = server->ops->negotiate(xid, ses, server);
	if (rc == 0) {
		spin_lock(&GlobalMid_Lock);
		spin_lock(&cifs_tcp_ses_lock);
		if (server->tcpStatus == CifsNeedNegotiate)
			server->tcpStatus = CifsGood;
		else
			rc = -EHOSTDOWN;
		spin_unlock(&GlobalMid_Lock);
		spin_unlock(&cifs_tcp_ses_lock);
	}

	return rc;
Loading