[CIFS] Do not attempt to close invalidated file handles

If a connection with open file handles has gone down
and come back up and reconnected without reopening
the file handle yet, do not attempt to send an SMB close
request for this handle in cifs_close. We were
checking for the connection being invalid in cifs_close
but since the connection may have been reconnected
we also need to check whether the file handle
was marked invalid (otherwise we could close the
wrong file handle by accident).

Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

+30 -9
+9 -1
fs/cifs/cifsglob.h
··· 606 * changes to the tcon->tidStatus should be done while holding this lock. 607 */ 608 GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 609 - GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 610 611 GLOBAL_EXTERN struct list_head GlobalOplock_Q; 612
··· 606 * changes to the tcon->tidStatus should be done while holding this lock. 607 */ 608 GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 609 + 610 + /* 611 + * This lock protects the cifs_file->llist and cifs_file->flist 612 + * list operations, and updates to some flags (cifs_file->invalidHandle) 613 + * It will be moved to either use the tcon->stat_lock or equivalent later. 614 + * If cifs_tcp_ses_lock and the lock below are both needed to be held, then 615 + * the cifs_tcp_ses_lock must be grabbed first and released last. 616 + */ 617 + GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; 618 619 GLOBAL_EXTERN struct list_head GlobalOplock_Q; 620
+14 -7
fs/cifs/file.c
··· 488 pTcon = cifs_sb->tcon; 489 if (pSMBFile) { 490 struct cifsLockInfo *li, *tmp; 491 - 492 pSMBFile->closePend = true; 493 if (pTcon) { 494 /* no sense reconnecting to close a file that is 495 already closed */ 496 if (!pTcon->need_reconnect) { 497 timeout = 2; 498 while ((atomic_read(&pSMBFile->wrtPending) != 0) 499 && (timeout <= 2048)) { ··· 511 timeout *= 4; 512 } 513 if (atomic_read(&pSMBFile->wrtPending)) 514 - cERROR(1, 515 - ("close with pending writes")); 516 - rc = CIFSSMBClose(xid, pTcon, 517 pSMBFile->netfid); 518 - } 519 - } 520 521 /* Delete any outstanding lock records. 522 We'll lose them when the file is closed anyway. */ ··· 591 pTcon = cifs_sb->tcon; 592 593 cFYI(1, ("Freeing private data in close dir")); 594 if (!pCFileStruct->srch_inf.endOfSearch && 595 !pCFileStruct->invalidHandle) { 596 pCFileStruct->invalidHandle = true; 597 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); 598 cFYI(1, ("Closing uncompleted readdir with rc %d", 599 rc)); 600 /* not much we can do if it fails anyway, ignore rc */ 601 rc = 0; 602 - } 603 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; 604 if (ptmp) { 605 cFYI(1, ("closedir free smb buf in srch struct"));
··· 488 pTcon = cifs_sb->tcon; 489 if (pSMBFile) { 490 struct cifsLockInfo *li, *tmp; 491 + write_lock(&GlobalSMBSeslock); 492 pSMBFile->closePend = true; 493 if (pTcon) { 494 /* no sense reconnecting to close a file that is 495 already closed */ 496 if (!pTcon->need_reconnect) { 497 + write_unlock(&GlobalSMBSeslock); 498 timeout = 2; 499 while ((atomic_read(&pSMBFile->wrtPending) != 0) 500 && (timeout <= 2048)) { ··· 510 timeout *= 4; 511 } 512 if (atomic_read(&pSMBFile->wrtPending)) 513 + cERROR(1, ("close with pending write")); 514 + if (!pTcon->need_reconnect && 515 + !pSMBFile->invalidHandle) 516 + rc = CIFSSMBClose(xid, pTcon, 517 pSMBFile->netfid); 518 + } else 519 + write_unlock(&GlobalSMBSeslock); 520 + } else 521 + write_unlock(&GlobalSMBSeslock); 522 523 /* Delete any outstanding lock records. 524 We'll lose them when the file is closed anyway. */ ··· 587 pTcon = cifs_sb->tcon; 588 589 cFYI(1, ("Freeing private data in close dir")); 590 + write_lock(&GlobalSMBSeslock); 591 if (!pCFileStruct->srch_inf.endOfSearch && 592 !pCFileStruct->invalidHandle) { 593 pCFileStruct->invalidHandle = true; 594 + write_unlock(&GlobalSMBSeslock); 595 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); 596 cFYI(1, ("Closing uncompleted readdir with rc %d", 597 rc)); 598 /* not much we can do if it fails anyway, ignore rc */ 599 rc = 0; 600 + } else 601 + write_unlock(&GlobalSMBSeslock); 602 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; 603 if (ptmp) { 604 cFYI(1, ("closedir free smb buf in srch struct"));
+3
fs/cifs/misc.c
··· 555 continue; 556 557 cifs_stats_inc(&tcon->num_oplock_brks); 558 list_for_each(tmp2, &tcon->openFileList) { 559 netfile = list_entry(tmp2, struct cifsFileInfo, 560 tlist); 561 if (pSMB->Fid != netfile->netfid) 562 continue; 563 564 read_unlock(&cifs_tcp_ses_lock); 565 cFYI(1, ("file id match, oplock break")); 566 pCifsInode = CIFS_I(netfile->pInode); ··· 578 579 return true; 580 } 581 read_unlock(&cifs_tcp_ses_lock); 582 cFYI(1, ("No matching file for oplock break")); 583 return true;
··· 555 continue; 556 557 cifs_stats_inc(&tcon->num_oplock_brks); 558 + write_lock(&GlobalSMBSeslock); 559 list_for_each(tmp2, &tcon->openFileList) { 560 netfile = list_entry(tmp2, struct cifsFileInfo, 561 tlist); 562 if (pSMB->Fid != netfile->netfid) 563 continue; 564 565 + write_unlock(&GlobalSMBSeslock); 566 read_unlock(&cifs_tcp_ses_lock); 567 cFYI(1, ("file id match, oplock break")); 568 pCifsInode = CIFS_I(netfile->pInode); ··· 576 577 return true; 578 } 579 + write_unlock(&GlobalSMBSeslock); 580 read_unlock(&cifs_tcp_ses_lock); 581 cFYI(1, ("No matching file for oplock break")); 582 return true;
+4 -1
fs/cifs/readdir.c
··· 741 (index_to_find < first_entry_in_buffer)) { 742 /* close and restart search */ 743 cFYI(1, ("search backing up - close and restart search")); 744 if (!cifsFile->srch_inf.endOfSearch && 745 !cifsFile->invalidHandle) { 746 cifsFile->invalidHandle = true; 747 CIFSFindClose(xid, pTcon, cifsFile->netfid); 748 - } 749 if (cifsFile->srch_inf.ntwrk_buf_start) { 750 cFYI(1, ("freeing SMB ff cache buf on search rewind")); 751 if (cifsFile->srch_inf.smallBuf)
··· 741 (index_to_find < first_entry_in_buffer)) { 742 /* close and restart search */ 743 cFYI(1, ("search backing up - close and restart search")); 744 + write_lock(&GlobalSMBSeslock); 745 if (!cifsFile->srch_inf.endOfSearch && 746 !cifsFile->invalidHandle) { 747 cifsFile->invalidHandle = true; 748 + write_unlock(&GlobalSMBSeslock); 749 CIFSFindClose(xid, pTcon, cifsFile->netfid); 750 + } else 751 + write_unlock(&GlobalSMBSeslock); 752 if (cifsFile->srch_inf.ntwrk_buf_start) { 753 cFYI(1, ("freeing SMB ff cache buf on search rewind")); 754 if (cifsFile->srch_inf.smallBuf)