aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-09-07 18:23:48 -0400
committerSteve French <sfrench@us.ibm.com>2007-09-07 18:23:48 -0400
commit15745320f374aa6cbfe4836b76469159c0f49640 (patch)
tree13da65b37dce287fb5be8977e1830f4fde7a0a7e /fs
parent77159b4df894f9e5e31f709fb0e5e52f6c1b1048 (diff)
[CIFS] Fix oops in find_writable_file
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/file.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 26fa50858aac..b1807fd1ac40 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -467,7 +467,7 @@ reopen_error_exit:
467int cifs_close(struct inode *inode, struct file *file) 467int cifs_close(struct inode *inode, struct file *file)
468{ 468{
469 int rc = 0; 469 int rc = 0;
470 int xid; 470 int xid, timeout;
471 struct cifs_sb_info *cifs_sb; 471 struct cifs_sb_info *cifs_sb;
472 struct cifsTconInfo *pTcon; 472 struct cifsTconInfo *pTcon;
473 struct cifsFileInfo *pSMBFile = 473 struct cifsFileInfo *pSMBFile =
@@ -485,9 +485,9 @@ int cifs_close(struct inode *inode, struct file *file)
485 /* no sense reconnecting to close a file that is 485 /* no sense reconnecting to close a file that is
486 already closed */ 486 already closed */
487 if (pTcon->tidStatus != CifsNeedReconnect) { 487 if (pTcon->tidStatus != CifsNeedReconnect) {
488 int timeout = 2; 488 timeout = 2;
489 while ((atomic_read(&pSMBFile->wrtPending) != 0) 489 while ((atomic_read(&pSMBFile->wrtPending) != 0)
490 && (timeout < 1000) ) { 490 && (timeout <= 2048)) {
491 /* Give write a better chance to get to 491 /* Give write a better chance to get to
492 server ahead of the close. We do not 492 server ahead of the close. We do not
493 want to add a wait_q here as it would 493 want to add a wait_q here as it would
@@ -522,6 +522,23 @@ int cifs_close(struct inode *inode, struct file *file)
522 list_del(&pSMBFile->flist); 522 list_del(&pSMBFile->flist);
523 list_del(&pSMBFile->tlist); 523 list_del(&pSMBFile->tlist);
524 write_unlock(&GlobalSMBSeslock); 524 write_unlock(&GlobalSMBSeslock);
525 timeout = 10;
526 /* We waited above to give the SMBWrite a chance to issue
527 on the wire (so we do not get SMBWrite returning EBADF
528 if writepages is racing with close. Note that writepages
529 does not specify a file handle, so it is possible for a file
530 to be opened twice, and the application close the "wrong"
531 file handle - in these cases we delay long enough to allow
532 the SMBWrite to get on the wire before the SMB Close.
533 We allow total wait here over 45 seconds, more than
534 oplock break time, and more than enough to allow any write
535 to complete on the server, or to time out on the client */
536 while ((atomic_read(&pSMBFile->wrtPending) != 0)
537 && (timeout <= 50000)) {
538 cERROR(1, ("writes pending, delay free of handle"));
539 msleep(timeout);
540 timeout *= 8;
541 }
525 kfree(pSMBFile->search_resume_name); 542 kfree(pSMBFile->search_resume_name);
526 kfree(file->private_data); 543 kfree(file->private_data);
527 file->private_data = NULL; 544 file->private_data = NULL;
@@ -1031,22 +1048,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
1031 (open_file->pfile->f_flags & O_WRONLY))) { 1048 (open_file->pfile->f_flags & O_WRONLY))) {
1032 atomic_inc(&open_file->wrtPending); 1049 atomic_inc(&open_file->wrtPending);
1033 read_unlock(&GlobalSMBSeslock); 1050 read_unlock(&GlobalSMBSeslock);
1034 if ((open_file->invalidHandle) && 1051 if (open_file->invalidHandle) {
1035 (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
1036 rc = cifs_reopen_file(open_file->pfile, FALSE); 1052 rc = cifs_reopen_file(open_file->pfile, FALSE);
1037 /* if it fails, try another handle - might be */ 1053 /* if it fails, try another handle - might be */
1038 /* dangerous to hold up writepages with retry */ 1054 /* dangerous to hold up writepages with retry */
1039 if (rc) { 1055 if (rc) {
1040 cFYI(1, 1056 cFYI(1, ("wp failed on reopen file"));
1041 ("failed on reopen file in wp"));
1042 read_lock(&GlobalSMBSeslock); 1057 read_lock(&GlobalSMBSeslock);
1043 /* can not use this handle, no write 1058 /* can not use this handle, no write
1044 pending on this one after all */ 1059 pending on this one after all */
1045 atomic_dec 1060 atomic_dec(&open_file->wrtPending);
1046 (&open_file->wrtPending);
1047 continue; 1061 continue;
1048 } 1062 }
1049 } 1063 }
1064 if (open_file->closePend) {
1065 read_lock(&GlobalSMBSeslock);
1066 atomic_dec(&open_file->wrtPending);
1067 continue;
1068 }
1050 return open_file; 1069 return open_file;
1051 } 1070 }
1052 } 1071 }