nfsd: only call inode_query_iversion in the I_VERSION case
inode_query_iversion() can modify i_version. Depending on the exported filesystem, that may not be safe. For example, if you're re-exporting NFS, NFS stores the server's change attribute in i_version and does not expect it to be modified locally. This has been observed causing unnecessary cache invalidations. The way a filesystem indicates that it's OK to call inode_query_iverson() is by setting SB_I_VERSION. So, move the I_VERSION check out of encode_change(), where it's used only in GETATTR responses, to nfsd4_change_attribute(), which is also called for pre- and post- operation attributes. (Note we could also pull the NFSEXP_V4ROOT case into nfsd4_change_attribute() as well. That would actually be a no-op, since pre/post attrs are only used for metadata-modifying operations, and V4ROOT exports are read-only. But we might make the change in the future just for simplicity.) Reported-by: Daire Byrne <daire@dneg.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Родитель
4a9d81caf8
Коммит
70b87f7729
|
@ -291,14 +291,13 @@ 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(&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 */
|
||||
fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
|
||||
} else
|
||||
fhp->fh_post_saved = true;
|
||||
fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
|
||||
d_inode(fhp->fh_dentry));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -2426,12 +2426,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
|
|||
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)) {
|
||||
} else
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat,
|
|||
{
|
||||
u64 chattr;
|
||||
|
||||
chattr = stat->ctime.tv_sec;
|
||||
chattr <<= 30;
|
||||
chattr += stat->ctime.tv_nsec;
|
||||
chattr += inode_query_iversion(inode);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче