提交 88cf75aa 编写于 作者: P Pavel Shilovsky 提交者: Steve French

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: NPavel Shilovsky <piastry@etersoft.ru>
Reviewed-by: NJeff Layton <jlayton@redhat.com>
Signed-off-by: NSteve French <smfrench@gmail.com>
上级 ca8aa29c
...@@ -2505,42 +2505,34 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, ...@@ -2505,42 +2505,34 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
struct cifsFileInfo *cfile = (struct cifsFileInfo *) struct cifsFileInfo *cfile = (struct cifsFileInfo *)
iocb->ki_filp->private_data; iocb->ki_filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
#ifdef CONFIG_CIFS_SMB2
/*
* If we have an oplock for read and want to write a data to the file
* we need to store it in the page cache and then push it to the server
* to be sure the next read will get a valid data.
*/
if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) {
ssize_t written; ssize_t written;
int rc;
written = generic_file_aio_write(iocb, iov, nr_segs, pos);
rc = filemap_fdatawrite(inode->i_mapping);
if (rc)
return (ssize_t)rc;
return written; if (cinode->clientCanCacheAll) {
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
&& ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
return generic_file_aio_write(iocb, iov, nr_segs, pos);
return cifs_writev(iocb, iov, nr_segs, pos);
} }
#endif
/* /*
* For non-oplocked files in strict cache mode we need to write the data * For non-oplocked files in strict cache mode we need to write the data
* to the server exactly from the pos to pos+len-1 rather than flush all * to the server exactly from the pos to pos+len-1 rather than flush all
* affected pages because it may cause a error with mandatory locks on * affected pages because it may cause a error with mandatory locks on
* these pages but not on the region from pos to ppos+len-1. * these pages but not on the region from pos to ppos+len-1.
*/ */
written = cifs_user_writev(iocb, iov, nr_segs, pos);
if (!cinode->clientCanCacheAll) if (written > 0 && cinode->clientCanCacheRead) {
return cifs_user_writev(iocb, iov, nr_segs, pos); /*
* Windows 7 server can delay breaking level2 oplock if a write
if (cap_unix(tcon->ses) && * request comes - break it on the client to prevent reading
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && * an old data.
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) */
return generic_file_aio_write(iocb, iov, nr_segs, pos); cifs_invalidate_mapping(inode);
cFYI(1, "Set no oplock for inode=%p after a write operation",
return cifs_writev(iocb, iov, nr_segs, pos); inode);
cinode->clientCanCacheRead = false;
}
return written;
} }
static struct cifs_readdata * static struct cifs_readdata *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册