summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2017-05-11 14:45:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2017-07-12 15:55:00 -0400
commit630458e730b82efe1f6eb90e6bcabad02fe76e20 (patch)
treea71f8715cbd69020f99cb9a5942b3ec16f4baefa /fs/nfsd
parent35a30fc389b5961b42bb73ef751f3bc85190a118 (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.c2
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsfh.h24
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 */
254static 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 */
246static inline void 268static 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}