diff options
author | Steve French <sfrench@us.ibm.com> | 2007-09-07 18:23:48 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-09-07 18:23:48 -0400 |
commit | 15745320f374aa6cbfe4836b76469159c0f49640 (patch) | |
tree | 13da65b37dce287fb5be8977e1830f4fde7a0a7e /fs/cifs/file.c | |
parent | 77159b4df894f9e5e31f709fb0e5e52f6c1b1048 (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/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 37 |
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: | |||
467 | int cifs_close(struct inode *inode, struct file *file) | 467 | int 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 | } |