aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-12-21 06:07:52 -0500
committerSteve French <smfrench@gmail.com>2013-01-02 00:04:14 -0500
commit88cf75aaaf27a652b3e85960ac3060172dd3edac (patch)
tree4d9b9f8050a5dce17bcfd0726daec0edceca08b9 /fs
parentca8aa29c60238720af2ca2a5caab25fa0c70067e (diff)
CIFS: Fix write after setting a read lock for read oplock files
If we have a read oplock and set a read lock in it, we can't write to the locked area - so, filemap_fdatawrite may fail with a no information for a userspace application even if we request a write to non-locked area. Fix this by writing directly to the server and then breaking oplock level from level2 to None. Also remove CONFIG_CIFS_SMB2 ifdefs because it's suitable for both CIFS and SMB2 protocols. Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/file.c48
1 files changed, 20 insertions, 28 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1b322d041f1e..22c37254b64e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2505,42 +2505,34 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
2505 struct cifsFileInfo *cfile = (struct cifsFileInfo *) 2505 struct cifsFileInfo *cfile = (struct cifsFileInfo *)
2506 iocb->ki_filp->private_data; 2506 iocb->ki_filp->private_data;
2507 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 2507 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
2508 ssize_t written;
2508 2509
2509#ifdef CONFIG_CIFS_SMB2 2510 if (cinode->clientCanCacheAll) {
2510 /* 2511 if (cap_unix(tcon->ses) &&
2511 * If we have an oplock for read and want to write a data to the file 2512 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
2512 * we need to store it in the page cache and then push it to the server 2513 && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
2513 * to be sure the next read will get a valid data. 2514 return generic_file_aio_write(iocb, iov, nr_segs, pos);
2514 */ 2515 return cifs_writev(iocb, iov, nr_segs, pos);
2515 if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) {
2516 ssize_t written;
2517 int rc;
2518
2519 written = generic_file_aio_write(iocb, iov, nr_segs, pos);
2520 rc = filemap_fdatawrite(inode->i_mapping);
2521 if (rc)
2522 return (ssize_t)rc;
2523
2524 return written;
2525 } 2516 }
2526#endif
2527
2528 /* 2517 /*
2529 * For non-oplocked files in strict cache mode we need to write the data 2518 * For non-oplocked files in strict cache mode we need to write the data
2530 * to the server exactly from the pos to pos+len-1 rather than flush all 2519 * to the server exactly from the pos to pos+len-1 rather than flush all
2531 * affected pages because it may cause a error with mandatory locks on 2520 * affected pages because it may cause a error with mandatory locks on
2532 * these pages but not on the region from pos to ppos+len-1. 2521 * these pages but not on the region from pos to ppos+len-1.
2533 */ 2522 */
2534 2523 written = cifs_user_writev(iocb, iov, nr_segs, pos);
2535 if (!cinode->clientCanCacheAll) 2524 if (written > 0 && cinode->clientCanCacheRead) {
2536 return cifs_user_writev(iocb, iov, nr_segs, pos); 2525 /*
2537 2526 * Windows 7 server can delay breaking level2 oplock if a write
2538 if (cap_unix(tcon->ses) && 2527 * request comes - break it on the client to prevent reading
2539 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 2528 * an old data.
2540 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 2529 */
2541 return generic_file_aio_write(iocb, iov, nr_segs, pos); 2530 cifs_invalidate_mapping(inode);
2542 2531 cFYI(1, "Set no oplock for inode=%p after a write operation",
2543 return cifs_writev(iocb, iov, nr_segs, pos); 2532 inode);
2533 cinode->clientCanCacheRead = false;
2534 }
2535 return written;
2544} 2536}
2545 2537
2546static struct cifs_readdata * 2538static struct cifs_readdata *