aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-12-06 13:07:52 -0500
committerSteve French <smfrench@gmail.com>2012-12-11 12:48:50 -0500
commitc299dd0e2d3dd61d0048a9d9b021aa01f023ed0c (patch)
tree5d3f913eea056a57b2d7086742f2d55b7d78c6f4 /fs/cifs
parentd387a5c50bca619d56f276a69627c2e1c6e5c548 (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 populating the page cache without marking affected pages dirty after a successful write directly to the server. Also remove CONFIG_CIFS_SMB2 ifdefs because it's suitable for both CIFS and SMB2 protocols. Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/file.c94
3 files changed, 65 insertions, 31 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c6e32f22fbd3..210f0af83fc4 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -229,6 +229,7 @@ cifs_alloc_inode(struct super_block *sb)
229 cifs_set_oplock_level(cifs_inode, 0); 229 cifs_set_oplock_level(cifs_inode, 0);
230 cifs_inode->delete_pending = false; 230 cifs_inode->delete_pending = false;
231 cifs_inode->invalid_mapping = false; 231 cifs_inode->invalid_mapping = false;
232 cifs_inode->leave_pages_clean = false;
232 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 233 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
233 cifs_inode->server_eof = 0; 234 cifs_inode->server_eof = 0;
234 cifs_inode->uniqueid = 0; 235 cifs_inode->uniqueid = 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index dfab450a191e..aea1eec64911 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1030,6 +1030,7 @@ struct cifsInodeInfo {
1030 bool clientCanCacheAll; /* read and writebehind oplock */ 1030 bool clientCanCacheAll; /* read and writebehind oplock */
1031 bool delete_pending; /* DELETE_ON_CLOSE is set */ 1031 bool delete_pending; /* DELETE_ON_CLOSE is set */
1032 bool invalid_mapping; /* pagecache is invalid */ 1032 bool invalid_mapping; /* pagecache is invalid */
1033 bool leave_pages_clean; /* protected by i_mutex, not set pages dirty */
1033 unsigned long time; /* jiffies of last update of inode */ 1034 unsigned long time; /* jiffies of last update of inode */
1034 u64 server_eof; /* current file size on server -- protected by i_lock */ 1035 u64 server_eof; /* current file size on server -- protected by i_lock */
1035 u64 uniqueid; /* server inode number */ 1036 u64 uniqueid; /* server inode number */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1b322d041f1e..0a6677ba212b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2103,7 +2103,15 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
2103 } else { 2103 } else {
2104 rc = copied; 2104 rc = copied;
2105 pos += copied; 2105 pos += copied;
2106 set_page_dirty(page); 2106 /*
2107 * When we use strict cache mode and cifs_strict_writev was run
2108 * with level II oplock (indicated by leave_pages_clean field of
2109 * CIFS_I(inode)), we can leave pages clean - cifs_strict_writev
2110 * sent the data to the server itself.
2111 */
2112 if (!CIFS_I(inode)->leave_pages_clean ||
2113 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO))
2114 set_page_dirty(page);
2107 } 2115 }
2108 2116
2109 if (rc > 0) { 2117 if (rc > 0) {
@@ -2454,8 +2462,8 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
2454} 2462}
2455 2463
2456static ssize_t 2464static ssize_t
2457cifs_writev(struct kiocb *iocb, const struct iovec *iov, 2465cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
2458 unsigned long nr_segs, loff_t pos) 2466 unsigned long nr_segs, loff_t pos, bool cache_ex)
2459{ 2467{
2460 struct file *file = iocb->ki_filp; 2468 struct file *file = iocb->ki_filp;
2461 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 2469 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
@@ -2477,8 +2485,12 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
2477 server->vals->exclusive_lock_type, NULL, 2485 server->vals->exclusive_lock_type, NULL,
2478 CIFS_WRITE_OP)) { 2486 CIFS_WRITE_OP)) {
2479 mutex_lock(&inode->i_mutex); 2487 mutex_lock(&inode->i_mutex);
2488 if (!cache_ex)
2489 cinode->leave_pages_clean = true;
2480 rc = __generic_file_aio_write(iocb, iov, nr_segs, 2490 rc = __generic_file_aio_write(iocb, iov, nr_segs,
2481 &iocb->ki_pos); 2491 &iocb->ki_pos);
2492 if (!cache_ex)
2493 cinode->leave_pages_clean = false;
2482 mutex_unlock(&inode->i_mutex); 2494 mutex_unlock(&inode->i_mutex);
2483 } 2495 }
2484 2496
@@ -2505,42 +2517,62 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
2505 struct cifsFileInfo *cfile = (struct cifsFileInfo *) 2517 struct cifsFileInfo *cfile = (struct cifsFileInfo *)
2506 iocb->ki_filp->private_data; 2518 iocb->ki_filp->private_data;
2507 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 2519 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
2508 2520 ssize_t written, written2;
2509#ifdef CONFIG_CIFS_SMB2
2510 /* 2521 /*
2511 * If we have an oplock for read and want to write a data to the file 2522 * We need to store clientCanCacheAll here to prevent race
2512 * we need to store it in the page cache and then push it to the server 2523 * conditions - this value can be changed during an execution
2513 * to be sure the next read will get a valid data. 2524 * of generic_file_aio_write. For CIFS it can be changed from
2525 * true to false only, but for SMB2 it can be changed both from
2526 * true to false and vice versa. So, we can end up with a data
2527 * stored in the cache, not marked dirty and not sent to the
2528 * server if this value changes its state from false to true
2529 * after cifs_write_end.
2514 */ 2530 */
2515 if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) { 2531 bool cache_ex = cinode->clientCanCacheAll;
2516 ssize_t written; 2532 bool cache_read = cinode->clientCanCacheRead;
2517 int rc; 2533 int rc;
2518 2534 loff_t saved_pos;
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 2535
2524 return written; 2536 if (cache_ex) {
2537 if (cap_unix(tcon->ses) &&
2538 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
2539 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
2540 tcon->fsUnixInfo.Capability)))
2541 return generic_file_aio_write(iocb, iov, nr_segs, pos);
2542 return cifs_pagecache_writev(iocb, iov, nr_segs, pos, cache_ex);
2525 } 2543 }
2526#endif
2527 2544
2528 /* 2545 /*
2529 * For non-oplocked files in strict cache mode we need to write the data 2546 * For files without exclusive oplock in strict cache mode we need to
2530 * to the server exactly from the pos to pos+len-1 rather than flush all 2547 * write the data to the server exactly from the pos to pos+len-1 rather
2531 * affected pages because it may cause a error with mandatory locks on 2548 * than flush all affected pages because it may cause a error with
2532 * these pages but not on the region from pos to ppos+len-1. 2549 * mandatory locks on these pages but not on the region from pos to
2550 * ppos+len-1.
2533 */ 2551 */
2552 written = cifs_user_writev(iocb, iov, nr_segs, pos);
2553 if (!cache_read || written <= 0)
2554 return written;
2534 2555
2535 if (!cinode->clientCanCacheAll) 2556 saved_pos = iocb->ki_pos;
2536 return cifs_user_writev(iocb, iov, nr_segs, pos); 2557 iocb->ki_pos = pos;
2537 2558 /* we have a read oplock - need to store a data in the page cache */
2538 if (cap_unix(tcon->ses) && 2559 if (cap_unix(tcon->ses) &&
2539 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 2560 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
2540 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 2561 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
2541 return generic_file_aio_write(iocb, iov, nr_segs, pos); 2562 tcon->fsUnixInfo.Capability)))
2542 2563 written2 = generic_file_aio_write(iocb, iov, nr_segs, pos);
2543 return cifs_writev(iocb, iov, nr_segs, pos); 2564 else
2565 written2 = cifs_pagecache_writev(iocb, iov, nr_segs, pos,
2566 cache_ex);
2567 /* errors occured during writing - invalidate the page cache */
2568 if (written2 < 0) {
2569 rc = cifs_invalidate_mapping(inode);
2570 if (rc)
2571 written = (ssize_t)rc;
2572 else
2573 iocb->ki_pos = saved_pos;
2574 }
2575 return written;
2544} 2576}
2545 2577
2546static struct cifs_readdata * 2578static struct cifs_readdata *