Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Shirish Pargaonkar and committed by
Steve French
7f48558e 3d378d3f

+38 -10
+21 -6
fs/cifs/connect.c
··· 2242 2242 2243 2243 spin_lock(&cifs_tcp_ses_lock); 2244 2244 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 2245 + if (ses->status == CifsExiting) 2246 + continue; 2245 2247 if (!match_session(ses, vol)) 2246 2248 continue; 2247 2249 ++ses->ses_count; ··· 2257 2255 static void 2258 2256 cifs_put_smb_ses(struct cifs_ses *ses) 2259 2257 { 2260 - unsigned int xid; 2258 + unsigned int rc, xid; 2261 2259 struct TCP_Server_Info *server = ses->server; 2262 2260 2263 2261 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); 2262 + 2264 2263 spin_lock(&cifs_tcp_ses_lock); 2264 + if (ses->status == CifsExiting) { 2265 + spin_unlock(&cifs_tcp_ses_lock); 2266 + return; 2267 + } 2265 2268 if (--ses->ses_count > 0) { 2266 2269 spin_unlock(&cifs_tcp_ses_lock); 2267 2270 return; 2268 2271 } 2272 + if (ses->status == CifsGood) 2273 + ses->status = CifsExiting; 2274 + spin_unlock(&cifs_tcp_ses_lock); 2269 2275 2276 + if (ses->status == CifsExiting && server->ops->logoff) { 2277 + xid = get_xid(); 2278 + rc = server->ops->logoff(xid, ses); 2279 + if (rc) 2280 + cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n", 2281 + __func__, rc); 2282 + _free_xid(xid); 2283 + } 2284 + 2285 + spin_lock(&cifs_tcp_ses_lock); 2270 2286 list_del_init(&ses->smb_ses_list); 2271 2287 spin_unlock(&cifs_tcp_ses_lock); 2272 2288 2273 - if (ses->status == CifsGood && server->ops->logoff) { 2274 - xid = get_xid(); 2275 - server->ops->logoff(xid, ses); 2276 - _free_xid(xid); 2277 - } 2278 2289 sesInfoFree(ses); 2279 2290 cifs_put_tcp_session(server); 2280 2291 }
+8 -2
fs/cifs/smb2transport.c
··· 516 516 return -EAGAIN; 517 517 } 518 518 519 - if (ses->status != CifsGood) { 520 - /* check if SMB2 session is bad because we are setting it up */ 519 + if (ses->status == CifsNew) { 521 520 if ((buf->Command != SMB2_SESSION_SETUP) && 522 521 (buf->Command != SMB2_NEGOTIATE)) 523 522 return -EAGAIN; 524 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 532 *mid = smb2_mid_entry_alloc(buf, ses->server); 527 533 if (*mid == NULL) 528 534 return -ENOMEM;
+9 -2
fs/cifs/transport.c
··· 431 431 return -EAGAIN; 432 432 } 433 433 434 - if (ses->status != CifsGood) { 435 - /* check if SMB session is bad because we are setting it up */ 434 + if (ses->status == CifsNew) { 436 435 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 437 436 (in_buf->Command != SMB_COM_NEGOTIATE)) 438 437 return -EAGAIN; 439 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 448 *ppmidQ = AllocMidQEntry(in_buf, ses->server); 442 449 if (*ppmidQ == NULL) 443 450 return -ENOMEM;