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

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
...@@ -498,10 +498,10 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a ...@@ -498,10 +498,10 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
goto unlock; goto unlock;
} }
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
if (tcon->ses->server->tcpStatus != CifsExiting) if (tcon->ses->server->tcpStatus != CifsExiting)
tcon->ses->server->tcpStatus = CifsNeedReconnect; tcon->ses->server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
unlock: unlock:
mutex_unlock(&tcon->ses->server->srv_mutex); mutex_unlock(&tcon->ses->server->srv_mutex);
......
...@@ -141,9 +141,13 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, ...@@ -141,9 +141,13 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
if ((cifs_pdu == NULL) || (server == NULL)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
spin_lock(&cifs_tcp_ses_lock);
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) || if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
server->tcpStatus == CifsNeedNegotiate) server->tcpStatus == CifsNeedNegotiate) {
spin_unlock(&cifs_tcp_ses_lock);
return rc; return rc;
}
spin_unlock(&cifs_tcp_ses_lock);
if (!server->session_estab) { if (!server->session_estab) {
memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8); memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
......
...@@ -586,7 +586,7 @@ struct TCP_Server_Info { ...@@ -586,7 +586,7 @@ struct TCP_Server_Info {
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
struct smb_version_operations *ops; struct smb_version_operations *ops;
struct smb_version_values *vals; 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 */ enum statusEnum tcpStatus; /* what we think the status is */
char *hostname; /* hostname portion of UNC string */ char *hostname; /* hostname portion of UNC string */
struct socket *ssocket; struct socket *ssocket;
...@@ -924,7 +924,7 @@ struct cifs_ses { ...@@ -924,7 +924,7 @@ struct cifs_ses {
struct mutex session_mutex; struct mutex session_mutex;
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */ 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 */ unsigned overrideSecFlg; /* if non-zero override global sec flags */
char *serverOS; /* name of operating system underlying server */ char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */ char *serverNOS; /* name of network operating system of server */
......
...@@ -120,15 +120,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -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 * only tree disconnect, open, and write, (and ulogoff which does not
* have tcon) are allowed as we start force umount * have tcon) are allowed as we start force umount
*/ */
spin_lock(&cifs_tcp_ses_lock);
if (tcon->tidStatus == CifsExiting) { if (tcon->tidStatus == CifsExiting) {
if (smb_command != SMB_COM_WRITE_ANDX && if (smb_command != SMB_COM_WRITE_ANDX &&
smb_command != SMB_COM_OPEN_ANDX && smb_command != SMB_COM_OPEN_ANDX &&
smb_command != SMB_COM_TREE_DISCONNECT) { smb_command != SMB_COM_TREE_DISCONNECT) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n", cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb_command); smb_command);
return -ENODEV; return -ENODEV;
} }
} }
spin_unlock(&cifs_tcp_ses_lock);
retries = server->nr_targets; retries = server->nr_targets;
...@@ -148,8 +151,12 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -148,8 +151,12 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
} }
/* are we still trying to reconnect? */ /* 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; break;
}
spin_unlock(&cifs_tcp_ses_lock);
if (retries && --retries) if (retries && --retries)
continue; continue;
...@@ -186,11 +193,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -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 the server never sends an answer the socket will be closed
* and tcpStatus set to reconnect. * and tcpStatus set to reconnect.
*/ */
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedReconnect) { if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
goto out; goto out;
} }
spin_unlock(&cifs_tcp_ses_lock);
/* /*
* need to prevent multiple threads trying to simultaneously * need to prevent multiple threads trying to simultaneously
......
...@@ -467,9 +467,12 @@ reconnect_dfs_server(struct TCP_Server_Info *server, ...@@ -467,9 +467,12 @@ reconnect_dfs_server(struct TCP_Server_Info *server,
dfs_cache_free_tgts(&tl); dfs_cache_free_tgts(&tl);
/* Need to set up echo worker again once connection has been established */ /* Need to set up echo worker again once connection has been established */
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) if (server->tcpStatus == CifsNeedNegotiate)
mod_delayed_work(cifsiod_wq, &server->echo, 0); mod_delayed_work(cifsiod_wq, &server->echo, 0);
spin_unlock(&cifs_tcp_ses_lock);
wake_up(&server->response_q); wake_up(&server->response_q);
return rc; return rc;
} }
...@@ -571,15 +574,18 @@ server_unresponsive(struct TCP_Server_Info *server) ...@@ -571,15 +574,18 @@ server_unresponsive(struct TCP_Server_Info *server)
* 65s kernel_recvmsg times out, and we see that we haven't gotten * 65s kernel_recvmsg times out, and we see that we haven't gotten
* a response in >60s. * a response in >60s.
*/ */
spin_lock(&cifs_tcp_ses_lock);
if ((server->tcpStatus == CifsGood || if ((server->tcpStatus == CifsGood ||
server->tcpStatus == CifsNeedNegotiate) && server->tcpStatus == CifsNeedNegotiate) &&
(!server->ops->can_echo || server->ops->can_echo(server)) && (!server->ops->can_echo || server->ops->can_echo(server)) &&
time_after(jiffies, server->lstrp + 3 * server->echo_interval)) { 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", cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
(3 * server->echo_interval) / HZ); (3 * server->echo_interval) / HZ);
cifs_reconnect(server, false); cifs_reconnect(server, false);
return true; return true;
} }
spin_unlock(&cifs_tcp_ses_lock);
return false; return false;
} }
...@@ -624,13 +630,18 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) ...@@ -624,13 +630,18 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
else else
length = sock_recvmsg(server->ssocket, smb_msg, 0); 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; return -ESHUTDOWN;
}
if (server->tcpStatus == CifsNeedReconnect) { if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_reconnect(server, false); cifs_reconnect(server, false);
return -ECONNABORTED; return -ECONNABORTED;
} }
spin_unlock(&cifs_tcp_ses_lock);
if (length == -ERESTARTSYS || if (length == -ERESTARTSYS ||
length == -EAGAIN || length == -EAGAIN ||
...@@ -808,9 +819,9 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) ...@@ -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->echo);
cancel_delayed_work_sync(&server->resolve); cancel_delayed_work_sync(&server->resolve);
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
wake_up_all(&server->response_q); wake_up_all(&server->response_q);
/* check if we have blocked requests that need to free */ /* 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) ...@@ -1427,9 +1438,9 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
else else
cancel_delayed_work_sync(&server->reconnect); cancel_delayed_work_sync(&server->reconnect);
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
cifs_crypto_secmech_release(server); cifs_crypto_secmech_release(server);
...@@ -1582,7 +1593,9 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ...@@ -1582,7 +1593,9 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
* to the struct since the kernel thread not created yet * to the struct since the kernel thread not created yet
* no need to spinlock this update of tcpStatus * no need to spinlock this update of tcpStatus
*/ */
spin_lock(&cifs_tcp_ses_lock);
tcp_ses->tcpStatus = CifsNeedNegotiate; tcp_ses->tcpStatus = CifsNeedNegotiate;
spin_unlock(&cifs_tcp_ses_lock);
if ((ctx->max_credits < 20) || (ctx->max_credits > 60000)) if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE; tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
...@@ -1799,15 +1812,13 @@ void cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -1799,15 +1812,13 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return; return;
} }
spin_unlock(&cifs_tcp_ses_lock);
/* ses_count can never go negative */ /* ses_count can never go negative */
WARN_ON(ses->ses_count < 0); WARN_ON(ses->ses_count < 0);
spin_lock(&GlobalMid_Lock);
if (ses->status == CifsGood) if (ses->status == CifsGood)
ses->status = CifsExiting; ses->status = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
cifs_free_ipc(ses); cifs_free_ipc(ses);
...@@ -3075,12 +3086,15 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx) ...@@ -3075,12 +3086,15 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
* for just this mount. * for just this mount.
*/ */
reset_cifs_unix_caps(xid, tcon, cifs_sb, ctx); reset_cifs_unix_caps(xid, tcon, cifs_sb, ctx);
spin_lock(&cifs_tcp_ses_lock);
if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
(le64_to_cpu(tcon->fsUnixInfo.Capability) & (le64_to_cpu(tcon->fsUnixInfo.Capability) &
CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
spin_unlock(&cifs_tcp_ses_lock);
rc = -EACCES; rc = -EACCES;
goto out; goto out;
} }
spin_unlock(&cifs_tcp_ses_lock);
} else } else
tcon->unix_ext = 0; /* server does not support them */ tcon->unix_ext = 0; /* server does not support them */
...@@ -3755,7 +3769,9 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, ...@@ -3755,7 +3769,9 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
if (rc == 0) { if (rc == 0) {
bool is_unicode; bool is_unicode;
spin_lock(&cifs_tcp_ses_lock);
tcon->tidStatus = CifsGood; tcon->tidStatus = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
tcon->need_reconnect = false; tcon->need_reconnect = false;
tcon->tid = smb_buffer_response->Tid; tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
...@@ -3859,12 +3875,12 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, ...@@ -3859,12 +3875,12 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
rc = server->ops->negotiate(xid, ses, server); rc = server->ops->negotiate(xid, ses, server);
if (rc == 0) { if (rc == 0) {
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) if (server->tcpStatus == CifsNeedNegotiate)
server->tcpStatus = CifsGood; server->tcpStatus = CifsGood;
else else
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
} }
return rc; return rc;
......
...@@ -896,10 +896,10 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr) ...@@ -896,10 +896,10 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
if (class == ERRSRV && code == ERRbaduid) { if (class == ERRSRV && code == ERRbaduid) {
cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n", cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
code); code);
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
if (mid->server->tcpStatus != CifsExiting) if (mid->server->tcpStatus != CifsExiting)
mid->server->tcpStatus = CifsNeedReconnect; mid->server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
} }
} }
......
...@@ -369,10 +369,10 @@ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses) ...@@ -369,10 +369,10 @@ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses)
int i; int i;
for (i = 0; i < ses->chan_count; i++) { for (i = 0; i < ses->chan_count; i++) {
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
if (ses->chans[i].server->tcpStatus != CifsExiting) if (ses->chans[i].server->tcpStatus != CifsExiting)
ses->chans[i].server->tcpStatus = CifsNeedReconnect; ses->chans[i].server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
} }
} }
...@@ -1052,9 +1052,9 @@ sess_establish_session(struct sess_data *sess_data) ...@@ -1052,9 +1052,9 @@ sess_establish_session(struct sess_data *sess_data)
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
/* Even if one channel is active, session is in good state */ /* Even if one channel is active, session is in good state */
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
ses->status = CifsGood; ses->status = CifsGood;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
return 0; return 0;
} }
......
...@@ -163,7 +163,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server) ...@@ -163,7 +163,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
{ {
__u64 mid = 0; __u64 mid = 0;
__u16 last_mid, cur_mid; __u16 last_mid, cur_mid;
bool collision; bool collision, reconnect;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
...@@ -215,7 +215,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server) ...@@ -215,7 +215,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
* an eventual reconnect to clean out the pending_mid_q. * an eventual reconnect to clean out the pending_mid_q.
*/ */
if (num_mids > 32768) if (num_mids > 32768)
server->tcpStatus = CifsNeedReconnect; reconnect = true;
if (!collision) { if (!collision) {
mid = (__u64)cur_mid; mid = (__u64)cur_mid;
...@@ -225,6 +225,13 @@ cifs_get_next_mid(struct TCP_Server_Info *server) ...@@ -225,6 +225,13 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
cur_mid++; cur_mid++;
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if (reconnect) {
spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsNeedReconnect;
spin_unlock(&cifs_tcp_ses_lock);
}
return mid; return mid;
} }
......
...@@ -121,9 +121,13 @@ smb2_add_credits(struct TCP_Server_Info *server, ...@@ -121,9 +121,13 @@ smb2_add_credits(struct TCP_Server_Info *server,
optype, scredits, add); optype, scredits, add);
} }
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedReconnect if (server->tcpStatus == CifsNeedReconnect
|| server->tcpStatus == CifsExiting) || server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return; return;
}
spin_unlock(&cifs_tcp_ses_lock);
switch (rc) { switch (rc) {
case -1: case -1:
...@@ -208,11 +212,15 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -208,11 +212,15 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
return rc; return rc;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
} else { } else {
spin_unlock(&server->req_lock);
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) { if (server->tcpStatus == CifsExiting) {
spin_unlock(&server->req_lock); spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
} }
spin_unlock(&cifs_tcp_ses_lock);
spin_lock(&server->req_lock);
scredits = server->credits; scredits = server->credits;
/* can deadlock with reopen */ /* can deadlock with reopen */
if (scredits <= 8) { if (scredits <= 8) {
...@@ -4983,10 +4991,12 @@ static void smb2_decrypt_offload(struct work_struct *work) ...@@ -4983,10 +4991,12 @@ static void smb2_decrypt_offload(struct work_struct *work)
mid->callback(mid); mid->callback(mid);
} else { } else {
spin_lock(&cifs_tcp_ses_lock);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (dw->server->tcpStatus == CifsNeedReconnect) { if (dw->server->tcpStatus == CifsNeedReconnect) {
mid->mid_state = MID_RETRY_NEEDED; mid->mid_state = MID_RETRY_NEEDED;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
spin_unlock(&cifs_tcp_ses_lock);
mid->callback(mid); mid->callback(mid);
} else { } else {
mid->mid_state = MID_REQUEST_SUBMITTED; mid->mid_state = MID_REQUEST_SUBMITTED;
...@@ -4994,6 +5004,7 @@ static void smb2_decrypt_offload(struct work_struct *work) ...@@ -4994,6 +5004,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
list_add_tail(&mid->qhead, list_add_tail(&mid->qhead,
&dw->server->pending_mid_q); &dw->server->pending_mid_q);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
spin_unlock(&cifs_tcp_ses_lock);
} }
} }
cifs_mid_q_entry_release(mid); cifs_mid_q_entry_release(mid);
......
...@@ -162,6 +162,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -162,6 +162,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL) if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
return 0; return 0;
spin_lock(&cifs_tcp_ses_lock);
if (tcon->tidStatus == CifsExiting) { if (tcon->tidStatus == CifsExiting) {
/* /*
* only tree disconnect, open, and write, * only tree disconnect, open, and write,
...@@ -171,11 +172,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -171,11 +172,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
if ((smb2_command != SMB2_WRITE) && if ((smb2_command != SMB2_WRITE) &&
(smb2_command != SMB2_CREATE) && (smb2_command != SMB2_CREATE) &&
(smb2_command != SMB2_TREE_DISCONNECT)) { (smb2_command != SMB2_TREE_DISCONNECT)) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n", cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb2_command); smb2_command);
return -ENODEV; return -ENODEV;
} }
} }
spin_unlock(&cifs_tcp_ses_lock);
if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
(!tcon->ses->server) || !server) (!tcon->ses->server) || !server)
return -EIO; return -EIO;
...@@ -214,8 +217,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -214,8 +217,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
} }
/* are we still trying to reconnect? */ /* 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; break;
}
spin_unlock(&cifs_tcp_ses_lock);
if (retries && --retries) if (retries && --retries)
continue; continue;
...@@ -255,11 +262,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -255,11 +262,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
* and the server never sends an answer the socket will be closed * and the server never sends an answer the socket will be closed
* and tcpStatus set to reconnect. * and tcpStatus set to reconnect.
*/ */
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedReconnect) { if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
goto out; goto out;
} }
spin_unlock(&cifs_tcp_ses_lock);
/* /*
* need to prevent multiple threads trying to simultaneously * need to prevent multiple threads trying to simultaneously
...@@ -1386,9 +1396,9 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data) ...@@ -1386,9 +1396,9 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
/* Even if one channel is active, session is in good state */ /* Even if one channel is active, session is in good state */
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
ses->status = CifsGood; ses->status = CifsGood;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
return rc; return rc;
} }
...@@ -1917,7 +1927,9 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1917,7 +1927,9 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
tcon->share_flags = le32_to_cpu(rsp->ShareFlags); tcon->share_flags = le32_to_cpu(rsp->ShareFlags);
tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */ tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */
tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
spin_lock(&cifs_tcp_ses_lock);
tcon->tidStatus = CifsGood; tcon->tidStatus = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
tcon->need_reconnect = false; tcon->need_reconnect = false;
tcon->tid = le32_to_cpu(rsp->hdr.Id.SyncId.TreeId); tcon->tid = le32_to_cpu(rsp->hdr.Id.SyncId.TreeId);
strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
...@@ -3854,11 +3866,14 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -3854,11 +3866,14 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) { if (server->tcpStatus == CifsNeedNegotiate) {
spin_unlock(&cifs_tcp_ses_lock);
/* No need to send echo on newly established connections */ /* No need to send echo on newly established connections */
mod_delayed_work(cifsiod_wq, &server->reconnect, 0); mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
return rc; return rc;
} }
spin_unlock(&cifs_tcp_ses_lock);
rc = smb2_plain_req_init(SMB2_ECHO, NULL, server, rc = smb2_plain_req_init(SMB2_ECHO, NULL, server,
(void **)&req, &total_len); (void **)&req, &total_len);
......
...@@ -634,8 +634,12 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -634,8 +634,12 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (!is_signed) if (!is_signed)
return 0; return 0;
if (server->tcpStatus == CifsNeedNegotiate) spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate) {
spin_unlock(&cifs_tcp_ses_lock);
return 0; return 0;
}
spin_unlock(&cifs_tcp_ses_lock);
if (!is_binding && !server->session_estab) { if (!is_binding && !server->session_estab) {
strncpy(shdr->Signature, "BSRSPYL", 8); strncpy(shdr->Signature, "BSRSPYL", 8);
return 0; return 0;
...@@ -751,30 +755,41 @@ static int ...@@ -751,30 +755,41 @@ static int
smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server, smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
struct smb2_hdr *shdr, struct mid_q_entry **mid) struct smb2_hdr *shdr, struct mid_q_entry **mid)
{ {
if (server->tcpStatus == CifsExiting) spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
}
if (server->tcpStatus == CifsNeedReconnect) { if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
return -EAGAIN; return -EAGAIN;
} }
if (server->tcpStatus == CifsNeedNegotiate && if (server->tcpStatus == CifsNeedNegotiate &&
shdr->Command != SMB2_NEGOTIATE) shdr->Command != SMB2_NEGOTIATE) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN; return -EAGAIN;
}
if (ses->status == CifsNew) { if (ses->status == CifsNew) {
if ((shdr->Command != SMB2_SESSION_SETUP) && if ((shdr->Command != SMB2_SESSION_SETUP) &&
(shdr->Command != SMB2_NEGOTIATE)) (shdr->Command != SMB2_NEGOTIATE)) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN; return -EAGAIN;
}
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) { if (ses->status == CifsExiting) {
if (shdr->Command != SMB2_LOGOFF) if (shdr->Command != SMB2_LOGOFF) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN; return -EAGAIN;
}
/* else ok - we are shutting down the session */ /* else ok - we are shutting down the session */
} }
spin_unlock(&cifs_tcp_ses_lock);
*mid = smb2_mid_entry_alloc(shdr, server); *mid = smb2_mid_entry_alloc(shdr, server);
if (*mid == NULL) if (*mid == NULL)
...@@ -847,9 +862,13 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) ...@@ -847,9 +862,13 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
(struct smb2_hdr *)rqst->rq_iov[0].iov_base; (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid; struct mid_q_entry *mid;
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsNeedNegotiate && if (server->tcpStatus == CifsNeedNegotiate &&
shdr->Command != SMB2_NEGOTIATE) shdr->Command != SMB2_NEGOTIATE) {
spin_unlock(&cifs_tcp_ses_lock);
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
}
spin_unlock(&cifs_tcp_ses_lock);
smb2_seq_num_into_buf(server, shdr); smb2_seq_num_into_buf(server, shdr);
......
...@@ -430,9 +430,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -430,9 +430,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
* be taken as the remainder of this one. We need to kill the * be taken as the remainder of this one. We need to kill the
* socket so the server throws away the partial SMB * socket so the server throws away the partial SMB
*/ */
spin_lock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsNeedReconnect; server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock);
trace_smb3_partial_send_reconnect(server->CurrentMid, trace_smb3_partial_send_reconnect(server->CurrentMid,
server->conn_id, server->hostname); server->conn_id, server->hostname);
} }
...@@ -578,10 +578,14 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -578,10 +578,14 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
return -ERESTARTSYS; return -ERESTARTSYS;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
} else { } else {
spin_unlock(&server->req_lock);
spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) { if (server->tcpStatus == CifsExiting) {
spin_unlock(&server->req_lock); spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
} }
spin_unlock(&cifs_tcp_ses_lock);
/* /*
* For normal commands, reserve the last MAX_COMPOUND * For normal commands, reserve the last MAX_COMPOUND
...@@ -596,6 +600,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -596,6 +600,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
* for servers that are slow to hand out credits on * for servers that are slow to hand out credits on
* new sessions. * new sessions.
*/ */
spin_lock(&server->req_lock);
if (!optype && num_credits == 1 && if (!optype && num_credits == 1 &&
server->in_flight > 2 * MAX_COMPOUND && server->in_flight > 2 * MAX_COMPOUND &&
*credits <= MAX_COMPOUND) { *credits <= MAX_COMPOUND) {
...@@ -723,28 +728,36 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -723,28 +728,36 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
struct mid_q_entry **ppmidQ) struct mid_q_entry **ppmidQ)
{ {
spin_lock(&cifs_tcp_ses_lock);
if (ses->server->tcpStatus == CifsExiting) { if (ses->server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
} }
if (ses->server->tcpStatus == CifsNeedReconnect) { if (ses->server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
return -EAGAIN; return -EAGAIN;
} }
if (ses->status == CifsNew) { if (ses->status == CifsNew) {
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) (in_buf->Command != SMB_COM_NEGOTIATE)) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN; return -EAGAIN;
}
/* else ok - we are setting up session */ /* else ok - we are setting up session */
} }
if (ses->status == CifsExiting) { if (ses->status == CifsExiting) {
/* check if SMB session is bad because we are setting it up */ /* check if SMB session is bad because we are setting it up */
if (in_buf->Command != SMB_COM_LOGOFF_ANDX) if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
spin_unlock(&cifs_tcp_ses_lock);
return -EAGAIN; return -EAGAIN;
}
/* else ok - we are shutting down session */ /* else ok - we are shutting down session */
} }
spin_unlock(&cifs_tcp_ses_lock);
*ppmidQ = AllocMidQEntry(in_buf, ses->server); *ppmidQ = AllocMidQEntry(in_buf, ses->server);
if (*ppmidQ == NULL) if (*ppmidQ == NULL)
...@@ -1085,8 +1098,12 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1085,8 +1098,12 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
return -EIO; return -EIO;
} }
if (server->tcpStatus == CifsExiting) spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
}
spin_unlock(&cifs_tcp_ses_lock);
/* /*
* Wait for all the requests to become available. * Wait for all the requests to become available.
...@@ -1189,11 +1206,17 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1189,11 +1206,17 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/* /*
* Compounding is never used during session establish. * Compounding is never used during session establish.
*/ */
spin_lock(&cifs_tcp_ses_lock);
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
spin_unlock(&cifs_tcp_ses_lock);
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec); smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
spin_lock(&cifs_tcp_ses_lock);
} }
spin_unlock(&cifs_tcp_ses_lock);
for (i = 0; i < num_rqst; i++) { for (i = 0; i < num_rqst; i++) {
rc = wait_for_response(server, midQ[i]); rc = wait_for_response(server, midQ[i]);
...@@ -1256,15 +1279,19 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1256,15 +1279,19 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/* /*
* Compounding is never used during session establish. * Compounding is never used during session establish.
*/ */
spin_lock(&cifs_tcp_ses_lock);
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
struct kvec iov = { struct kvec iov = {
.iov_base = resp_iov[0].iov_base, .iov_base = resp_iov[0].iov_base,
.iov_len = resp_iov[0].iov_len .iov_len = resp_iov[0].iov_len
}; };
spin_unlock(&cifs_tcp_ses_lock);
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
smb311_update_preauth_hash(ses, server, &iov, 1); smb311_update_preauth_hash(ses, server, &iov, 1);
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
spin_lock(&cifs_tcp_ses_lock);
} }
spin_unlock(&cifs_tcp_ses_lock);
out: out:
/* /*
...@@ -1353,8 +1380,12 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, ...@@ -1353,8 +1380,12 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
return -EIO; return -EIO;
} }
if (server->tcpStatus == CifsExiting) spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
}
spin_unlock(&cifs_tcp_ses_lock);
/* Ensure that we do not send more than 50 overlapping requests /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or to the same server. We may make this configurable later or
...@@ -1494,8 +1525,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1494,8 +1525,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
return -EIO; return -EIO;
} }
if (server->tcpStatus == CifsExiting) spin_lock(&cifs_tcp_ses_lock);
if (server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT; return -ENOENT;
}
spin_unlock(&cifs_tcp_ses_lock);
/* Ensure that we do not send more than 50 overlapping requests /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or to the same server. We may make this configurable later or
...@@ -1553,10 +1588,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1553,10 +1588,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
(server->tcpStatus != CifsNew))); (server->tcpStatus != CifsNew)));
/* Were we interrupted by a signal ? */ /* Were we interrupted by a signal ? */
spin_lock(&cifs_tcp_ses_lock);
if ((rc == -ERESTARTSYS) && if ((rc == -ERESTARTSYS) &&
(midQ->mid_state == MID_REQUEST_SUBMITTED) && (midQ->mid_state == MID_REQUEST_SUBMITTED) &&
((server->tcpStatus == CifsGood) || ((server->tcpStatus == CifsGood) ||
(server->tcpStatus == CifsNew))) { (server->tcpStatus == CifsNew))) {
spin_unlock(&cifs_tcp_ses_lock);
if (in_buf->Command == SMB_COM_TRANSACTION2) { if (in_buf->Command == SMB_COM_TRANSACTION2) {
/* POSIX lock. We send a NT_CANCEL SMB to cause the /* POSIX lock. We send a NT_CANCEL SMB to cause the
...@@ -1595,7 +1632,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1595,7 +1632,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
/* We got the response - restart system call. */ /* We got the response - restart system call. */
rstart = 1; rstart = 1;
spin_lock(&cifs_tcp_ses_lock);
} }
spin_unlock(&cifs_tcp_ses_lock);
rc = cifs_sync_mid_result(midQ, server); rc = cifs_sync_mid_result(midQ, server);
if (rc != 0) if (rc != 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment