From: "J. Bruce Fields" <[email protected]>

fill_{pre/post}_attr are unconditionally using i_version even when the
underlying filesystem doesn't have proper support for i_version.

Move the code that chooses which i_version to use to the common
nfsd4_change_attribute().

The NFSEXP_V4ROOT case probably doesn't matter (the pseudoroot
filesystem is usually read-only and unlikely to see operations with pre
and post change attributes), but let's put it in the same place anyway
for consistency.

Fixes: c654b8a9cba6 ("nfsd: support ext4 i_version")
Signed-off-by: J. Bruce Fields <[email protected]>
---
 fs/nfsd/nfs4xdr.c | 11 +----------
 fs/nfsd/nfsfh.c   | 11 +++++++----
 fs/nfsd/nfsfh.h   | 23 -----------------------
 fs/nfsd/vfs.c     | 32 ++++++++++++++++++++++++++++++++
 fs/nfsd/vfs.h     |  3 +++
 5 files changed, 43 insertions(+), 37 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 833a2c64dfe8..6806207b6d18 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2295,16 +2295,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode 
*inode,
                             struct svc_export *exp)
 {
-       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)) {
-               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;
+       return xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode, exp));
 }
 
 /*
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index b3b4e8809aa9..4fbe1413e767 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -719,6 +719,7 @@ void fill_pre_wcc(struct svc_fh *fhp)
 {
        struct inode    *inode;
        struct kstat    stat;
+       struct svc_export *exp = fhp->fh_export;
        __be32 err;
 
        if (fhp->fh_pre_saved)
@@ -736,7 +737,7 @@ void fill_pre_wcc(struct svc_fh *fhp)
        fhp->fh_pre_mtime = stat.mtime;
        fhp->fh_pre_ctime = stat.ctime;
        fhp->fh_pre_size  = stat.size;
-       fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
+       fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode, exp);
        fhp->fh_pre_saved = true;
 }
 
@@ -746,17 +747,19 @@ void fill_pre_wcc(struct svc_fh *fhp)
 void fill_post_wcc(struct svc_fh *fhp)
 {
        __be32 err;
+       struct inode *inode = d_inode(fhp->fh_dentry);
+       struct svc_export *exp = fhp->fh_export;
 
        if (fhp->fh_post_saved)
                printk("nfsd: inode locked twice during operation.\n");
 
        err = fh_getattr(fhp, &fhp->fh_post_attr);
-       fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
-                                                    d_inode(fhp->fh_dentry));
+       fhp->fh_post_change =
+                       nfsd4_change_attribute(&fhp->fh_post_attr, inode, exp);
        if (err) {
                fhp->fh_post_saved = false;
                /* Grab the ctime anyway - set_change_info might use it */
-               fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
+               fhp->fh_post_attr.ctime = inode->i_ctime;
        } else
                fhp->fh_post_saved = true;
 }
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 56cfbc361561..547aef9b3265 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -245,29 +245,6 @@ fh_clear_wcc(struct svc_fh *fhp)
        fhp->fh_pre_saved = false;
 }
 
-/*
- * We could use i_version alone as the change attribute.  However,
- * i_version can go backwards after a reboot.  On its own that doesn't
- * necessarily cause a problem, but if i_version goes backwards and then
- * is incremented again it could reuse a value that was previously used
- * before boot, and a client who queried the two values might
- * incorrectly assume nothing changed.
- *
- * By using both ctime and the i_version counter we guarantee that as
- * long as time doesn't go backwards we never reuse an old value.
- */
-static inline u64 nfsd4_change_attribute(struct kstat *stat,
-                                        struct inode *inode)
-{
-       u64 chattr;
-
-       chattr =  stat->ctime.tv_sec;
-       chattr <<= 30;
-       chattr += stat->ctime.tv_nsec;
-       chattr += inode_query_iversion(inode);
-       return chattr;
-}
-
 extern void fill_pre_wcc(struct svc_fh *fhp);
 extern void fill_post_wcc(struct svc_fh *fhp);
 #else
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 1ecaceebee13..2c71b02dd1fe 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2390,3 +2390,35 @@ nfsd_permission(struct svc_rqst *rqstp, struct 
svc_export *exp,
 
        return err? nfserrno(err) : 0;
 }
+
+/*
+ * We could use i_version alone as the change attribute.  However,
+ * i_version can go backwards after a reboot.  On its own that doesn't
+ * necessarily cause a problem, but if i_version goes backwards and then
+ * is incremented again it could reuse a value that was previously used
+ * before boot, and a client who queried the two values might
+ * incorrectly assume nothing changed.
+ *
+ * By using both ctime and the i_version counter we guarantee that as
+ * long as time doesn't go backwards we never reuse an old value.
+ */
+u64 nfsd4_change_attribute(struct kstat *stat, struct inode *inode,
+                                        struct svc_export *exp)
+{
+       u64 chattr;
+
+       if (exp->ex_flags & NFSEXP_V4ROOT) {
+               chattr = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
+               chattr <<= 32;
+       } else if (IS_I_VERSION(inode)) {
+               chattr = stat->ctime.tv_sec;
+               chattr <<= 30;
+               chattr += stat->ctime.tv_nsec;
+               chattr += inode_query_iversion(inode);
+       } else {
+               chattr = stat->ctime.tv_sec;
+               chattr <<= 32;
+               chattr += stat->ctime.tv_nsec;
+       }
+       return chattr;
+}
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index a2442ebe5acf..26ed15256340 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -132,6 +132,9 @@ __be32              nfsd_statfs(struct svc_rqst *, struct 
svc_fh *,
 __be32         nfsd_permission(struct svc_rqst *, struct svc_export *,
                                struct dentry *, int);
 
+u64            nfsd4_change_attribute(struct kstat *stat, struct inode *inode,
+                               struct svc_export *exp);
+
 static inline int fh_want_write(struct svc_fh *fh)
 {
        int ret;
-- 
2.28.0

--
Linux-cachefs mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to