diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 86 |
1 files changed, 66 insertions, 20 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 894b1f7b299d..1e7e4c06d9e3 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,12 +522,30 @@ 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; |
528 | } else | 545 | } else |
529 | rc = -EBADF; | 546 | rc = -EBADF; |
530 | 547 | ||
548 | read_lock(&GlobalSMBSeslock); | ||
531 | if (list_empty(&(CIFS_I(inode)->openFileList))) { | 549 | if (list_empty(&(CIFS_I(inode)->openFileList))) { |
532 | cFYI(1, ("closing last open instance for inode %p", inode)); | 550 | cFYI(1, ("closing last open instance for inode %p", inode)); |
533 | /* if the file is not open we do not know if we can cache info | 551 | /* if the file is not open we do not know if we can cache info |
@@ -535,6 +553,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
535 | CIFS_I(inode)->clientCanCacheRead = FALSE; | 553 | CIFS_I(inode)->clientCanCacheRead = FALSE; |
536 | CIFS_I(inode)->clientCanCacheAll = FALSE; | 554 | CIFS_I(inode)->clientCanCacheAll = FALSE; |
537 | } | 555 | } |
556 | read_unlock(&GlobalSMBSeslock); | ||
538 | if ((rc == 0) && CIFS_I(inode)->write_behind_rc) | 557 | if ((rc == 0) && CIFS_I(inode)->write_behind_rc) |
539 | rc = CIFS_I(inode)->write_behind_rc; | 558 | rc = CIFS_I(inode)->write_behind_rc; |
540 | FreeXid(xid); | 559 | FreeXid(xid); |
@@ -767,7 +786,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
767 | mutex_lock(&fid->lock_mutex); | 786 | mutex_lock(&fid->lock_mutex); |
768 | list_for_each_entry_safe(li, tmp, &fid->llist, llist) { | 787 | list_for_each_entry_safe(li, tmp, &fid->llist, llist) { |
769 | if (pfLock->fl_start <= li->offset && | 788 | if (pfLock->fl_start <= li->offset && |
770 | length >= li->length) { | 789 | (pfLock->fl_start + length) >= |
790 | (li->offset + li->length)) { | ||
771 | stored_rc = CIFSSMBLock(xid, pTcon, | 791 | stored_rc = CIFSSMBLock(xid, pTcon, |
772 | netfid, | 792 | netfid, |
773 | li->length, li->offset, | 793 | li->length, li->offset, |
@@ -1022,6 +1042,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | |||
1022 | } | 1042 | } |
1023 | 1043 | ||
1024 | read_lock(&GlobalSMBSeslock); | 1044 | read_lock(&GlobalSMBSeslock); |
1045 | refind_writable: | ||
1025 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1046 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1026 | if (open_file->closePend) | 1047 | if (open_file->closePend) |
1027 | continue; | 1048 | continue; |
@@ -1029,24 +1050,49 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | |||
1029 | ((open_file->pfile->f_flags & O_RDWR) || | 1050 | ((open_file->pfile->f_flags & O_RDWR) || |
1030 | (open_file->pfile->f_flags & O_WRONLY))) { | 1051 | (open_file->pfile->f_flags & O_WRONLY))) { |
1031 | atomic_inc(&open_file->wrtPending); | 1052 | atomic_inc(&open_file->wrtPending); |
1053 | |||
1054 | if (!open_file->invalidHandle) { | ||
1055 | /* found a good writable file */ | ||
1056 | read_unlock(&GlobalSMBSeslock); | ||
1057 | return open_file; | ||
1058 | } | ||
1059 | |||
1032 | read_unlock(&GlobalSMBSeslock); | 1060 | read_unlock(&GlobalSMBSeslock); |
1033 | if ((open_file->invalidHandle) && | 1061 | /* Had to unlock since following call can block */ |
1034 | (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { | 1062 | rc = cifs_reopen_file(open_file->pfile, FALSE); |
1035 | rc = cifs_reopen_file(open_file->pfile, FALSE); | 1063 | if (!rc) { |
1036 | /* if it fails, try another handle - might be */ | 1064 | if (!open_file->closePend) |
1037 | /* dangerous to hold up writepages with retry */ | 1065 | return open_file; |
1038 | if (rc) { | 1066 | else { /* start over in case this was deleted */ |
1039 | cFYI(1, | 1067 | /* since the list could be modified */ |
1040 | ("failed on reopen file in wp")); | ||
1041 | read_lock(&GlobalSMBSeslock); | 1068 | read_lock(&GlobalSMBSeslock); |
1042 | /* can not use this handle, no write | 1069 | atomic_dec(&open_file->wrtPending); |
1043 | pending on this one after all */ | 1070 | goto refind_writable; |
1044 | atomic_dec | ||
1045 | (&open_file->wrtPending); | ||
1046 | continue; | ||
1047 | } | 1071 | } |
1048 | } | 1072 | } |
1049 | return open_file; | 1073 | |
1074 | /* if it fails, try another handle if possible - | ||
1075 | (we can not do this if closePending since | ||
1076 | loop could be modified - in which case we | ||
1077 | have to start at the beginning of the list | ||
1078 | again. Note that it would be bad | ||
1079 | to hold up writepages here (rather than | ||
1080 | in caller) with continuous retries */ | ||
1081 | cFYI(1, ("wp failed on reopen file")); | ||
1082 | read_lock(&GlobalSMBSeslock); | ||
1083 | /* can not use this handle, no write | ||
1084 | pending on this one after all */ | ||
1085 | atomic_dec(&open_file->wrtPending); | ||
1086 | |||
1087 | if (open_file->closePend) /* list could have changed */ | ||
1088 | goto refind_writable; | ||
1089 | /* else we simply continue to the next entry. Thus | ||
1090 | we do not loop on reopen errors. If we | ||
1091 | can not reopen the file, for example if we | ||
1092 | reconnected to a server with another client | ||
1093 | racing to delete or lock the file we would not | ||
1094 | make progress if we restarted before the beginning | ||
1095 | of the loop here. */ | ||
1050 | } | 1096 | } |
1051 | } | 1097 | } |
1052 | read_unlock(&GlobalSMBSeslock); | 1098 | read_unlock(&GlobalSMBSeslock); |
@@ -1709,7 +1755,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1709 | struct page *page; | 1755 | struct page *page; |
1710 | struct cifs_sb_info *cifs_sb; | 1756 | struct cifs_sb_info *cifs_sb; |
1711 | struct cifsTconInfo *pTcon; | 1757 | struct cifsTconInfo *pTcon; |
1712 | int bytes_read = 0; | 1758 | unsigned int bytes_read = 0; |
1713 | unsigned int read_size, i; | 1759 | unsigned int read_size, i; |
1714 | char *smb_read_data = NULL; | 1760 | char *smb_read_data = NULL; |
1715 | struct smb_com_read_rsp *pSMBr; | 1761 | struct smb_com_read_rsp *pSMBr; |
@@ -1803,7 +1849,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1803 | 1849 | ||
1804 | i += bytes_read >> PAGE_CACHE_SHIFT; | 1850 | i += bytes_read >> PAGE_CACHE_SHIFT; |
1805 | cifs_stats_bytes_read(pTcon, bytes_read); | 1851 | cifs_stats_bytes_read(pTcon, bytes_read); |
1806 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | 1852 | if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) { |
1807 | i++; /* account for partial page */ | 1853 | i++; /* account for partial page */ |
1808 | 1854 | ||
1809 | /* server copy of file can have smaller size | 1855 | /* server copy of file can have smaller size |