[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>
This commit is contained in:
Steve French 2008-11-20 20:00:44 +00:00
parent bfb59820ee
commit ddb4cbfc53
4 changed files with 30 additions and 9 deletions

View 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. * changes to the tcon->tidStatus should be done while holding this lock.
*/ */
GLOBAL_EXTERN rwlock_t cifs_tcp_ses_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; GLOBAL_EXTERN struct list_head GlobalOplock_Q;

View File

@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (pSMBFile) { if (pSMBFile) {
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
write_lock(&GlobalSMBSeslock);
pSMBFile->closePend = true; pSMBFile->closePend = true;
if (pTcon) { if (pTcon) {
/* no sense reconnecting to close a file that is /* no sense reconnecting to close a file that is
already closed */ already closed */
if (!pTcon->need_reconnect) { if (!pTcon->need_reconnect) {
write_unlock(&GlobalSMBSeslock);
timeout = 2; timeout = 2;
while ((atomic_read(&pSMBFile->wrtPending) != 0) while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout <= 2048)) { && (timeout <= 2048)) {
@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file)
timeout *= 4; timeout *= 4;
} }
if (atomic_read(&pSMBFile->wrtPending)) if (atomic_read(&pSMBFile->wrtPending))
cERROR(1, cERROR(1, ("close with pending write"));
("close with pending writes")); if (!pTcon->need_reconnect &&
rc = CIFSSMBClose(xid, pTcon, !pSMBFile->invalidHandle)
rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid); pSMBFile->netfid);
} } else
} write_unlock(&GlobalSMBSeslock);
} else
write_unlock(&GlobalSMBSeslock);
/* Delete any outstanding lock records. /* Delete any outstanding lock records.
We'll lose them when the file is closed anyway. */ 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; pTcon = cifs_sb->tcon;
cFYI(1, ("Freeing private data in close dir")); cFYI(1, ("Freeing private data in close dir"));
write_lock(&GlobalSMBSeslock);
if (!pCFileStruct->srch_inf.endOfSearch && if (!pCFileStruct->srch_inf.endOfSearch &&
!pCFileStruct->invalidHandle) { !pCFileStruct->invalidHandle) {
pCFileStruct->invalidHandle = true; pCFileStruct->invalidHandle = true;
write_unlock(&GlobalSMBSeslock);
rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
cFYI(1, ("Closing uncompleted readdir with rc %d", cFYI(1, ("Closing uncompleted readdir with rc %d",
rc)); rc));
/* not much we can do if it fails anyway, ignore rc */ /* not much we can do if it fails anyway, ignore rc */
rc = 0; rc = 0;
} } else
write_unlock(&GlobalSMBSeslock);
ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
if (ptmp) { if (ptmp) {
cFYI(1, ("closedir free smb buf in srch struct")); cFYI(1, ("closedir free smb buf in srch struct"));

View File

@ -555,12 +555,14 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
continue; continue;
cifs_stats_inc(&tcon->num_oplock_brks); cifs_stats_inc(&tcon->num_oplock_brks);
write_lock(&GlobalSMBSeslock);
list_for_each(tmp2, &tcon->openFileList) { list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo, netfile = list_entry(tmp2, struct cifsFileInfo,
tlist); tlist);
if (pSMB->Fid != netfile->netfid) if (pSMB->Fid != netfile->netfid)
continue; continue;
write_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock); read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("file id match, oplock break")); cFYI(1, ("file id match, oplock break"));
pCifsInode = CIFS_I(netfile->pInode); pCifsInode = CIFS_I(netfile->pInode);
@ -576,6 +578,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return true; return true;
} }
write_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock); read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("No matching file for oplock break")); cFYI(1, ("No matching file for oplock break"));
return true; return true;

View File

@ -741,11 +741,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
(index_to_find < first_entry_in_buffer)) { (index_to_find < first_entry_in_buffer)) {
/* close and restart search */ /* close and restart search */
cFYI(1, ("search backing up - close and restart search")); cFYI(1, ("search backing up - close and restart search"));
write_lock(&GlobalSMBSeslock);
if (!cifsFile->srch_inf.endOfSearch && if (!cifsFile->srch_inf.endOfSearch &&
!cifsFile->invalidHandle) { !cifsFile->invalidHandle) {
cifsFile->invalidHandle = true; cifsFile->invalidHandle = true;
write_unlock(&GlobalSMBSeslock);
CIFSFindClose(xid, pTcon, cifsFile->netfid); CIFSFindClose(xid, pTcon, cifsFile->netfid);
} } else
write_unlock(&GlobalSMBSeslock);
if (cifsFile->srch_inf.ntwrk_buf_start) { if (cifsFile->srch_inf.ntwrk_buf_start) {
cFYI(1, ("freeing SMB ff cache buf on search rewind")); cFYI(1, ("freeing SMB ff cache buf on search rewind"));
if (cifsFile->srch_inf.smallBuf) if (cifsFile->srch_inf.smallBuf)