diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2012-12-21 06:07:52 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2013-01-02 00:04:14 -0500 |
commit | 88cf75aaaf27a652b3e85960ac3060172dd3edac (patch) | |
tree | 4d9b9f8050a5dce17bcfd0726daec0edceca08b9 /fs | |
parent | ca8aa29c60238720af2ca2a5caab25fa0c70067e (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.c | 48 |
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 | ||
2546 | static struct cifs_readdata * | 2538 | static struct cifs_readdata * |