nfsd: store stat times in fill_pre_wcc() instead of inode times
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>
This commit is contained in:
parent
76c479480b
commit
39ca1bf624
|
@ -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);
|
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
|
* 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");
|
printk("nfsd: inode locked twice during operation.\n");
|
||||||
|
|
||||||
err = fh_getattr(fhp, &fhp->fh_post_attr);
|
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) {
|
if (err) {
|
||||||
fhp->fh_post_saved = false;
|
fhp->fh_post_saved = false;
|
||||||
/* Grab the ctime anyway - set_change_info might use it */
|
/* Grab the ctime anyway - set_change_info might use it */
|
||||||
|
|
|
@ -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++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
} else if (IS_I_VERSION(inode)) {
|
} 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 {
|
} else {
|
||||||
*p++ = cpu_to_be32(stat->ctime.tv_sec);
|
*p++ = cpu_to_be32(stat->ctime.tv_sec);
|
||||||
*p++ = cpu_to_be32(stat->ctime.tv_nsec);
|
*p++ = cpu_to_be32(stat->ctime.tv_nsec);
|
||||||
|
|
|
@ -252,36 +252,20 @@ fh_clear_wcc(struct svc_fh *fhp)
|
||||||
* By using both ctime and the i_version counter we guarantee that as
|
* 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.
|
* 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;
|
u64 chattr;
|
||||||
|
|
||||||
chattr = inode->i_ctime.tv_sec;
|
chattr = stat->ctime.tv_sec;
|
||||||
chattr <<= 30;
|
chattr <<= 30;
|
||||||
chattr += inode->i_ctime.tv_nsec;
|
chattr += stat->ctime.tv_nsec;
|
||||||
chattr += inode->i_version;
|
chattr += inode->i_version;
|
||||||
return chattr;
|
return chattr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
extern void fill_pre_wcc(struct svc_fh *fhp);
|
||||||
* Fill in the pre_op attr for the wcc data
|
extern void fill_post_wcc(struct svc_fh *fhp);
|
||||||
*/
|
|
||||||
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 *);
|
|
||||||
#else
|
#else
|
||||||
#define fh_clear_wcc(ignored)
|
#define fh_clear_wcc(ignored)
|
||||||
#define fill_pre_wcc(ignored)
|
#define fill_pre_wcc(ignored)
|
||||||
|
|
Loading…
Reference in New Issue