Skip to content

Commit 080dc5e

Browse files
sprasad-microsoftsmfrench
authored andcommitted
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: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 183eea2 commit 080dc5e

File tree

12 files changed

+164
-43
lines changed

12 files changed

+164
-43
lines changed

fs/cifs/cifs_swn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,10 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
498498
goto unlock;
499499
}
500500

501-
spin_lock(&GlobalMid_Lock);
501+
spin_lock(&cifs_tcp_ses_lock);
502502
if (tcon->ses->server->tcpStatus != CifsExiting)
503503
tcon->ses->server->tcpStatus = CifsNeedReconnect;
504-
spin_unlock(&GlobalMid_Lock);
504+
spin_unlock(&cifs_tcp_ses_lock);
505505

506506
unlock:
507507
mutex_unlock(&tcon->ses->server->srv_mutex);

fs/cifs/cifsencrypt.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,13 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
141141
if ((cifs_pdu == NULL) || (server == NULL))
142142
return -EINVAL;
143143

144+
spin_lock(&cifs_tcp_ses_lock);
144145
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
145-
server->tcpStatus == CifsNeedNegotiate)
146+
server->tcpStatus == CifsNeedNegotiate) {
147+
spin_unlock(&cifs_tcp_ses_lock);
146148
return rc;
149+
}
150+
spin_unlock(&cifs_tcp_ses_lock);
147151

148152
if (!server->session_estab) {
149153
memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);

fs/cifs/cifsglob.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ struct TCP_Server_Info {
586586
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
587587
struct smb_version_operations *ops;
588588
struct smb_version_values *vals;
589-
/* updates to tcpStatus protected by GlobalMid_Lock */
589+
/* updates to tcpStatus protected by cifs_tcp_ses_lock */
590590
enum statusEnum tcpStatus; /* what we think the status is */
591591
char *hostname; /* hostname portion of UNC string */
592592
struct socket *ssocket;
@@ -924,7 +924,7 @@ struct cifs_ses {
924924
struct mutex session_mutex;
925925
struct TCP_Server_Info *server; /* pointer to server info */
926926
int ses_count; /* reference counter */
927-
enum statusEnum status; /* updates protected by GlobalMid_Lock */
927+
enum statusEnum status; /* updates protected by cifs_tcp_ses_lock */
928928
unsigned overrideSecFlg; /* if non-zero override global sec flags */
929929
char *serverOS; /* name of operating system underlying server */
930930
char *serverNOS; /* name of network operating system of server */

fs/cifs/cifssmb.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
120120
* only tree disconnect, open, and write, (and ulogoff which does not
121121
* have tcon) are allowed as we start force umount
122122
*/
123+
spin_lock(&cifs_tcp_ses_lock);
123124
if (tcon->tidStatus == CifsExiting) {
124125
if (smb_command != SMB_COM_WRITE_ANDX &&
125126
smb_command != SMB_COM_OPEN_ANDX &&
126127
smb_command != SMB_COM_TREE_DISCONNECT) {
128+
spin_unlock(&cifs_tcp_ses_lock);
127129
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
128130
smb_command);
129131
return -ENODEV;
130132
}
131133
}
134+
spin_unlock(&cifs_tcp_ses_lock);
132135

133136
retries = server->nr_targets;
134137

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

150153
/* are we still trying to reconnect? */
151-
if (server->tcpStatus != CifsNeedReconnect)
154+
spin_lock(&cifs_tcp_ses_lock);
155+
if (server->tcpStatus != CifsNeedReconnect) {
156+
spin_unlock(&cifs_tcp_ses_lock);
152157
break;
158+
}
159+
spin_unlock(&cifs_tcp_ses_lock);
153160

154161
if (retries && --retries)
155162
continue;
@@ -186,11 +193,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
186193
* and the server never sends an answer the socket will be closed
187194
* and tcpStatus set to reconnect.
188195
*/
196+
spin_lock(&cifs_tcp_ses_lock);
189197
if (server->tcpStatus == CifsNeedReconnect) {
198+
spin_unlock(&cifs_tcp_ses_lock);
190199
rc = -EHOSTDOWN;
191200
mutex_unlock(&ses->session_mutex);
192201
goto out;
193202
}
203+
spin_unlock(&cifs_tcp_ses_lock);
194204

195205
/*
196206
* need to prevent multiple threads trying to simultaneously

fs/cifs/connect.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,12 @@ reconnect_dfs_server(struct TCP_Server_Info *server,
467467
dfs_cache_free_tgts(&tl);
468468

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

474+
spin_unlock(&cifs_tcp_ses_lock);
475+
473476
wake_up(&server->response_q);
474477
return rc;
475478
}
@@ -571,15 +574,18 @@ server_unresponsive(struct TCP_Server_Info *server)
571574
* 65s kernel_recvmsg times out, and we see that we haven't gotten
572575
* a response in >60s.
573576
*/
577+
spin_lock(&cifs_tcp_ses_lock);
574578
if ((server->tcpStatus == CifsGood ||
575579
server->tcpStatus == CifsNeedNegotiate) &&
576580
(!server->ops->can_echo || server->ops->can_echo(server)) &&
577581
time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
582+
spin_unlock(&cifs_tcp_ses_lock);
578583
cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
579584
(3 * server->echo_interval) / HZ);
580585
cifs_reconnect(server, false);
581586
return true;
582587
}
588+
spin_unlock(&cifs_tcp_ses_lock);
583589

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

