Skip to content

Commit

Permalink
[CIFS] Fix oops in find_writable_file
Browse files Browse the repository at this point in the history
There was a case in which find_writable_file was not waiting long enough
under heavy stress when writepages was racing with close of the file
handle being used by the write.

Signed-off-by: Steve French <sfrench@us.ibm.com>
  • Loading branch information
Steve French committed Sep 7, 2007
1 parent 77159b4 commit 1574532
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ static int cifs_reopen_file(struct file *file, int can_flush)
int cifs_close(struct inode *inode, struct file *file)
{
int rc = 0;
int xid;
int xid, timeout;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct cifsFileInfo *pSMBFile =
Expand All @@ -485,9 +485,9 @@ int cifs_close(struct inode *inode, struct file *file)
/* no sense reconnecting to close a file that is
already closed */
if (pTcon->tidStatus != CifsNeedReconnect) {
int timeout = 2;
timeout = 2;
while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout < 1000) ) {
&& (timeout <= 2048)) {
/* Give write a better chance to get to
server ahead of the close. We do not
want to add a wait_q here as it would
Expand Down Expand Up @@ -522,6 +522,23 @@ int cifs_close(struct inode *inode, struct file *file)
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
write_unlock(&GlobalSMBSeslock);
timeout = 10;
/* We waited above to give the SMBWrite a chance to issue
on the wire (so we do not get SMBWrite returning EBADF
if writepages is racing with close. Note that writepages
does not specify a file handle, so it is possible for a file
to be opened twice, and the application close the "wrong"
file handle - in these cases we delay long enough to allow
the SMBWrite to get on the wire before the SMB Close.
We allow total wait here over 45 seconds, more than
oplock break time, and more than enough to allow any write
to complete on the server, or to time out on the client */
while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout <= 50000)) {
cERROR(1, ("writes pending, delay free of handle"));
msleep(timeout);
timeout *= 8;
}
kfree(pSMBFile->search_resume_name);
kfree(file->private_data);
file->private_data = NULL;
Expand Down Expand Up @@ -1031,22 +1048,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
(open_file->pfile->f_flags & O_WRONLY))) {
atomic_inc(&open_file->wrtPending);
read_unlock(&GlobalSMBSeslock);
if ((open_file->invalidHandle) &&
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
if (open_file->invalidHandle) {
rc = cifs_reopen_file(open_file->pfile, FALSE);
/* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */
if (rc) {
cFYI(1,
("failed on reopen file in wp"));
cFYI(1, ("wp failed on reopen file"));
read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write
pending on this one after all */
atomic_dec
(&open_file->wrtPending);
atomic_dec(&open_file->wrtPending);
continue;
}
}
if (open_file->closePend) {
read_lock(&GlobalSMBSeslock);
atomic_dec(&open_file->wrtPending);
continue;
}
return open_file;
}
}
Expand Down

0 comments on commit 1574532

Please sign in to comment.