[CIFS] Do not attempt to close invalidated file handles
authorSteve French <sfrench@us.ibm.com>
Thu, 20 Nov 2008 20:00:44 +0000 (20:00 +0000)
committerSteve French <sfrench@us.ibm.com>
Thu, 20 Nov 2008 20:14:13 +0000 (20:14 +0000)
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>
fs/cifs/cifsglob.h
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/readdir.c

index f1ae1f57c30dcbfd86de17dcbb46bcc9c3991e71..c57c0565547fa99058e9a192796123a419309066 100644 (file)
@@ -606,7 +606,15 @@ GLOBAL_EXTERN struct list_head             cifs_tcp_ses_list;
  * changes to the tcon->tidStatus should be done while holding this lock.
  */
 GLOBAL_EXTERN rwlock_t         cifs_tcp_ses_lock;
-GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
+
+/*
+ * This lock protects the cifs_file->llist and cifs_file->flist
+ * list operations, and updates to some flags (cifs_file->invalidHandle)
+ * It will be moved to either use the tcon->stat_lock or equivalent later.
+ * If cifs_tcp_ses_lock and the lock below are both needed to be held, then
+ * the cifs_tcp_ses_lock must be grabbed first and released last.
+ */
+GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
 
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
index 6449e1aae621aa2721a1f5a5bd12338ac2890b6c..b691b893a848a8d4d74c1e0ecce800d561b99b67 100644 (file)
@@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file)
        pTcon = cifs_sb->tcon;
        if (pSMBFile) {
                struct cifsLockInfo *li, *tmp;
-
+               write_lock(&GlobalSMBSeslock);
                pSMBFile->closePend = true;
                if (pTcon) {
                        /* no sense reconnecting to close a file that is
                           already closed */
                        if (!pTcon->need_reconnect) {
+                               write_unlock(&GlobalSMBSeslock);
                                timeout = 2;
                                while ((atomic_read(&pSMBFile->wrtPending) != 0)
                                        && (timeout <= 2048)) {
@@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file)
                                        timeout *= 4;
                                }
                                if (atomic_read(&pSMBFile->wrtPending))
-                                       cERROR(1,
-                                               ("close with pending writes"));
-                               rc = CIFSSMBClose(xid, pTcon,
+                                       cERROR(1, ("close with pending write"));
+                               if (!pTcon->need_reconnect &&
+                                   !pSMBFile->invalidHandle)
+                                       rc = CIFSSMBClose(xid, pTcon,
                                                  pSMBFile->netfid);
-                       }
-               }
+                       } else
+                               write_unlock(&GlobalSMBSeslock);
+               } else
+                       write_unlock(&GlobalSMBSeslock);
 
                /* Delete any outstanding lock records.
                   We'll lose them when the file is closed anyway. */
@@ -587,15 +591,18 @@ int cifs_closedir(struct inode *inode, struct file *file)
                pTcon = cifs_sb->tcon;
 
                cFYI(1, ("Freeing private data in close dir"));
+               write_lock(&GlobalSMBSeslock);
                if (!pCFileStruct->srch_inf.endOfSearch &&
                    !pCFileStruct->invalidHandle) {
                        pCFileStruct->invalidHandle = true;
+                       write_unlock(&GlobalSMBSeslock);
                        rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
                        cFYI(1, ("Closing uncompleted readdir with rc %d",
                                 rc));
                        /* not much we can do if it fails anyway, ignore rc */
                        rc = 0;
-               }
+               } else
+                       write_unlock(&GlobalSMBSeslock);
                ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
                if (ptmp) {
                        cFYI(1, ("closedir free smb buf in srch struct"));
index addd1dcc2d79513ab6404e6a530d6927cbe71eee..9ee3f689c2b0c0f78468082658d0aad8cf56791c 100644 (file)
@@ -555,12 +555,14 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                                continue;
 
                        cifs_stats_inc(&tcon->num_oplock_brks);
+                       write_lock(&GlobalSMBSeslock);
                        list_for_each(tmp2, &tcon->openFileList) {
                                netfile = list_entry(tmp2, struct cifsFileInfo,
                                                     tlist);
                                if (pSMB->Fid != netfile->netfid)
                                        continue;
 
+                               write_unlock(&GlobalSMBSeslock);
                                read_unlock(&cifs_tcp_ses_lock);
                                cFYI(1, ("file id match, oplock break"));
                                pCifsInode = CIFS_I(netfile->pInode);
@@ -576,6 +578,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                return true;
                        }
+                       write_unlock(&GlobalSMBSeslock);
                        read_unlock(&cifs_tcp_ses_lock);
                        cFYI(1, ("No matching file for oplock break"));
                        return true;
index 58d57299f2a08c432625f9be298e731e2fa7bae0..9f51f9bf0292f4a67aee9ca82aae2f6d3b6cc5d0 100644 (file)
@@ -741,11 +741,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
           (index_to_find < first_entry_in_buffer)) {
                /* close and restart search */
                cFYI(1, ("search backing up - close and restart search"));
+               write_lock(&GlobalSMBSeslock);
                if (!cifsFile->srch_inf.endOfSearch &&
                    !cifsFile->invalidHandle) {
                        cifsFile->invalidHandle = true;
+                       write_unlock(&GlobalSMBSeslock);
                        CIFSFindClose(xid, pTcon, cifsFile->netfid);
-               }
+               } else
+                       write_unlock(&GlobalSMBSeslock);
                if (cifsFile->srch_inf.ntwrk_buf_start) {
                        cFYI(1, ("freeing SMB ff cache buf on search rewind"));
                        if (cifsFile->srch_inf.smallBuf)