aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2013-10-12 11:06:03 -0400
committerSteve French <smfrench@gmail.com>2013-11-02 13:52:35 -0400
commit7f48558e6489d032b1584b0cc9ac4bb11072c034 (patch)
tree54c6b7529085229d53cae09cada37d548f848f26
parent3d378d3fd82a759d59c60d89b4559bf325d7e668 (diff)
cifs: Send a logoff request before removing a smb session
Send a smb session logoff request before removing smb session off of the list. On a signed smb session, remvoing a session off of the list before sending a logoff request results in server returning an error for lack of smb signature. Never seen an error during smb logoff, so as per MS-SMB2 3.2.5.1, not sure how an error during logoff should be retried. So for now, if a server returns an error to a logoff request, log the error and remove the session off of the list. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/connect.c25
-rw-r--r--fs/cifs/smb2transport.c10
-rw-r--r--fs/cifs/transport.c11
3 files changed, 37 insertions, 9 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a279ffc0bc29..62a55147400a 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2242,6 +2242,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2242 2242
2243 spin_lock(&cifs_tcp_ses_lock); 2243 spin_lock(&cifs_tcp_ses_lock);
2244 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 2244 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
2245 if (ses->status == CifsExiting)
2246 continue;
2245 if (!match_session(ses, vol)) 2247 if (!match_session(ses, vol))
2246 continue; 2248 continue;
2247 ++ses->ses_count; 2249 ++ses->ses_count;
@@ -2255,24 +2257,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2255static void 2257static void
2256cifs_put_smb_ses(struct cifs_ses *ses) 2258cifs_put_smb_ses(struct cifs_ses *ses)
2257{ 2259{
2258 unsigned int xid; 2260 unsigned int rc, xid;
2259 struct TCP_Server_Info *server = ses->server; 2261 struct TCP_Server_Info *server = ses->server;
2260 2262
2261 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); 2263 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
2264
2262 spin_lock(&cifs_tcp_ses_lock); 2265 spin_lock(&cifs_tcp_ses_lock);
2266 if (ses->status == CifsExiting) {
2267 spin_unlock(&cifs_tcp_ses_lock);
2268 return;
2269 }
2263 if (--ses->ses_count > 0) { 2270 if (--ses->ses_count > 0) {
2264 spin_unlock(&cifs_tcp_ses_lock); 2271 spin_unlock(&cifs_tcp_ses_lock);
2265 return; 2272 return;
2266 } 2273 }
2267 2274 if (ses->status == CifsGood)
2268 list_del_init(&ses->smb_ses_list); 2275 ses->status = CifsExiting;
2269 spin_unlock(&cifs_tcp_ses_lock); 2276 spin_unlock(&cifs_tcp_ses_lock);
2270 2277
2271 if (ses->status == CifsGood && server->ops->logoff) { 2278 if (ses->status == CifsExiting && server->ops->logoff) {
2272 xid = get_xid(); 2279 xid = get_xid();
2273 server->ops->logoff(xid, ses); 2280 rc = server->ops->logoff(xid, ses);
2281 if (rc)
2282 cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
2283 __func__, rc);
2274 _free_xid(xid); 2284 _free_xid(xid);
2275 } 2285 }
2286
2287 spin_lock(&cifs_tcp_ses_lock);
2288 list_del_init(&ses->smb_ses_list);
2289 spin_unlock(&cifs_tcp_ses_lock);
2290
2276 sesInfoFree(ses); 2291 sesInfoFree(ses);
2277 cifs_put_tcp_session(server); 2292 cifs_put_tcp_session(server);
2278} 2293}
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index c523617eade2..59c748ce872f 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
516 return -EAGAIN; 516 return -EAGAIN;
517 } 517 }
518 518
519 if (ses->status != CifsGood) { 519 if (ses->status == CifsNew) {
520 /* check if SMB2 session is bad because we are setting it up */
521 if ((buf->Command != SMB2_SESSION_SETUP) && 520 if ((buf->Command != SMB2_SESSION_SETUP) &&
522 (buf->Command != SMB2_NEGOTIATE)) 521 (buf->Command != SMB2_NEGOTIATE))
523 return -EAGAIN; 522 return -EAGAIN;
524 /* else ok - we are setting up session */ 523 /* else ok - we are setting up session */
525 } 524 }
525
526 if (ses->status == CifsExiting) {
527 if (buf->Command != SMB2_LOGOFF)
528 return -EAGAIN;
529 /* else ok - we are shutting down the session */
530 }
531
526 *mid = smb2_mid_entry_alloc(buf, ses->server); 532 *mid = smb2_mid_entry_alloc(buf, ses->server);
527 if (*mid == NULL) 533 if (*mid == NULL)
528 return -ENOMEM; 534 return -ENOMEM;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0ee6d249ef6f..b37570952846 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -431,13 +431,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
431 return -EAGAIN; 431 return -EAGAIN;
432 } 432 }
433 433
434 if (ses->status != CifsGood) { 434 if (ses->status == CifsNew) {
435 /* check if SMB session is bad because we are setting it up */
436 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 435 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
437 (in_buf->Command != SMB_COM_NEGOTIATE)) 436 (in_buf->Command != SMB_COM_NEGOTIATE))
438 return -EAGAIN; 437 return -EAGAIN;
439 /* else ok - we are setting up session */ 438 /* else ok - we are setting up session */
440 } 439 }
440
441 if (ses->status == CifsExiting) {
442 /* check if SMB session is bad because we are setting it up */
443 if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
444 return -EAGAIN;
445 /* else ok - we are shutting down session */
446 }
447
441 *ppmidQ = AllocMidQEntry(in_buf, ses->server); 448 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
442 if (*ppmidQ == NULL) 449 if (*ppmidQ == NULL)
443 return -ENOMEM; 450 return -ENOMEM;