cifs: protect all accesses to chan_* with chan_lock
A spin lock called chan_lock was introduced recently. But not all accesses were protected. Doing that with this change. To make sure that a channel is not freed when in use, we need to introduce a ref count. But today, we don't ever free channels. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
a05885ce13
commit
88b024f556
@ -1831,7 +1831,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
chan_count = ses->chan_count;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
/* close any extra channels */
|
||||
if (chan_count > 1) {
|
||||
@ -1848,6 +1847,7 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
|
||||
ses->chans[i].server = NULL;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
sesInfoFree(ses);
|
||||
cifs_put_tcp_session(server, 0);
|
||||
@ -2123,8 +2123,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
|
||||
/* each channel uses a different signing key */
|
||||
spin_lock(&ses->chan_lock);
|
||||
memcpy(ses->chans[0].signkey, ses->smb3signingkey,
|
||||
sizeof(ses->smb3signingkey));
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (rc)
|
||||
goto get_ses_fail;
|
||||
|
@ -65,6 +65,8 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* channel helper functions. assumed that chan_lock is held by caller. */
|
||||
|
||||
unsigned int
|
||||
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server)
|
||||
@ -134,10 +136,10 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
left = ses->chan_max - ses->chan_count;
|
||||
|
||||
if (left <= 0) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_dbg(FYI,
|
||||
"ses already at max_channels (%zu), nothing to open\n",
|
||||
ses->chan_max);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -369,12 +371,14 @@ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->chan_lock);
|
||||
for (i = 0; i < ses->chan_count; i++) {
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
if (ses->chans[i].server->tcpStatus != CifsExiting)
|
||||
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
|
||||
|
@ -244,10 +244,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d",
|
||||
tcon->ses->chans_need_reconnect,
|
||||
tcon->need_reconnect);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
nls_codepage = load_nls_default();
|
||||
|
||||
@ -3835,11 +3835,13 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
* binding session, but tcon is healthy (some other channel
|
||||
* is active)
|
||||
*/
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (!tcon_selected && cifs_chan_needs_reconnect(ses, server)) {
|
||||
list_add_tail(&ses->rlist, &tmp_ses_list);
|
||||
ses_selected = ses_exist = true;
|
||||
ses->ses_count++;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
}
|
||||
/*
|
||||
* Get the reference to server struct to be sure that the last call of
|
||||
|
@ -100,6 +100,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
|
||||
goto out;
|
||||
|
||||
found:
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (cifs_chan_needs_reconnect(ses, server) &&
|
||||
!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
|
||||
/*
|
||||
@ -108,6 +109,7 @@ found:
|
||||
* session key
|
||||
*/
|
||||
memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -119,9 +121,11 @@ found:
|
||||
chan = ses->chans + i;
|
||||
if (chan->server == server) {
|
||||
memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
cifs_dbg(VFS,
|
||||
"%s: Could not find channel signing key for session 0x%llx\n",
|
||||
@ -430,8 +434,10 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
||||
return rc;
|
||||
|
||||
/* safe to access primary channel, since it will never go away */
|
||||
spin_lock(&ses->chan_lock);
|
||||
memcpy(ses->chans[0].signkey, ses->smb3signingkey,
|
||||
SMB3_SIGN_KEY_SIZE);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
rc = generate_key(ses, ptriplet->encryption.label,
|
||||
ptriplet->encryption.context,
|
||||
|
@ -1049,7 +1049,10 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
|
||||
|
||||
/* round robin */
|
||||
index = (uint)atomic_inc_return(&ses->chan_seq);
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
index %= ses->chan_count;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
return ses->chans[index].server;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user