diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 187 | ||||
-rw-r--r-- | fs/cifs/misc.c | 10 |
3 files changed, 60 insertions, 138 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 28337cba0295..3365e77f6f24 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -393,7 +393,6 @@ struct cifsFileInfo { | |||
393 | struct tcon_link *tlink; | 393 | struct tcon_link *tlink; |
394 | struct mutex lock_mutex; | 394 | struct mutex lock_mutex; |
395 | struct list_head llist; /* list of byte range locks we have. */ | 395 | struct list_head llist; /* list of byte range locks we have. */ |
396 | bool closePend:1; /* file is marked to close */ | ||
397 | bool invalidHandle:1; /* file closed via session abend */ | 396 | bool invalidHandle:1; /* file closed via session abend */ |
398 | bool oplock_break_cancelled:1; | 397 | bool oplock_break_cancelled:1; |
399 | atomic_t count; /* reference count */ | 398 | atomic_t count; /* reference count */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index a3634e43bd4f..8c81e7b14d53 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -238,7 +238,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
238 | pCifsFile->dentry = dget(dentry); | 238 | pCifsFile->dentry = dget(dentry); |
239 | pCifsFile->f_flags = file->f_flags; | 239 | pCifsFile->f_flags = file->f_flags; |
240 | pCifsFile->invalidHandle = false; | 240 | pCifsFile->invalidHandle = false; |
241 | pCifsFile->closePend = false; | ||
242 | pCifsFile->tlink = cifs_get_tlink(tlink); | 241 | pCifsFile->tlink = cifs_get_tlink(tlink); |
243 | mutex_init(&pCifsFile->fh_mutex); | 242 | mutex_init(&pCifsFile->fh_mutex); |
244 | mutex_init(&pCifsFile->lock_mutex); | 243 | mutex_init(&pCifsFile->lock_mutex); |
@@ -266,14 +265,55 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
266 | return pCifsFile; | 265 | return pCifsFile; |
267 | } | 266 | } |
268 | 267 | ||
269 | /* Release a reference on the file private data */ | 268 | /* |
269 | * Release a reference on the file private data. This may involve closing | ||
270 | * the filehandle out on the server. | ||
271 | */ | ||
270 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | 272 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) |
271 | { | 273 | { |
272 | if (atomic_dec_and_test(&cifs_file->count)) { | 274 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); |
273 | cifs_put_tlink(cifs_file->tlink); | 275 | struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode); |
274 | dput(cifs_file->dentry); | 276 | struct cifsLockInfo *li, *tmp; |
275 | kfree(cifs_file); | 277 | |
278 | spin_lock(&cifs_file_list_lock); | ||
279 | if (!atomic_dec_and_test(&cifs_file->count)) { | ||
280 | spin_unlock(&cifs_file_list_lock); | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | /* remove it from the lists */ | ||
285 | list_del(&cifs_file->flist); | ||
286 | list_del(&cifs_file->tlist); | ||
287 | |||
288 | if (list_empty(&cifsi->openFileList)) { | ||
289 | cFYI(1, "closing last open instance for inode %p", | ||
290 | cifs_file->dentry->d_inode); | ||
291 | cifsi->clientCanCacheRead = false; | ||
292 | cifsi->clientCanCacheAll = false; | ||
293 | } | ||
294 | spin_unlock(&cifs_file_list_lock); | ||
295 | |||
296 | if (!tcon->need_reconnect && !cifs_file->invalidHandle) { | ||
297 | int xid, rc; | ||
298 | |||
299 | xid = GetXid(); | ||
300 | rc = CIFSSMBClose(xid, tcon, cifs_file->netfid); | ||
301 | FreeXid(xid); | ||
302 | } | ||
303 | |||
304 | /* Delete any outstanding lock records. We'll lose them when the file | ||
305 | * is closed anyway. | ||
306 | */ | ||
307 | mutex_lock(&cifs_file->lock_mutex); | ||
308 | list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) { | ||
309 | list_del(&li->llist); | ||
310 | kfree(li); | ||
276 | } | 311 | } |
312 | mutex_unlock(&cifs_file->lock_mutex); | ||
313 | |||
314 | cifs_put_tlink(cifs_file->tlink); | ||
315 | dput(cifs_file->dentry); | ||
316 | kfree(cifs_file); | ||
277 | } | 317 | } |
278 | 318 | ||
279 | int cifs_open(struct inode *inode, struct file *file) | 319 | int cifs_open(struct inode *inode, struct file *file) |
@@ -605,79 +645,11 @@ reopen_error_exit: | |||
605 | 645 | ||
606 | int cifs_close(struct inode *inode, struct file *file) | 646 | int cifs_close(struct inode *inode, struct file *file) |
607 | { | 647 | { |
608 | int rc = 0; | 648 | cifsFileInfo_put(file->private_data); |
609 | int xid, timeout; | 649 | file->private_data = NULL; |
610 | struct cifs_sb_info *cifs_sb; | ||
611 | struct cifsTconInfo *pTcon; | ||
612 | struct cifsFileInfo *pSMBFile = file->private_data; | ||
613 | |||
614 | xid = GetXid(); | ||
615 | |||
616 | cifs_sb = CIFS_SB(inode->i_sb); | ||
617 | pTcon = tlink_tcon(pSMBFile->tlink); | ||
618 | if (pSMBFile) { | ||
619 | struct cifsLockInfo *li, *tmp; | ||
620 | spin_lock(&cifs_file_list_lock); | ||
621 | pSMBFile->closePend = true; | ||
622 | if (pTcon) { | ||
623 | /* no sense reconnecting to close a file that is | ||
624 | already closed */ | ||
625 | if (!pTcon->need_reconnect) { | ||
626 | spin_unlock(&cifs_file_list_lock); | ||
627 | timeout = 2; | ||
628 | while ((atomic_read(&pSMBFile->count) != 1) | ||
629 | && (timeout <= 2048)) { | ||
630 | /* Give write a better chance to get to | ||
631 | server ahead of the close. We do not | ||
632 | want to add a wait_q here as it would | ||
633 | increase the memory utilization as | ||
634 | the struct would be in each open file, | ||
635 | but this should give enough time to | ||
636 | clear the socket */ | ||
637 | cFYI(DBG2, "close delay, write pending"); | ||
638 | msleep(timeout); | ||
639 | timeout *= 4; | ||
640 | } | ||
641 | if (!pTcon->need_reconnect && | ||
642 | !pSMBFile->invalidHandle) | ||
643 | rc = CIFSSMBClose(xid, pTcon, | ||
644 | pSMBFile->netfid); | ||
645 | } else | ||
646 | spin_unlock(&cifs_file_list_lock); | ||
647 | } else | ||
648 | spin_unlock(&cifs_file_list_lock); | ||
649 | |||
650 | /* Delete any outstanding lock records. | ||
651 | We'll lose them when the file is closed anyway. */ | ||
652 | mutex_lock(&pSMBFile->lock_mutex); | ||
653 | list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { | ||
654 | list_del(&li->llist); | ||
655 | kfree(li); | ||
656 | } | ||
657 | mutex_unlock(&pSMBFile->lock_mutex); | ||
658 | 650 | ||
659 | spin_lock(&cifs_file_list_lock); | 651 | /* return code from the ->release op is always ignored */ |
660 | list_del(&pSMBFile->flist); | 652 | return 0; |
661 | list_del(&pSMBFile->tlist); | ||
662 | spin_unlock(&cifs_file_list_lock); | ||
663 | cifsFileInfo_put(file->private_data); | ||
664 | file->private_data = NULL; | ||
665 | } else | ||
666 | rc = -EBADF; | ||
667 | |||
668 | spin_lock(&cifs_file_list_lock); | ||
669 | if (list_empty(&(CIFS_I(inode)->openFileList))) { | ||
670 | cFYI(1, "closing last open instance for inode %p", inode); | ||
671 | /* if the file is not open we do not know if we can cache info | ||
672 | on this inode, much less write behind and read ahead */ | ||
673 | CIFS_I(inode)->clientCanCacheRead = false; | ||
674 | CIFS_I(inode)->clientCanCacheAll = false; | ||
675 | } | ||
676 | spin_unlock(&cifs_file_list_lock); | ||
677 | if ((rc == 0) && CIFS_I(inode)->write_behind_rc) | ||
678 | rc = CIFS_I(inode)->write_behind_rc; | ||
679 | FreeXid(xid); | ||
680 | return rc; | ||
681 | } | 653 | } |
682 | 654 | ||
683 | int cifs_closedir(struct inode *inode, struct file *file) | 655 | int cifs_closedir(struct inode *inode, struct file *file) |
@@ -1024,13 +996,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
1024 | we blocked so return what we managed to write */ | 996 | we blocked so return what we managed to write */ |
1025 | return total_written; | 997 | return total_written; |
1026 | } | 998 | } |
1027 | if (open_file->closePend) { | ||
1028 | FreeXid(xid); | ||
1029 | if (total_written) | ||
1030 | return total_written; | ||
1031 | else | ||
1032 | return -EBADF; | ||
1033 | } | ||
1034 | if (open_file->invalidHandle) { | 999 | if (open_file->invalidHandle) { |
1035 | /* we could deadlock if we called | 1000 | /* we could deadlock if we called |
1036 | filemap_fdatawait from here so tell | 1001 | filemap_fdatawait from here so tell |
@@ -1111,13 +1076,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
1111 | total_written += bytes_written) { | 1076 | total_written += bytes_written) { |
1112 | rc = -EAGAIN; | 1077 | rc = -EAGAIN; |
1113 | while (rc == -EAGAIN) { | 1078 | while (rc == -EAGAIN) { |
1114 | if (open_file->closePend) { | ||
1115 | FreeXid(xid); | ||
1116 | if (total_written) | ||
1117 | return total_written; | ||
1118 | else | ||
1119 | return -EBADF; | ||
1120 | } | ||
1121 | if (open_file->invalidHandle) { | 1079 | if (open_file->invalidHandle) { |
1122 | /* we could deadlock if we called | 1080 | /* we could deadlock if we called |
1123 | filemap_fdatawait from here so tell | 1081 | filemap_fdatawait from here so tell |
@@ -1197,8 +1155,6 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1197 | are always at the end of the list but since the first entry might | 1155 | are always at the end of the list but since the first entry might |
1198 | have a close pending, we go through the whole list */ | 1156 | have a close pending, we go through the whole list */ |
1199 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1157 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1200 | if (open_file->closePend) | ||
1201 | continue; | ||
1202 | if (fsuid_only && open_file->uid != current_fsuid()) | 1158 | if (fsuid_only && open_file->uid != current_fsuid()) |
1203 | continue; | 1159 | continue; |
1204 | if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { | 1160 | if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { |
@@ -1244,8 +1200,6 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1244 | spin_lock(&cifs_file_list_lock); | 1200 | spin_lock(&cifs_file_list_lock); |
1245 | refind_writable: | 1201 | refind_writable: |
1246 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1202 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1247 | if (open_file->closePend) | ||
1248 | continue; | ||
1249 | if (!any_available && open_file->pid != current->tgid) | 1203 | if (!any_available && open_file->pid != current->tgid) |
1250 | continue; | 1204 | continue; |
1251 | if (fsuid_only && open_file->uid != current_fsuid()) | 1205 | if (fsuid_only && open_file->uid != current_fsuid()) |
@@ -1260,34 +1214,18 @@ refind_writable: | |||
1260 | } | 1214 | } |
1261 | 1215 | ||
1262 | spin_unlock(&cifs_file_list_lock); | 1216 | spin_unlock(&cifs_file_list_lock); |
1217 | |||
1263 | /* Had to unlock since following call can block */ | 1218 | /* Had to unlock since following call can block */ |
1264 | rc = cifs_reopen_file(open_file, false); | 1219 | rc = cifs_reopen_file(open_file, false); |
1265 | if (!rc) { | 1220 | if (!rc) |
1266 | if (!open_file->closePend) | 1221 | return open_file; |
1267 | return open_file; | ||
1268 | else { /* start over in case this was deleted */ | ||
1269 | /* since the list could be modified */ | ||
1270 | spin_lock(&cifs_file_list_lock); | ||
1271 | cifsFileInfo_put(open_file); | ||
1272 | goto refind_writable; | ||
1273 | } | ||
1274 | } | ||
1275 | 1222 | ||
1276 | /* if it fails, try another handle if possible - | 1223 | /* if it fails, try another handle if possible */ |
1277 | (we can not do this if closePending since | ||
1278 | loop could be modified - in which case we | ||
1279 | have to start at the beginning of the list | ||
1280 | again. Note that it would be bad | ||
1281 | to hold up writepages here (rather than | ||
1282 | in caller) with continuous retries */ | ||
1283 | cFYI(1, "wp failed on reopen file"); | 1224 | cFYI(1, "wp failed on reopen file"); |
1284 | spin_lock(&cifs_file_list_lock); | ||
1285 | /* can not use this handle, no write | ||
1286 | pending on this one after all */ | ||
1287 | cifsFileInfo_put(open_file); | 1225 | cifsFileInfo_put(open_file); |
1288 | 1226 | ||
1289 | if (open_file->closePend) /* list could have changed */ | 1227 | spin_lock(&cifs_file_list_lock); |
1290 | goto refind_writable; | 1228 | |
1291 | /* else we simply continue to the next entry. Thus | 1229 | /* else we simply continue to the next entry. Thus |
1292 | we do not loop on reopen errors. If we | 1230 | we do not loop on reopen errors. If we |
1293 | can not reopen the file, for example if we | 1231 | can not reopen the file, for example if we |
@@ -1808,8 +1746,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1808 | smb_read_data = NULL; | 1746 | smb_read_data = NULL; |
1809 | while (rc == -EAGAIN) { | 1747 | while (rc == -EAGAIN) { |
1810 | int buf_type = CIFS_NO_BUFFER; | 1748 | int buf_type = CIFS_NO_BUFFER; |
1811 | if ((open_file->invalidHandle) && | 1749 | if (open_file->invalidHandle) { |
1812 | (!open_file->closePend)) { | ||
1813 | rc = cifs_reopen_file(open_file, true); | 1750 | rc = cifs_reopen_file(open_file, true); |
1814 | if (rc != 0) | 1751 | if (rc != 0) |
1815 | break; | 1752 | break; |
@@ -1894,8 +1831,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1894 | } | 1831 | } |
1895 | rc = -EAGAIN; | 1832 | rc = -EAGAIN; |
1896 | while (rc == -EAGAIN) { | 1833 | while (rc == -EAGAIN) { |
1897 | if ((open_file->invalidHandle) && | 1834 | if (open_file->invalidHandle) { |
1898 | (!open_file->closePend)) { | ||
1899 | rc = cifs_reopen_file(open_file, true); | 1835 | rc = cifs_reopen_file(open_file, true); |
1900 | if (rc != 0) | 1836 | if (rc != 0) |
1901 | break; | 1837 | break; |
@@ -2059,8 +1995,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2059 | read_size, contig_pages); | 1995 | read_size, contig_pages); |
2060 | rc = -EAGAIN; | 1996 | rc = -EAGAIN; |
2061 | while (rc == -EAGAIN) { | 1997 | while (rc == -EAGAIN) { |
2062 | if ((open_file->invalidHandle) && | 1998 | if (open_file->invalidHandle) { |
2063 | (!open_file->closePend)) { | ||
2064 | rc = cifs_reopen_file(open_file, true); | 1999 | rc = cifs_reopen_file(open_file, true); |
2065 | if (rc != 0) | 2000 | if (rc != 0) |
2066 | break; | 2001 | break; |
@@ -2212,8 +2147,6 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode) | |||
2212 | 2147 | ||
2213 | spin_lock(&cifs_file_list_lock); | 2148 | spin_lock(&cifs_file_list_lock); |
2214 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 2149 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
2215 | if (open_file->closePend) | ||
2216 | continue; | ||
2217 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { | 2150 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
2218 | spin_unlock(&cifs_file_list_lock); | 2151 | spin_unlock(&cifs_file_list_lock); |
2219 | return 1; | 2152 | return 1; |
@@ -2372,7 +2305,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
2372 | * not bother sending an oplock release if session to server still is | 2305 | * not bother sending an oplock release if session to server still is |
2373 | * disconnected since oplock already released by the server | 2306 | * disconnected since oplock already released by the server |
2374 | */ | 2307 | */ |
2375 | if (!cfile->closePend && !cfile->oplock_break_cancelled) { | 2308 | if (!cfile->oplock_break_cancelled) { |
2376 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, | 2309 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, |
2377 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); | 2310 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); |
2378 | cFYI(1, "Oplock release rc = %d", rc); | 2311 | cFYI(1, "Oplock release rc = %d", rc); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index a7b492c213cd..1c681f6a6803 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -567,16 +567,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
567 | if (pSMB->Fid != netfile->netfid) | 567 | if (pSMB->Fid != netfile->netfid) |
568 | continue; | 568 | continue; |
569 | 569 | ||
570 | /* | ||
571 | * don't do anything if file is about to be | ||
572 | * closed anyway. | ||
573 | */ | ||
574 | if (netfile->closePend) { | ||
575 | spin_unlock(&cifs_file_list_lock); | ||
576 | spin_unlock(&cifs_tcp_ses_lock); | ||
577 | return true; | ||
578 | } | ||
579 | |||
580 | cFYI(1, "file id match, oplock break"); | 570 | cFYI(1, "file id match, oplock break"); |
581 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
582 | pCifsInode->clientCanCacheAll = false; | 572 | pCifsInode->clientCanCacheAll = false; |