Skip to content

Commit ddb4cbf

Browse files
author
Steve French
committed
[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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent bfb5982 commit ddb4cbf

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

fs/cifs/cifsglob.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,15 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
606606
* changes to the tcon->tidStatus should be done while holding this lock.
607607
*/
608608
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;
610618

611619
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
612620

fs/cifs/file.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file)
488488
pTcon = cifs_sb->tcon;
489489
if (pSMBFile) {
490490
struct cifsLockInfo *li, *tmp;
491-
491+
write_lock(&GlobalSMBSeslock);
492492
pSMBFile->closePend = true;
493493
if (pTcon) {
494494
/* no sense reconnecting to close a file that is
495495
already closed */
496496
if (!pTcon->need_reconnect) {
497+
write_unlock(&GlobalSMBSeslock);
497498
timeout = 2;
498499
while ((atomic_read(&pSMBFile->wrtPending) != 0)
499500
&& (timeout <= 2048)) {
@@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file)
510511
timeout *= 4;
511512
}
512513
if (atomic_read(&pSMBFile->wrtPending))
513-
cERROR(1,
514-
("close with pending writes"));
515-
rc = CIFSSMBClose(xid, pTcon,
514+
cERROR(1, ("close with pending write"));
515+
if (!pTcon->need_reconnect &&
516+
!pSMBFile->invalidHandle)
517+
rc = CIFSSMBClose(xid, pTcon,
516518
pSMBFile->netfid);
517-
}
518-
}
519+
} else
520+
write_unlock(&GlobalSMBSeslock);
521+
} else
522+
write_unlock(&GlobalSMBSeslock);
519523

520524
/* Delete any outstanding lock records.
521525
We'll lose them when the file is closed anyway. */
@@ -587,15 +591,18 @@ int cifs_closedir(struct inode *inode, struct file *file)
587591
pTcon = cifs_sb->tcon;
588592

589593
cFYI(1, ("Freeing private data in close dir"));
594+
write_lock(&GlobalSMBSeslock);
590595
if (!pCFileStruct->srch_inf.endOfSearch &&
591596
!pCFileStruct->invalidHandle) {
592597
pCFileStruct->invalidHandle = true;
598+
write_unlock(&GlobalSMBSeslock);
593599
rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
594600
cFYI(1, ("Closing uncompleted readdir with rc %d",
595601
rc));
596602
/* not much we can do if it fails anyway, ignore rc */
597603
rc = 0;
598-
}
604+
} else
605+
write_unlock(&GlobalSMBSeslock);
599606
ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
600607
if (ptmp) {
601608
cFYI(1, ("closedir free smb buf in srch struct"));

fs/cifs/misc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,12 +555,14 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
555555
continue;
556556

557557
cifs_stats_inc(&tcon->num_oplock_brks);
558+
write_lock(&GlobalSMBSeslock);
558559
list_for_each(tmp2, &tcon->openFileList) {
559560
netfile = list_entry(tmp2, struct cifsFileInfo,
560561
tlist);
561562
if (pSMB->Fid != netfile->netfid)
562563
continue;
563564

565+
write_unlock(&GlobalSMBSeslock);
564566
read_unlock(&cifs_tcp_ses_lock);
565567
cFYI(1, ("file id match, oplock break"));
566568
pCifsInode = CIFS_I(netfile->pInode);
@@ -576,6 +578,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
576578

577579
return true;
578580
}
581+
write_unlock(&GlobalSMBSeslock);
579582
read_unlock(&cifs_tcp_ses_lock);
580583
cFYI(1, ("No matching file for oplock break"));
581584
return true;

fs/cifs/readdir.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,11 +741,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
741741
(index_to_find < first_entry_in_buffer)) {
742742
/* close and restart search */
743743
cFYI(1, ("search backing up - close and restart search"));
744+
write_lock(&GlobalSMBSeslock);
744745
if (!cifsFile->srch_inf.endOfSearch &&
745746
!cifsFile->invalidHandle) {
746747
cifsFile->invalidHandle = true;
748+
write_unlock(&GlobalSMBSeslock);
747749
CIFSFindClose(xid, pTcon, cifsFile->netfid);
748-
}
750+
} else
751+
write_unlock(&GlobalSMBSeslock);
749752
if (cifsFile->srch_inf.ntwrk_buf_start) {
750753
cFYI(1, ("freeing SMB ff cache buf on search rewind"));
751754
if (cifsFile->srch_inf.smallBuf)

0 commit comments

Comments
 (0)