diff options
author | J. Bruce Fields <bfields@redhat.com> | 2020-12-01 01:46:14 +0300 |
---|---|---|
committer | Chuck Lever <chuck.lever@oracle.com> | 2020-12-09 17:39:37 +0300 |
commit | 70b87f77294d16d3e567056ba4c9ee2b091a5b50 (patch) | |
tree | 557e788075d69a9eb9248a8cc6aeb3486dd5c348 /fs/nfsd/nfs4xdr.c | |
parent | 4a9d81caf841cd2c0ae36abec9c2963bf21d0284 (diff) | |
download | linux-70b87f77294d16d3e567056ba4c9ee2b091a5b50.tar.xz |
nfsd: only call inode_query_iversion in the I_VERSION case
inode_query_iversion() can modify i_version. Depending on the exported
filesystem, that may not be safe. For example, if you're re-exporting
NFS, NFS stores the server's change attribute in i_version and does not
expect it to be modified locally. This has been observed causing
unnecessary cache invalidations.
The way a filesystem indicates that it's OK to call
inode_query_iverson() is by setting SB_I_VERSION.
So, move the I_VERSION check out of encode_change(), where it's used
only in GETATTR responses, to nfsd4_change_attribute(), which is
also called for pre- and post- operation attributes.
(Note we could also pull the NFSEXP_V4ROOT case into
nfsd4_change_attribute() as well. That would actually be a no-op,
since pre/post attrs are only used for metadata-modifying operations,
and V4ROOT exports are read-only. But we might make the change in
the future just for simplicity.)
Reported-by: Daire Byrne <daire@dneg.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 6 |
1 files changed, 1 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7142b0501451..ef1f55366616 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2426,12 +2426,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, if (exp->ex_flags & NFSEXP_V4ROOT) { *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); *p++ = 0; - } else if (IS_I_VERSION(inode)) { + } else p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode)); - } else { - *p++ = cpu_to_be32(stat->ctime.tv_sec); - *p++ = cpu_to_be32(stat->ctime.tv_nsec); - } return p; } |