1 From 263b4509ec4d47e0da3e753f85a39ea12d1eff24 Mon Sep 17 00:00:00 2001
2 From: Scott Mayhew <smayhew@redhat.com>
3 Date: Fri, 17 Jan 2014 15:12:05 -0500
4 Subject: nfs: always make sure page is up-to-date before extending a write to cover the entire page
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 From: Scott Mayhew <smayhew@redhat.com>
11 commit 263b4509ec4d47e0da3e753f85a39ea12d1eff24 upstream.
13 We should always make sure the cached page is up-to-date when we're
14 determining whether we can extend a write to cover the full page -- even
15 if we've received a write delegation from the server.
17 Commit c7559663 added logic to skip this check if we have a write
18 delegation, which can lead to data corruption such as the following
19 scenario if client B receives a write delegation from the NFS server:
22 # echo 123456789 > /mnt/file
25 # echo abcdefghi >> /mnt/file
29 Just because we hold a write delegation doesn't mean that we've read in
30 the entire page contents.
32 Signed-off-by: Scott Mayhew <smayhew@redhat.com>
33 Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
34 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
37 fs/nfs/write.c | 11 ++++++-----
38 1 file changed, 6 insertions(+), 5 deletions(-)
42 @@ -922,19 +922,20 @@ out:
43 * extend the write to cover the entire page in order to avoid fragmentation
46 - * If the file is opened for synchronous writes or if we have a write delegation
47 - * from the server then we can just skip the rest of the checks.
48 + * If the file is opened for synchronous writes then we can just skip the rest
51 static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
53 if (file->f_flags & O_DSYNC)
55 + if (!nfs_write_pageuptodate(page, inode))
57 if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
59 - if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL ||
60 - (inode->i_flock->fl_start == 0 &&
61 + if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 &&
62 inode->i_flock->fl_end == OFFSET_MAX &&
63 - inode->i_flock->fl_type != F_RDLCK)))
64 + inode->i_flock->fl_type != F_RDLCK))