linux/fs/nfs
Jeff Layton 81d9bce530 nfs: don't extend writes to cover entire page if pagecache is invalid
Jian reported that the following sequence would leave "testfile" with
corrupt data:

    # mount localhost:/export /mnt/nfs/ -o vers=3
    # echo abc > /mnt/nfs/testfile; echo def >> /export/testfile; echo ghi >> /mnt/nfs/testfile
    # cat -v /export/testfile
    abc
    ^@^@^@^@ghi

While there's no locking involved here, the operations are serialized,
so CTO should prevent corruption.

The first write to the file is fine and writes 4 bytes. The file is then
extended on the server. When it's reopened a GETATTR is issued and the
size change is noticed. This causes NFS_INO_INVALID_DATA to be set on
the file. Because the file is opened for write only,
nfs_want_read_modify_write() returns 0 to nfs_write_begin().
nfs_updatepage then calls nfs_write_pageuptodate() to see if it should
extend the nfs_page to cover the whole page. NFS_INO_INVALID_DATA is
still set on the file at that point, but that flag is ignored and
nfs_pageuptodate erroneously extends the write to cover the whole page,
with the write done on the server side filled in with zeroes.

This patch just has that function check for NFS_INO_INVALID_DATA in
addition to NFS_INO_REVAL_PAGECACHE. This fixes the bug, but looking
over the code, I wonder if we might have a similar bug in
nfs_revalidate_size(). The difference between those two flags is very
subtle, so it seems like we ought to be checking for
NFS_INO_INVALID_DATA in most of the places that we look for
NFS_INO_REVAL_PAGECACHE.

I believe this is regression introduced by commit 8d197a568. The code
did check for NFS_INO_INVALID_DATA prior to that patch.

Original bug report is here:

    https://bugzilla.redhat.com/show_bug.cgi?id=885743