627-
if (server->tcpStatus == CifsExiting)
633+
spin_lock(&cifs_tcp_ses_lock);
634+
if (server->tcpStatus == CifsExiting) {
635+
spin_unlock(&cifs_tcp_ses_lock);
628636
return -ESHUTDOWN;
637+
}
629638

630639
if (server->tcpStatus == CifsNeedReconnect) {
640+
spin_unlock(&cifs_tcp_ses_lock);
631641
cifs_reconnect(server, false);
632642
return -ECONNABORTED;
633643
}
644+
spin_unlock(&cifs_tcp_ses_lock);
634645

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

811-
spin_lock(&GlobalMid_Lock);
822+
spin_lock(&cifs_tcp_ses_lock);
812823
server->tcpStatus = CifsExiting;
813-
spin_unlock(&GlobalMid_Lock);
824+
spin_unlock(&cifs_tcp_ses_lock);
814825
wake_up_all(&server->response_q);
815826

816827
/* 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)
14271438
else
14281439
cancel_delayed_work_sync(&server->reconnect);
14291440

1430-
spin_lock(&GlobalMid_Lock);
1441+
spin_lock(&cifs_tcp_ses_lock);
14311442
server->tcpStatus = CifsExiting;
1432-
spin_unlock(&GlobalMid_Lock);
1443+
spin_unlock(&cifs_tcp_ses_lock);
14331444

14341445
cifs_crypto_secmech_release(server);
14351446

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

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

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

1807-
spin_lock(&GlobalMid_Lock);
18081819
if (ses->status == CifsGood)
18091820
ses->status = CifsExiting;
1810-
spin_unlock(&GlobalMid_Lock);
1821+
spin_unlock(&cifs_tcp_ses_lock);
18111822

18121823
cifs_free_ipc(ses);
18131824

@@ -3075,12 +3086,15 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
30753086
* for just this mount.
30763087
*/
30773088
reset_cifs_unix_caps(xid, tcon, cifs_sb, ctx);
3089+
spin_lock(&cifs_tcp_ses_lock);
30783090
if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
30793091
(le64_to_cpu(tcon->fsUnixInfo.Capability) &
30803092
CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
3093+
spin_unlock(&cifs_tcp_ses_lock);
30813094
rc = -EACCES;
30823095
goto out;
30833096
}
3097+
spin_unlock(&cifs_tcp_ses_lock);
30843098
} else
30853099
tcon->unix_ext = 0; /* server does not support them */
30863100

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

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

38603876
rc = server->ops->negotiate(xid, ses, server);
38613877
if (rc == 0) {
3862-
spin_lock(&GlobalMid_Lock);
3878+
spin_lock(&cifs_tcp_ses_lock);
38633879
if (server->tcpStatus == CifsNeedNegotiate)
38643880
server->tcpStatus = CifsGood;
38653881
else
38663882
rc = -EHOSTDOWN;
3867-
spin_unlock(&GlobalMid_Lock);
3883+
spin_unlock(&cifs_tcp_ses_lock);
38683884
}
38693885

38703886
return rc;

fs/cifs/netmisc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,10 +896,10 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
896896
if (class == ERRSRV && code == ERRbaduid) {
897897
cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
898898
code);
899-
spin_lock(&GlobalMid_Lock);
899+
spin_lock(&cifs_tcp_ses_lock);
900900
if (mid->server->tcpStatus != CifsExiting)
901901
mid->server->tcpStatus = CifsNeedReconnect;
902-
spin_unlock(&GlobalMid_Lock);
902+
spin_unlock(&cifs_tcp_ses_lock);
903903
}
904904
}
905905

