aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-11-20 15:00:44 -0500
committerSteve French <sfrench@us.ibm.com>2008-11-20 15:14:13 -0500
commitddb4cbfc53aa0913ee8da059fcbf628d14f40f63 (patch)
treed77a2d510fa3a3b6556052af024355ed5cfc43d8 /fs/cifs
parentbfb59820ee46616a7bdb4af6b8f7e109646de6ec (diff)
[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>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/file.c21
-rw-r--r--fs/cifs/misc.c3
-rw-r--r--fs/cifs/readdir.c5
4 files changed, 30 insertions, 9 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index f1ae1f57c30d..c57c0565547f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -606,7 +606,15 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
606 * changes to the tcon->tidStatus should be done while holding this lock. 606 * changes to the tcon->tidStatus should be done while holding this lock.
607 */ 607 */
608GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 608GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
609GLOBAL_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 */
617GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
610 618
611GLOBAL_EXTERN struct list_head GlobalOplock_Q; 619GLOBAL_EXTERN struct list_head GlobalOplock_Q;
612 620
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6449e1aae621..b691b893a848 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file)
488 pTcon = cifs_sb->tcon; 488 pTcon = cifs_sb->tcon;
489 if (pSMBFile) { 489 if (pSMBFile) {
490 struct cifsLockInfo *li, *tmp; 490 struct cifsLockInfo *li, *tmp;
491 491 write_lock(&GlobalSMBSeslock);
492 pSMBFile->closePend = true; 492 pSMBFile->closePend = true;
493 if (pTcon) { 493 if (pTcon) {
494 /* no sense reconnecting to close a file that is 494 /* no sense reconnecting to close a file that is
495 already closed */ 495 already closed */
496 if (!pTcon->need_reconnect) { 496 if (!pTcon->need_reconnect) {
497 write_unlock(&GlobalSMBSeslock);
497 timeout = 2; 498 timeout = 2;
498 while ((atomic_read(&pSMBFile->wrtPending) != 0) 499 while ((atomic_read(&pSMBFile->wrtPending) != 0)
499 && (timeout <= 2048)) { 500 && (timeout <= 2048)) {
@@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file)
510 timeout *= 4; 511 timeout *= 4;
511 } 512 }
512 if (atomic_read(&pSMBFile->wrtPending)) 513 if (atomic_read(&pSMBFile->wrtPending))
513 cERROR(1, 514 cERROR(1, ("close with pending write"));
514 ("close with pending writes")); 515 if (!pTcon->need_reconnect &&
515 rc = CIFSSMBClose(xid, pTcon, 516 !pSMBFile->invalidHandle)
517 rc = CIFSSMBClose(xid, pTcon,
516 pSMBFile->netfid); 518 pSMBFile->netfid);
517 } 519 } else
518 } 520 write_unlock(&GlobalSMBSeslock);
521 } else
522 write_unlock(&GlobalSMBSeslock);
519 523
520 /* Delete any outstanding lock records. 524 /* Delete any outstanding lock records.
521 We'll lose them when the file is closed anyway. */ 525 We'll lose them when the file is closed anyway. */
@@ -587,15 +591,18 @@ int cifs_closedir(struct inode *inode, struct file *file)
587 pTcon = cifs_sb->tcon; 591 pTcon = cifs_sb->tcon;
588 592
589 cFYI(1, ("Freeing private data in close dir")); 593 cFYI(1, ("Freeing private data in close dir"));
594 write_lock(&GlobalSMBSeslock);
590 if (!pCFileStruct->srch_inf.endOfSearch && 595 if (!pCFileStruct->srch_inf.endOfSearch &&
591 !pCFileStruct->invalidHandle) { 596 !pCFileStruct->invalidHandle) {
592 pCFileStruct->invalidHandle = true; 597 pCFileStruct->invalidHandle = true;
598 write_unlock(&GlobalSMBSeslock);
593 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); 599 rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
594 cFYI(1, ("Closing uncompleted readdir with rc %d", 600 cFYI(1, ("Closing uncompleted readdir with rc %d",
595 rc)); 601 rc));
596 /* not much we can do if it fails anyway, ignore rc */ 602 /* not much we can do if it fails anyway, ignore rc */
597 rc = 0; 603 rc = 0;
598 } 604 } else
605 write_unlock(&GlobalSMBSeslock);
599 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; 606 ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
600 if (ptmp) { 607 if (ptmp) {
601 cFYI(1, ("closedir free smb buf in srch struct")); 608 cFYI(1, ("closedir free smb buf in srch struct"));
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index addd1dcc2d79..9ee3f689c2b0 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -555,12 +555,14 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
555 continue; 555 continue;
556 556
557 cifs_stats_inc(&tcon->num_oplock_brks); 557 cifs_stats_inc(&tcon->num_oplock_brks);
558 write_lock(&GlobalSMBSeslock);
558 list_for_each(tmp2, &tcon->openFileList) { 559 list_for_each(tmp2, &tcon->openFileList) {
559 netfile = list_entry(tmp2, struct cifsFileInfo, 560 netfile = list_entry(tmp2, struct cifsFileInfo,
560 tlist); 561 tlist);
561 if (pSMB->Fid != netfile->netfid) 562 if (pSMB->Fid != netfile->netfid)
562 continue; 563 continue;
563 564
565 write_unlock(&GlobalSMBSeslock);
564 read_unlock(&cifs_tcp_ses_lock); 566 read_unlock(&cifs_tcp_ses_lock);
565 cFYI(1, ("file id match, oplock break")); 567 cFYI(1, ("file id match, oplock break"));
566 pCifsInode = CIFS_I(netfile->pInode); 568 pCifsInode = CIFS_I(netfile->pInode);
@@ -576,6 +578,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
576 578
577 return true; 579 return true;
578 } 580 }
581 write_unlock(&GlobalSMBSeslock);
579 read_unlock(&cifs_tcp_ses_lock); 582 read_unlock(&cifs_tcp_ses_lock);
580 cFYI(1, ("No matching file for oplock break")); 583 cFYI(1, ("No matching file for oplock break"));
581 return true; 584 return true;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 58d57299f2a0..9f51f9bf0292 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -741,11 +741,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
741 (index_to_find < first_entry_in_buffer)) { 741 (index_to_find < first_entry_in_buffer)) {
742 /* close and restart search */ 742 /* close and restart search */
743 cFYI(1, ("search backing up - close and restart search")); 743 cFYI(1, ("search backing up - close and restart search"));
744 write_lock(&GlobalSMBSeslock);
744 if (!cifsFile->srch_inf.endOfSearch && 745 if (!cifsFile->srch_inf.endOfSearch &&
745 !cifsFile->invalidHandle) { 746 !cifsFile->invalidHandle) {
746 cifsFile->invalidHandle = true; 747 cifsFile->invalidHandle = true;
748 write_unlock(&GlobalSMBSeslock);
747 CIFSFindClose(xid, pTcon, cifsFile->netfid); 749 CIFSFindClose(xid, pTcon, cifsFile->netfid);
748 } 750 } else
751 write_unlock(&GlobalSMBSeslock);
749 if (cifsFile->srch_inf.ntwrk_buf_start) { 752 if (cifsFile->srch_inf.ntwrk_buf_start) {
750 cFYI(1, ("freeing SMB ff cache buf on search rewind")); 753 cFYI(1, ("freeing SMB ff cache buf on search rewind"));
751 if (cifsFile->srch_inf.smallBuf) 754 if (cifsFile->srch_inf.smallBuf)