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