fs/cifs/sess.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,10 @@ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses)
369369
int i;
370370

371371
for (i = 0; i < ses->chan_count; i++) {
372-
spin_lock(&GlobalMid_Lock);
372+
spin_lock(&cifs_tcp_ses_lock);
373373
if (ses->chans[i].server->tcpStatus != CifsExiting)
374374
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
375-
spin_unlock(&GlobalMid_Lock);
375+
spin_unlock(&cifs_tcp_ses_lock);
376376
}
377377
}
378378

@@ -1052,9 +1052,9 @@ sess_establish_session(struct sess_data *sess_data)
10521052
spin_unlock(&ses->chan_lock);
10531053

10541054
/* Even if one channel is active, session is in good state */
1055-
spin_lock(&GlobalMid_Lock);
1055+
spin_lock(&cifs_tcp_ses_lock);
10561056
ses->status = CifsGood;
1057-
spin_unlock(&GlobalMid_Lock);
1057+
spin_unlock(&cifs_tcp_ses_lock);
10581058

10591059
return 0;
10601060
}

fs/cifs/smb1ops.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
163163
{
164164
__u64 mid = 0;
165165
__u16 last_mid, cur_mid;
166-
bool collision;
166+
bool collision, reconnect;
167167

168168
spin_lock(&GlobalMid_Lock);
169169

@@ -215,7 +215,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
215215
* an eventual reconnect to clean out the pending_mid_q.
216216
*/
217217
if (num_mids > 32768)
218-
server->tcpStatus = CifsNeedReconnect;
218+
reconnect = true;
219219

220220
if (!collision) {
221221
mid = (__u64)cur_mid;
@@ -225,6 +225,13 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
225225
cur_mid++;
226226
}
227227
spin_unlock(&GlobalMid_Lock);
228+
229+
if (reconnect) {
230+
spin_lock(&cifs_tcp_ses_lock);
231+
server->tcpStatus = CifsNeedReconnect;
232+
spin_unlock(&cifs_tcp_ses_lock);
233+
}
234+
228235
return mid;
229236
}
230237

fs/cifs/smb2ops.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,13 @@ smb2_add_credits(struct TCP_Server_Info *server,
121121
optype, scredits, add);
122122
}
123123

124+
spin_lock(&cifs_tcp_ses_lock);
124125
if (server->tcpStatus == CifsNeedReconnect
125-
|| server->tcpStatus == CifsExiting)
126+
|| server->tcpStatus == CifsExiting) {
127+
spin_unlock(&cifs_tcp_ses_lock);
126128
return;
129+
}
130+
spin_unlock(&cifs_tcp_ses_lock);
127131

128132
switch (rc) {
129133
case -1:
@@ -208,11 +212,15 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
208212
return rc;
209213
spin_lock(&server->req_lock);
210214
} else {
215+
spin_unlock(&server->req_lock);
216+
spin_lock(&cifs_tcp_ses_lock);
211217
if (server->tcpStatus == CifsExiting) {
212-
spin_unlock(&server->req_lock);
218+
spin_unlock(&cifs_tcp_ses_lock);
213219
return -ENOENT;
214220
}
221+
spin_unlock(&cifs_tcp_ses_lock);
215222

223+
spin_lock(&server->req_lock);
216224
scredits = server->credits;
217225
/* can deadlock with reopen */
218226
if (scredits <= 8) {
@@ -4983,17 +4991,20 @@ static void smb2_decrypt_offload(struct work_struct *work)
49834991

49844992
mid->callback(mid);
49854993
} else {
4994+
spin_lock(&cifs_tcp_ses_lock);
49864995
spin_lock(&GlobalMid_Lock);
49874996
if (dw->server->tcpStatus == CifsNeedReconnect) {
49884997
mid->mid_state = MID_RETRY_NEEDED;
49894998
spin_unlock(&GlobalMid_Lock);
4999+
spin_unlock(&cifs_tcp_ses_lock);
49905000
mid->callback(mid);
49915001
} else {
49925002
mid->mid_state = MID_REQUEST_SUBMITTED;
49935003
mid->mid_flags &= ~(MID_DELETED);
49945004
list_add_tail(&mid->qhead,
49955005
&dw->server->pending_mid_q);
49965006
spin_unlock(&GlobalMid_Lock);
5007+
spin_unlock(&cifs_tcp_ses_lock);
49975008
}
49985009
}
49995010
cifs_mid_q_entry_release(mid);

0 commit comments

Comments
 (0)