NFS: flush data when locking a file to ensure cache coherence for mmap.

When a byte range lock (or flock) is taken out on an NFS file, the
validity of the cached data is checked and the inode is marked
NFS_INODE_INVALID_DATA. However the cached data isn't flushed from
the page cache.

This is sufficient for future read() requests or mmap() requests as
they call nfs_revalidate_mapping() which performs the flush if
necessary.

However an existing mapping is not affected. Accessing data through
that mapping will continue to return old data even though the inode is
marked NFS_INODE_INVALID_DATA.

This can easily be confirmed using the 'nfs' tool in
git://github.com/okirch/twopence-nfs.git
and running

nfs coherence FILENAME
on one client, and
nfs coherence -r FILENAME
on another client.

It appears that prior to Linux 2.6.0 this worked correctly.

However commit:

http://git.kernel.org/cgit/linux/kernel/git/history/history.git/commit/?id=ca9268fe3ddd075714005adecd4afbd7f9ab87d0

removed the call to inode_invalidate_pages() from nfs_zap_caches(). I
haven't tested this code, but inspection suggests that prior to this
commit, file locking would invalidate all inode pages.

This patch adds a call to nfs_revalidate_mapping() after a
successful SETLK so that invalid data is flushed. With this patch the
above test passes. To minimize impact (and possibly avoid a GETATTR
call) this only happens if the mapping might be mapped into
userspace.

Cc: Olaf Kirch <okir@suse.com>
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

authored by

NeilBrown and committed by
Trond Myklebust
779eafab f1ecbc21

+7 -4
+7 -4
fs/nfs/file.c
··· 744 744 goto out; 745 745 746 746 /* 747 - * Revalidate the cache if the server has time stamps granular 748 - * enough to detect subsecond changes. Otherwise, clear the 749 - * cache to prevent missing any changes. 747 + * Invalidate cache to prevent missing any changes. If 748 + * the file is mapped, clear the page cache as well so 749 + * those mappings will be loaded. 750 750 * 751 751 * This makes locking act as a cache coherency point. 752 752 */ 753 753 nfs_sync_mapping(filp->f_mapping); 754 - if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 754 + if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) { 755 755 nfs_zap_caches(inode); 756 + if (mapping_mapped(filp->f_mapping)) 757 + nfs_revalidate_mapping(inode, filp->f_mapping); 758 + } 756 759 out: 757 760 return status; 758 761 }