]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
nfsd: store stat times in fill_pre_wcc() instead of inode times
authorAmir Goldstein <amir73il@gmail.com>
Wed, 3 Jan 2018 15:14:35 +0000 (17:14 +0200)
committerJ. Bruce Fields <bfields@redhat.com>
Thu, 8 Feb 2018 18:40:17 +0000 (13:40 -0500)
The time values in stat and inode may differ for overlayfs and stat time
values are the correct ones to use. This is also consistent with the fact
that fill_post_wcc() also stores stat time values.

This means introducing a stat call that could fail, where previously we
were just copying values out of the inode.  To be conservative about
changing behavior, we fall back to copying values out of the inode in
the error case.  It might be better just to clear fh_pre_saved (though
note the BUG_ON in set_change_info).

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsfh.h

index 2758480555faa504b1aafc204ea549361bf3b932..1a70581e1cb2b1222a35b8169a7af804348beec7 100644 (file)
@@ -250,6 +250,34 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
        return encode_post_op_attr(rqstp, p, fhp);
 }
 
+/*
+ * Fill in the pre_op attr for the wcc data
+ */
+void fill_pre_wcc(struct svc_fh *fhp)
+{
+       struct inode    *inode;
+       struct kstat    stat;
+       __be32 err;
+
+       if (fhp->fh_pre_saved)
+               return;
+
+       inode = d_inode(fhp->fh_dentry);
+       err = fh_getattr(fhp, &stat);
+       if (err) {
+               /* Grab the times from inode anyway */
+               stat.mtime = inode->i_mtime;
+               stat.ctime = inode->i_ctime;
+               stat.size  = inode->i_size;
+       }
+
+       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_saved = true;
+}
+
 /*
  * Fill in the post_op attr for the wcc data
  */
@@ -261,7 +289,8 @@ void fill_post_wcc(struct svc_fh *fhp)
                printk("nfsd: inode locked twice during operation.\n");
 
        err = fh_getattr(fhp, &fhp->fh_post_attr);
-       fhp->fh_post_change = nfsd4_change_attribute(d_inode(fhp->fh_dentry));
+       fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
+                                                    d_inode(fhp->fh_dentry));
        if (err) {
                fhp->fh_post_saved = false;
                /* Grab the ctime anyway - set_change_info might use it */
index 5dcd7cb45b2d2bfaf0780322000fb2354bd680c6..e4395abd0f2b322258df5073c8b8407cff2a31a8 100644 (file)
@@ -1996,7 +1996,7 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
                *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(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);
index 43f31cf49bae3f1e27fe8af8630e1f489e636d8b..99be87b50ebed67114b4e27119a3fa65c893a587 100644 (file)
@@ -252,36 +252,20 @@ fh_clear_wcc(struct svc_fh *fhp)
  * 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 inode *inode)
+static inline u64 nfsd4_change_attribute(struct kstat *stat,
+                                        struct inode *inode)
 {
        u64 chattr;
 
-       chattr =  inode->i_ctime.tv_sec;
+       chattr =  stat->ctime.tv_sec;
        chattr <<= 30;
-       chattr += inode->i_ctime.tv_nsec;
+       chattr += stat->ctime.tv_nsec;
        chattr += inode->i_version;
        return chattr;
 }
 
-/*
- * Fill in the pre_op attr for the wcc data
- */
-static inline void
-fill_pre_wcc(struct svc_fh *fhp)
-{
-       struct inode    *inode;
-
-       inode = d_inode(fhp->fh_dentry);
-       if (!fhp->fh_pre_saved) {
-               fhp->fh_pre_mtime = inode->i_mtime;
-               fhp->fh_pre_ctime = inode->i_ctime;
-               fhp->fh_pre_size  = inode->i_size;
-               fhp->fh_pre_change = nfsd4_change_attribute(inode);
-               fhp->fh_pre_saved = true;
-       }
-}
-
-extern void fill_post_wcc(struct svc_fh *);
+extern void fill_pre_wcc(struct svc_fh *fhp);
+extern void fill_post_wcc(struct svc_fh *fhp);
 #else
 #define fh_clear_wcc(ignored)
 #define fill_pre_wcc(ignored)