aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-12-21 06:05:47 -0500
committerSteve French <smfrench@gmail.com>2013-01-01 23:59:55 -0500
commitca8aa29c60238720af2ca2a5caab25fa0c70067e (patch)
treecc5940d0c0acaa31b19793b456423764ac97afe0 /fs
parent31efee60f489c759c341454d755a9fd13de8c03d (diff)
Revert "CIFS: Fix write after setting a read lock for read oplock files"
that solution has data races and can end up two identical writes to the server: when clientCanCacheAll value can be changed during the execution of __generic_file_aio_write. 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/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/file.c94
3 files changed, 31 insertions, 65 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f653835d067b..de7f9168a118 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -228,7 +228,6 @@ cifs_alloc_inode(struct super_block *sb)
228 cifs_set_oplock_level(cifs_inode, 0); 228 cifs_set_oplock_level(cifs_inode, 0);
229 cifs_inode->delete_pending = false; 229 cifs_inode->delete_pending = false;
230 cifs_inode->invalid_mapping = false; 230 cifs_inode->invalid_mapping = false;
231 cifs_inode->leave_pages_clean = false;
232 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 231 cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
233 cifs_inode->server_eof = 0; 232 cifs_inode->server_eof = 0;
234 cifs_inode->uniqueid = 0; 233 cifs_inode->uniqueid = 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index aea1eec64911..dfab450a191e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1030,7 +1030,6 @@ 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 */
1034 unsigned long time; /* jiffies of last update of inode */ 1033 unsigned long time; /* jiffies of last update of inode */
1035 u64 server_eof; /* current file size on server -- protected by i_lock */ 1034 u64 server_eof; /* current file size on server -- protected by i_lock */
1036 u64 uniqueid; /* server inode number */ 1035 u64 uniqueid; /* server inode number */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0a6677ba212b..1b322d041f1e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2103,15 +2103,7 @@ 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 /* 2106 set_page_dirty(page);
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);
2115 } 2107 }
2116 2108
2117 if (rc > 0) { 2109 if (rc > 0) {
@@ -2462,8 +2454,8 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
2462} 2454}
2463 2455
2464static ssize_t 2456static ssize_t
2465cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov, 2457cifs_writev(struct kiocb *iocb, const struct iovec *iov,
2466 unsigned long nr_segs, loff_t pos, bool cache_ex) 2458 unsigned long nr_segs, loff_t pos)
2467{ 2459{
2468 struct file *file = iocb->ki_filp; 2460 struct file *file = iocb->ki_filp;
2469 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 2461 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
@@ -2485,12 +2477,8 @@ cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
2485 server->vals->exclusive_lock_type, NULL, 2477 server->vals->exclusive_lock_type, NULL,
2486 CIFS_WRITE_OP)) { 2478 CIFS_WRITE_OP)) {
2487 mutex_lock(&inode->i_mutex); 2479 mutex_lock(&inode->i_mutex);
2488 if (!cache_ex)
2489 cinode->leave_pages_clean = true;
2490 rc = __generic_file_aio_write(iocb, iov, nr_segs, 2480 rc = __generic_file_aio_write(iocb, iov, nr_segs,
2491 &iocb->ki_pos); 2481 &iocb->ki_pos);
2492 if (!cache_ex)
2493 cinode->leave_pages_clean = false;
2494 mutex_unlock(&inode->i_mutex); 2482 mutex_unlock(&inode->i_mutex);
2495 } 2483 }
2496 2484
@@ -2517,62 +2505,42 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
2517 struct cifsFileInfo *cfile = (struct cifsFileInfo *) 2505 struct cifsFileInfo *cfile = (struct cifsFileInfo *)
2518 iocb->ki_filp->private_data; 2506 iocb->ki_filp->private_data;
2519 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 2507 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
2520 ssize_t written, written2; 2508
2509#ifdef CONFIG_CIFS_SMB2
2521 /* 2510 /*
2522 * We need to store clientCanCacheAll here to prevent race 2511 * If we have an oplock for read and want to write a data to the file
2523 * conditions - this value can be changed during an execution 2512 * we need to store it in the page cache and then push it to the server
2524 * of generic_file_aio_write. For CIFS it can be changed from 2513 * to be sure the next read will get a valid data.
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.
2530 */ 2514 */
2531 bool cache_ex = cinode->clientCanCacheAll; 2515 if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) {
2532 bool cache_read = cinode->clientCanCacheRead; 2516 ssize_t written;
2533 int rc; 2517 int rc;
2534 loff_t saved_pos; 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;
2535 2523
2536 if (cache_ex) { 2524 return written;
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);
2543 } 2525 }
2526#endif
2544 2527
2545 /* 2528 /*
2546 * For files without exclusive oplock in strict cache mode we need to 2529 * For non-oplocked files in strict cache mode we need to write the data
2547 * write the data to the server exactly from the pos to pos+len-1 rather 2530 * to the server exactly from the pos to pos+len-1 rather than flush all
2548 * than flush all affected pages because it may cause a error with 2531 * affected pages because it may cause a error with mandatory locks on
2549 * mandatory locks on these pages but not on the region from pos to 2532 * these pages but not on the region from pos to ppos+len-1.
2550 * ppos+len-1.
2551 */ 2533 */
2552 written = cifs_user_writev(iocb, iov, nr_segs, pos);
2553 if (!cache_read || written <= 0)
2554 return written;
2555 2534
2556 saved_pos = iocb->ki_pos; 2535 if (!cinode->clientCanCacheAll)
2557 iocb->ki_pos = pos; 2536 return cifs_user_writev(iocb, iov, nr_segs, pos);
2558 /* we have a read oplock - need to store a data in the page cache */ 2537
2559 if (cap_unix(tcon->ses) && 2538 if (cap_unix(tcon->ses) &&
2560 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) && 2539 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
2561 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu( 2540 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
2562 tcon->fsUnixInfo.Capability))) 2541 return generic_file_aio_write(iocb, iov, nr_segs, pos);
2563 written2 = generic_file_aio_write(iocb, iov, nr_segs, pos); 2542
2564 else 2543 return cifs_writev(iocb, iov, nr_segs, pos);
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;
2576} 2544}
2577 2545
2578static struct cifs_readdata * 2546static struct cifs_readdata *