Cc: <stable@vger.kernel.org> # 3.5+
Reported-by: Jian Li <jiali@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
2012-12-11 09:14:51 -05:00
..
blocklayout pnfsblock: cleanup nfs4_blkdev_get 2012-10-08 19:32:40 -04:00
objlayout NFSv4.1: Declare osd_pri_2_pnfs_err(), objio_init_read/write to be static 2012-10-16 12:38:00 -04:00
cache_lib.c NFS: remove RPC PipeFS mount point references from NFS cache routines 2012-01-31 18:20:26 -05:00
cache_lib.h NFS: DNS resolver PipeFS notifier introduced 2012-01-31 18:20:26 -05:00
callback.c NFSv4: Fix the return value for nfs_callback_start_svc 2012-10-16 13:14:42 -04:00
callback.h nfs: declare nfs_callback_tcp_port in header 2012-10-02 08:17:02 -07:00
callback_proc.c NFSv4.1: Clean up the removal of pnfs_layout_hdr from the server list 2012-09-28 16:03:14 -04:00
callback_xdr.c SUNRPC: service request network namespace helper introduced 2012-07-27 16:49:21 -04:00
client.c NFS: Remove unnecessary semicolons (fs/nfs/client.c) 2012-10-01 15:40:03 -07:00
delegation.c NFS: Create a return_delegation rpc op 2012-06-29 11:46:45 -04:00
delegation.h NFS: Convert v4 into a module 2012-07-30 19:06:52 -04:00
dir.c NFSv4: Add ACCESS operation to OPEN compound 2012-10-01 15:20:11 -07:00
direct.c NFS41: send real write size in layoutget 2012-10-08 19:32:22 -04:00
dns_resolve.c NFS: fix bug in legacy DNS resolver. 2012-10-31 16:25:59 -04:00
dns_resolve.h NFS: DNS resolver cache per network namespace context introduced 2012-01-31 18:20:26 -05:00
file.c NFS client updates for Linux 3.7 2012-10-10 23:52:35 +09:00
fscache-index.c NFS: Use the inode->i_version to cache NFSv4 change attribute information 2011-10-18 09:14:34 -07:00
fscache.c NFS: Don't pass mount data to nfs_fscache_get_super_cookie() 2012-05-14 17:30:26 -07:00
fscache.h NFS: Fix a compile issue when CONFIG_NFS_FSCACHE was undefined 2012-05-16 10:24:20 -07:00
getroot.c nfs: include internal.h in getroot.h 2012-10-02 08:17:04 -07:00
idmap.c NFS: Set key construction data for the legacy upcall 2012-10-02 13:04:09 -07:00
inode.c NFS: add nfs_sb_deactive_async to avoid deadlock 2012-10-31 16:26:26 -04:00
internal.h NFS: add nfs_sb_deactive_async to avoid deadlock 2012-10-31 16:26:26 -04:00
iostat.h NFS: Squelch compiler warning in nfs_add_server_stats() 2010-05-14 15:09:31 -04:00
Kconfig NFSv4.1: Remove the dependency on CONFIG_EXPERIMENTAL 2012-10-03 10:54:50 -07:00
Makefile NFS: Fix a regression when loading the NFS v4 module 2012-08-16 16:15:49 -04:00
mount_clnt.c nfsv3: Make v3 mounts fail with ETIMEDOUTs instead EIO on mountd timeouts 2012-10-31 16:26:25 -04:00
namespace.c nfs: Show original device name verbatim in /proc/*/mount{s,info} 2012-10-31 16:26:26 -04:00
netns.h nfs: include NFSv4 header in netns.h 2012-10-02 08:17:02 -07:00
nfs.h NFS: Convert v4 into a module 2012-07-30 19:06:52 -04:00
nfs2super.c NFS: Convert v2 into a module 2012-07-30 19:06:41 -04:00
nfs2xdr.c NFS: Let xdr_read_pages() check for buffer overflows 2012-06-28 17:20:43 -04:00
nfs3acl.c userns: Pass a userns parameter into posix_acl_to_xattr and posix_acl_from_xattr 2012-09-18 01:01:35 -07:00
nfs3client.c NFS: Only initialize the ACL client in the v3 case 2012-07-30 19:05:54 -04:00
nfs3proc.c NFS: Fix the initialisation of the readdir 'cookieverf' array 2012-09-04 14:52:42 -04:00
nfs3super.c NFS: Convert v3 into a module 2012-07-30 19:06:46 -04:00
nfs3xdr.c NFS: Cleanup - only store the write verifier in struct nfs_page 2012-06-28 17:20:50 -04:00
nfs4_fs.h NFSv4: Fix a compile time warning when #undef CONFIG_NFS_V4_1 2012-11-21 22:59:28 -05:00
nfs4client.c NFS: nfs41_walk_client_list(): re-lock before iterating 2012-10-02 09:25:02 -07:00
nfs4file.c NFS: Write the entire file if a server reboot occurs during fsync() 2012-09-28 16:03:05 -04:00
nfs4filelayout.c NFSv4.1: Use kcalloc() to allocate zeroed arrays instead of kzalloc() 2012-10-15 10:49:43 -04:00
nfs4filelayout.h NFSv4.1: Kill nfs4_ds_disconnect() 2012-10-15 10:49:42 -04:00
nfs4filelayoutdev.c NFSv4.1: Kill nfs4_ds_disconnect() 2012-10-15 10:49:42 -04:00
nfs4getroot.c NFSv4: fs/nfs/nfs4getroot.c needs to include "internal.h" 2012-10-16 12:37:59 -04:00
nfs4namespace.c nfs: Show original device name verbatim in /proc/*/mount{s,info} 2012-10-31 16:26:26 -04:00
nfs4proc.c NFSv4: Check for buffer length in __nfs4_get_acl_uncached 2012-12-11 09:14:50 -05:00
nfs4renewd.c workqueue: use mod_delayed_work() instead of cancel + queue 2012-08-13 16:27:37 -07:00
nfs4state.c NFSv4.1: don't do two EXCHANGE_IDs on mount 2012-10-02 11:35:47 -07:00
nfs4super.c NFS: Fix a regression when loading the NFS v4 module 2012-08-16 16:15:49 -04:00
nfs4sysctl.c nfs: include nfs4_fh.h in nfs4sysctl.c 2012-10-02 08:17:03 -07:00
nfs4xdr.c NFS: Reduce stack use in encode_exchange_id() 2012-11-21 22:59:29 -05:00
nfsroot.c SUNRPC/NFS: Add Kbuild dependencies for NFS_DEBUG/RPC_DEBUG 2012-03-20 13:08:26 -04:00
pagelist.c NFS: Clean up helper function nfs4_select_rw_stateid() 2012-09-28 16:03:04 -04:00
pnfs.c nfs: Check whether a layout pointer is NULL before free it 2012-10-31 16:26:25 -04:00
pnfs.h NFSv4.1: Do not call pnfs_return_layout() from an rpciod context 2012-10-15 10:49:43 -04:00
pnfs_dev.c NFSv4.1: pNFS data servers may be temporarily offline 2012-09-28 16:03:09 -04:00
proc.c NFS: Only initialize the ACL client in the v3 case 2012-07-30 19:05:54 -04:00
read.c Merge branch 'akpm' (Andrew's patch-bomb) 2012-07-31 19:25:39 -07:00
super.c NFS: add nfs_sb_deactive_async to avoid deadlock 2012-10-31 16:26:26 -04:00
symlink.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
sysctl.c NFS: Initialize v4 sysctls from nfs_init_v4() 2012-07-17 13:33:18 -04:00
unlink.c NFS: add nfs_sb_deactive_async to avoid deadlock 2012-10-31 16:26:26 -04:00
write.c nfs: don't extend writes to cover entire page if pagecache is invalid 2012-12-11 09:14:51 -05:00