diff options
author | J. Bruce Fields <bfields@redhat.com> | 2018-04-25 21:34:11 +0300 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2018-06-17 17:41:11 +0300 |
commit | 16945141c3567bb8561de3677de1ec657675bb15 (patch) | |
tree | 9b8bf154e464cc93a9ae085fbeb7c80437317de1 /fs/nfsd | |
parent | d6ebf5088f09472c1136cd506bdc27034a6763f8 (diff) | |
download | linux-16945141c3567bb8561de3677de1ec657675bb15.tar.xz |
nfsd: fix NFSv4 time_delta attribute
Currently we return the worst-case value of 1 second in the time delta
attribute. That's not terribly useful. Instead, return a value
calculated from the time granularity supported by the filesystem and the
system clock.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a96843c59fc1..4161031ae14e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2006,6 +2006,31 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, return p; } +/* + * ctime (in NFSv4, time_metadata) is not writeable, and the client + * doesn't really care what resolution could theoretically be stored by + * the filesystem. + * + * The client cares how close together changes can be while still + * guaranteeing ctime changes. For most filesystems (which have + * timestamps with nanosecond fields) that is limited by the resolution + * of the time returned from current_time() (which I'm assuming to be + * 1/HZ). + */ +static __be32 *encode_time_delta(__be32 *p, struct inode *inode) +{ + struct timespec ts; + u32 ns; + + ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran); + ts = ns_to_timespec(ns); + + p = xdr_encode_hyper(p, ts.tv_sec); + *p++ = cpu_to_be32(ts.tv_nsec); + + return p; +} + static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c) { *p++ = cpu_to_be32(c->atomic); @@ -2797,9 +2822,7 @@ out_acl: p = xdr_reserve_space(xdr, 12); if (!p) goto out_resource; - *p++ = cpu_to_be32(0); - *p++ = cpu_to_be32(1); - *p++ = cpu_to_be32(0); + p = encode_time_delta(p, d_inode(dentry)); } if (bmval1 & FATTR4_WORD1_TIME_METADATA) { p = xdr_reserve_space(xdr, 12); |