diff options
| -rw-r--r-- | fs/cifs/cifsacl.c | 4 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 15 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 2 | ||||
| -rw-r--r-- | fs/cifs/file.c | 43 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 6 |
5 files changed, 31 insertions, 39 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 6941c22398a6..7dfe0842a6f6 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -607,7 +607,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | |||
| 607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); | 607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); |
| 608 | 608 | ||
| 609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); | 609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); |
| 610 | atomic_dec(&open_file->wrtPending); | 610 | cifsFileInfo_put(open_file); |
| 611 | return pntsd; | 611 | return pntsd; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| @@ -665,7 +665,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); | 665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); |
| 666 | 666 | ||
| 667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); | 667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); |
| 668 | atomic_dec(&open_file->wrtPending); | 668 | cifsFileInfo_put(open_file); |
| 669 | return rc; | 669 | return rc; |
| 670 | } | 670 | } |
| 671 | 671 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f100399ee05e..6cfc81a32703 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -351,11 +351,24 @@ struct cifsFileInfo { | |||
| 351 | bool closePend:1; /* file is marked to close */ | 351 | bool closePend:1; /* file is marked to close */ |
| 352 | bool invalidHandle:1; /* file closed via session abend */ | 352 | bool invalidHandle:1; /* file closed via session abend */ |
| 353 | bool messageMode:1; /* for pipes: message vs byte mode */ | 353 | bool messageMode:1; /* for pipes: message vs byte mode */ |
| 354 | atomic_t wrtPending; /* handle in use - defer close */ | 354 | atomic_t count; /* reference count */ |
| 355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
| 356 | struct cifs_search_info srch_inf; | 356 | struct cifs_search_info srch_inf; |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | /* Take a reference on the file private data */ | ||
| 360 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) | ||
| 361 | { | ||
| 362 | atomic_inc(&cifs_file->count); | ||
| 363 | } | ||
| 364 | |||
| 365 | /* Release a reference on the file private data */ | ||
| 366 | static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | ||
| 367 | { | ||
| 368 | if (atomic_dec_and_test(&cifs_file->count)) | ||
| 369 | kfree(cifs_file); | ||
| 370 | } | ||
| 371 | |||
| 359 | /* | 372 | /* |
| 360 | * One of these for each file inode | 373 | * One of these for each file inode |
| 361 | */ | 374 | */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4326ffd90fa9..a6424cfc0121 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -153,7 +153,7 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
| 153 | mutex_init(&pCifsFile->fh_mutex); | 153 | mutex_init(&pCifsFile->fh_mutex); |
| 154 | mutex_init(&pCifsFile->lock_mutex); | 154 | mutex_init(&pCifsFile->lock_mutex); |
| 155 | INIT_LIST_HEAD(&pCifsFile->llist); | 155 | INIT_LIST_HEAD(&pCifsFile->llist); |
| 156 | atomic_set(&pCifsFile->wrtPending, 0); | 156 | atomic_set(&pCifsFile->count, 1); |
| 157 | 157 | ||
| 158 | /* set the following in open now | 158 | /* set the following in open now |
| 159 | pCifsFile->pfile = file; */ | 159 | pCifsFile->pfile = file; */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c34b7f8a217b..fa7beac8b80e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -53,11 +53,9 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
| 53 | private_data->pInode = inode; | 53 | private_data->pInode = inode; |
| 54 | private_data->invalidHandle = false; | 54 | private_data->invalidHandle = false; |
| 55 | private_data->closePend = false; | 55 | private_data->closePend = false; |
| 56 | /* we have to track num writers to the inode, since writepages | 56 | /* Initialize reference count to one. The private data is |
| 57 | does not tell us which handle the write is for so there can | 57 | freed on the release of the last reference */ |
| 58 | be a close (overlapping with write) of the filehandle that | 58 | atomic_set(&private_data->count, 1); |
| 59 | cifs_writepages chose to use */ | ||
| 60 | atomic_set(&private_data->wrtPending, 0); | ||
| 61 | 59 | ||
| 62 | return private_data; | 60 | return private_data; |
| 63 | } | 61 | } |
| @@ -643,7 +641,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 643 | if (!pTcon->need_reconnect) { | 641 | if (!pTcon->need_reconnect) { |
| 644 | write_unlock(&GlobalSMBSeslock); | 642 | write_unlock(&GlobalSMBSeslock); |
| 645 | timeout = 2; | 643 | timeout = 2; |
| 646 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 644 | while ((atomic_read(&pSMBFile->count) != 1) |
| 647 | && (timeout <= 2048)) { | 645 | && (timeout <= 2048)) { |
| 648 | /* Give write a better chance to get to | 646 | /* Give write a better chance to get to |
| 649 | server ahead of the close. We do not | 647 | server ahead of the close. We do not |
| @@ -657,8 +655,6 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 657 | msleep(timeout); | 655 | msleep(timeout); |
| 658 | timeout *= 4; | 656 | timeout *= 4; |
| 659 | } | 657 | } |
| 660 | if (atomic_read(&pSMBFile->wrtPending)) | ||
| 661 | cERROR(1, ("close with pending write")); | ||
| 662 | if (!pTcon->need_reconnect && | 658 | if (!pTcon->need_reconnect && |
| 663 | !pSMBFile->invalidHandle) | 659 | !pSMBFile->invalidHandle) |
| 664 | rc = CIFSSMBClose(xid, pTcon, | 660 | rc = CIFSSMBClose(xid, pTcon, |
| @@ -681,24 +677,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 681 | list_del(&pSMBFile->flist); | 677 | list_del(&pSMBFile->flist); |
| 682 | list_del(&pSMBFile->tlist); | 678 | list_del(&pSMBFile->tlist); |
| 683 | write_unlock(&GlobalSMBSeslock); | 679 | write_unlock(&GlobalSMBSeslock); |
| 684 | timeout = 10; | 680 | cifsFileInfo_put(file->private_data); |
| 685 | /* We waited above to give the SMBWrite a chance to issue | ||
| 686 | on the wire (so we do not get SMBWrite returning EBADF | ||
| 687 | if writepages is racing with close. Note that writepages | ||
| 688 | does not specify a file handle, so it is possible for a file | ||
| 689 | to be opened twice, and the application close the "wrong" | ||
| 690 | file handle - in these cases we delay long enough to allow | ||
| 691 | the SMBWrite to get on the wire before the SMB Close. | ||
| 692 | We allow total wait here over 45 seconds, more than | ||
| 693 | oplock break time, and more than enough to allow any write | ||
| 694 | to complete on the server, or to time out on the client */ | ||
| 695 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | ||
| 696 | && (timeout <= 50000)) { | ||
| 697 | cERROR(1, ("writes pending, delay free of handle")); | ||
| 698 | msleep(timeout); | ||
| 699 | timeout *= 8; | ||
| 700 | } | ||
| 701 | kfree(file->private_data); | ||
| 702 | file->private_data = NULL; | 681 | file->private_data = NULL; |
| 703 | } else | 682 | } else |
| 704 | rc = -EBADF; | 683 | rc = -EBADF; |
| @@ -1236,7 +1215,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
| 1236 | if (!open_file->invalidHandle) { | 1215 | if (!open_file->invalidHandle) { |
| 1237 | /* found a good file */ | 1216 | /* found a good file */ |
| 1238 | /* lock it so it will not be closed on us */ | 1217 | /* lock it so it will not be closed on us */ |
| 1239 | atomic_inc(&open_file->wrtPending); | 1218 | cifsFileInfo_get(open_file); |
| 1240 | read_unlock(&GlobalSMBSeslock); | 1219 | read_unlock(&GlobalSMBSeslock); |
| 1241 | return open_file; | 1220 | return open_file; |
| 1242 | } /* else might as well continue, and look for | 1221 | } /* else might as well continue, and look for |
| @@ -1276,7 +1255,7 @@ refind_writable: | |||
| 1276 | if (open_file->pfile && | 1255 | if (open_file->pfile && |
| 1277 | ((open_file->pfile->f_flags & O_RDWR) || | 1256 | ((open_file->pfile->f_flags & O_RDWR) || |
| 1278 | (open_file->pfile->f_flags & O_WRONLY))) { | 1257 | (open_file->pfile->f_flags & O_WRONLY))) { |
| 1279 | atomic_inc(&open_file->wrtPending); | 1258 | cifsFileInfo_get(open_file); |
| 1280 | 1259 | ||
| 1281 | if (!open_file->invalidHandle) { | 1260 | if (!open_file->invalidHandle) { |
| 1282 | /* found a good writable file */ | 1261 | /* found a good writable file */ |
| @@ -1293,7 +1272,7 @@ refind_writable: | |||
| 1293 | else { /* start over in case this was deleted */ | 1272 | else { /* start over in case this was deleted */ |
| 1294 | /* since the list could be modified */ | 1273 | /* since the list could be modified */ |
| 1295 | read_lock(&GlobalSMBSeslock); | 1274 | read_lock(&GlobalSMBSeslock); |
| 1296 | atomic_dec(&open_file->wrtPending); | 1275 | cifsFileInfo_put(open_file); |
| 1297 | goto refind_writable; | 1276 | goto refind_writable; |
| 1298 | } | 1277 | } |
| 1299 | } | 1278 | } |
| @@ -1309,7 +1288,7 @@ refind_writable: | |||
| 1309 | read_lock(&GlobalSMBSeslock); | 1288 | read_lock(&GlobalSMBSeslock); |
| 1310 | /* can not use this handle, no write | 1289 | /* can not use this handle, no write |
| 1311 | pending on this one after all */ | 1290 | pending on this one after all */ |
| 1312 | atomic_dec(&open_file->wrtPending); | 1291 | cifsFileInfo_put(open_file); |
| 1313 | 1292 | ||
| 1314 | if (open_file->closePend) /* list could have changed */ | 1293 | if (open_file->closePend) /* list could have changed */ |
| 1315 | goto refind_writable; | 1294 | goto refind_writable; |
| @@ -1373,7 +1352,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 1373 | if (open_file) { | 1352 | if (open_file) { |
| 1374 | bytes_written = cifs_write(open_file->pfile, write_data, | 1353 | bytes_written = cifs_write(open_file->pfile, write_data, |
| 1375 | to-from, &offset); | 1354 | to-from, &offset); |
| 1376 | atomic_dec(&open_file->wrtPending); | 1355 | cifsFileInfo_put(open_file); |
| 1377 | /* Does mm or vfs already set times? */ | 1356 | /* Does mm or vfs already set times? */ |
| 1378 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); | 1357 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
| 1379 | if ((bytes_written > 0) && (offset)) | 1358 | if ((bytes_written > 0) && (offset)) |
| @@ -1562,7 +1541,7 @@ retry: | |||
| 1562 | bytes_to_write, offset, | 1541 | bytes_to_write, offset, |
| 1563 | &bytes_written, iov, n_iov, | 1542 | &bytes_written, iov, n_iov, |
| 1564 | long_op); | 1543 | long_op); |
| 1565 | atomic_dec(&open_file->wrtPending); | 1544 | cifsFileInfo_put(open_file); |
| 1566 | cifs_update_eof(cifsi, offset, bytes_written); | 1545 | cifs_update_eof(cifsi, offset, bytes_written); |
| 1567 | 1546 | ||
| 1568 | if (rc || bytes_written < bytes_to_write) { | 1547 | if (rc || bytes_written < bytes_to_write) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 82d83839655e..1f09c7619319 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -800,7 +800,7 @@ set_via_filehandle: | |||
| 800 | if (open_file == NULL) | 800 | if (open_file == NULL) |
| 801 | CIFSSMBClose(xid, pTcon, netfid); | 801 | CIFSSMBClose(xid, pTcon, netfid); |
| 802 | else | 802 | else |
| 803 | atomic_dec(&open_file->wrtPending); | 803 | cifsFileInfo_put(open_file); |
| 804 | out: | 804 | out: |
| 805 | return rc; | 805 | return rc; |
| 806 | } | 806 | } |
| @@ -1635,7 +1635,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
| 1635 | __u32 npid = open_file->pid; | 1635 | __u32 npid = open_file->pid; |
| 1636 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | 1636 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, |
| 1637 | npid, false); | 1637 | npid, false); |
| 1638 | atomic_dec(&open_file->wrtPending); | 1638 | cifsFileInfo_put(open_file); |
| 1639 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | 1639 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); |
| 1640 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 1640 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
| 1641 | unsigned int bytes_written; | 1641 | unsigned int bytes_written; |
| @@ -1790,7 +1790,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1790 | u16 nfid = open_file->netfid; | 1790 | u16 nfid = open_file->netfid; |
| 1791 | u32 npid = open_file->pid; | 1791 | u32 npid = open_file->pid; |
| 1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | 1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); |
| 1793 | atomic_dec(&open_file->wrtPending); | 1793 | cifsFileInfo_put(open_file); |
| 1794 | } else { | 1794 | } else { |
| 1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
| 1796 | cifs_sb->local_nls, | 1796 | cifs_sb->local_nls, |
