diff options
author | J. Bruce Fields <bfields@redhat.com> | 2017-05-11 14:45:06 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-07-12 15:55:00 -0400 |
commit | 630458e730b82efe1f6eb90e6bcabad02fe76e20 (patch) | |
tree | a71f8715cbd69020f99cb9a5942b3ec16f4baefa /fs/nfsd | |
parent | 35a30fc389b5961b42bb73ef751f3bc85190a118 (diff) |
nfsd4: factor ctime into change attribute
Factoring ctime into the nfsv4 change attribute gives us better
properties than just i_version alone.
Eventually we'll likely also expose this (as opposed to raw i_version)
to userspace, at which point we'll want to move it to a common helper,
called from either userspace or individual filesystems. For now, nfsd
is the only user.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.h | 24 |
3 files changed, 25 insertions, 3 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index b8838d3023ff..bf444b664011 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -260,7 +260,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
260 | printk("nfsd: inode locked twice during operation.\n"); | 260 | printk("nfsd: inode locked twice during operation.\n"); |
261 | 261 | ||
262 | err = fh_getattr(fhp, &fhp->fh_post_attr); | 262 | err = fh_getattr(fhp, &fhp->fh_post_attr); |
263 | fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version; | 263 | fhp->fh_post_change = nfsd4_change_attribute(d_inode(fhp->fh_dentry)); |
264 | if (err) { | 264 | if (err) { |
265 | fhp->fh_post_saved = false; | 265 | fhp->fh_post_saved = false; |
266 | /* Grab the ctime anyway - set_change_info might use it */ | 266 | /* Grab the ctime anyway - set_change_info might use it */ |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 54e212e3541e..20fbcab97753 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1973,7 +1973,7 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, | |||
1973 | *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); | 1973 | *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); |
1974 | *p++ = 0; | 1974 | *p++ = 0; |
1975 | } else if (IS_I_VERSION(inode)) { | 1975 | } else if (IS_I_VERSION(inode)) { |
1976 | p = xdr_encode_hyper(p, inode->i_version); | 1976 | p = xdr_encode_hyper(p, nfsd4_change_attribute(inode)); |
1977 | } else { | 1977 | } else { |
1978 | *p++ = cpu_to_be32(stat->ctime.tv_sec); | 1978 | *p++ = cpu_to_be32(stat->ctime.tv_sec); |
1979 | *p++ = cpu_to_be32(stat->ctime.tv_nsec); | 1979 | *p++ = cpu_to_be32(stat->ctime.tv_nsec); |
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index f84fe6bf9aee..e47cf6c2ac28 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h | |||
@@ -241,6 +241,28 @@ fh_clear_wcc(struct svc_fh *fhp) | |||
241 | } | 241 | } |
242 | 242 | ||
243 | /* | 243 | /* |
244 | * We could use i_version alone as the change attribute. However, | ||
245 | * i_version can go backwards after a reboot. On its own that doesn't | ||
246 | * necessarily cause a problem, but if i_version goes backwards and then | ||
247 | * is incremented again it could reuse a value that was previously used | ||
248 | * before boot, and a client who queried the two values might | ||
249 | * incorrectly assume nothing changed. | ||
250 | * | ||
251 | * By using both ctime and the i_version counter we guarantee that as | ||
252 | * long as time doesn't go backwards we never reuse an old value. | ||
253 | */ | ||
254 | static inline u64 nfsd4_change_attribute(struct inode *inode) | ||
255 | { | ||
256 | u64 chattr; | ||
257 | |||
258 | chattr = inode->i_ctime.tv_sec; | ||
259 | chattr <<= 30; | ||
260 | chattr += inode->i_ctime.tv_nsec; | ||
261 | chattr += inode->i_version; | ||
262 | return chattr; | ||
263 | } | ||
264 | |||
265 | /* | ||
244 | * Fill in the pre_op attr for the wcc data | 266 | * Fill in the pre_op attr for the wcc data |
245 | */ | 267 | */ |
246 | static inline void | 268 | static inline void |
@@ -253,7 +275,7 @@ fill_pre_wcc(struct svc_fh *fhp) | |||
253 | fhp->fh_pre_mtime = inode->i_mtime; | 275 | fhp->fh_pre_mtime = inode->i_mtime; |
254 | fhp->fh_pre_ctime = inode->i_ctime; | 276 | fhp->fh_pre_ctime = inode->i_ctime; |
255 | fhp->fh_pre_size = inode->i_size; | 277 | fhp->fh_pre_size = inode->i_size; |
256 | fhp->fh_pre_change = inode->i_version; | 278 | fhp->fh_pre_change = nfsd4_change_attribute(inode); |
257 | fhp->fh_pre_saved = true; | 279 | fhp->fh_pre_saved = true; |
258 | } | 280 | } |
259 | } | 281 | } |