nfsd: skip some unnecessary stats in the v4 case

In the typical case of v4 and an i_version-supporting filesystem, we can
skip a stat which is only required to fake up a change attribute from
ctime.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
J. Bruce Fields 2021-01-29 14:27:01 -05:00 committed by Chuck Lever
parent 3cc55f4434
commit 428a23d2bf

View file

@ -364,6 +364,11 @@ 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);
} }
static bool fs_supports_change_attribute(struct super_block *sb)
{
return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion;
}
/* /*
* Fill in the pre_op attr for the wcc data * Fill in the pre_op attr for the wcc data
*/ */
@ -372,24 +377,26 @@ void fill_pre_wcc(struct svc_fh *fhp)
struct inode *inode; struct inode *inode;
struct kstat stat; struct kstat stat;
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
__be32 err;
if (fhp->fh_no_wcc || fhp->fh_pre_saved) if (fhp->fh_no_wcc || fhp->fh_pre_saved)
return; return;
inode = d_inode(fhp->fh_dentry); inode = d_inode(fhp->fh_dentry);
err = fh_getattr(fhp, &stat); if (fs_supports_change_attribute(inode->i_sb) || !v4) {
if (err) { __be32 err = fh_getattr(fhp, &stat);
/* Grab the times from inode anyway */
stat.mtime = inode->i_mtime; if (err) {
stat.ctime = inode->i_ctime; /* Grab the times from inode anyway */
stat.size = inode->i_size; 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;
} }
if (v4) if (v4)
fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
fhp->fh_pre_mtime = stat.mtime;
fhp->fh_pre_ctime = stat.ctime;
fhp->fh_pre_size = stat.size;
fhp->fh_pre_saved = true; fhp->fh_pre_saved = true;
} }
@ -400,7 +407,6 @@ void fill_post_wcc(struct svc_fh *fhp)
{ {
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
struct inode *inode = d_inode(fhp->fh_dentry); struct inode *inode = d_inode(fhp->fh_dentry);
__be32 err;
if (fhp->fh_no_wcc) if (fhp->fh_no_wcc)
return; return;
@ -408,12 +414,16 @@ void fill_post_wcc(struct svc_fh *fhp)
if (fhp->fh_post_saved) if (fhp->fh_post_saved)
printk("nfsd: inode locked twice during operation.\n"); printk("nfsd: inode locked twice during operation.\n");
err = fh_getattr(fhp, &fhp->fh_post_attr); fhp->fh_post_saved = true;
if (err) {
fhp->fh_post_saved = false; if (fs_supports_change_attribute(inode->i_sb) || !v4) {
fhp->fh_post_attr.ctime = inode->i_ctime; __be32 err = fh_getattr(fhp, &fhp->fh_post_attr);
} else
fhp->fh_post_saved = true; if (err) {
fhp->fh_post_saved = false;
fhp->fh_post_attr.ctime = inode->i_ctime;
}
}
if (v4) if (v4)
fhp->fh_post_change = fhp->fh_post_change =
nfsd4_change_attribute(&fhp->fh_post_attr, inode); nfsd4_change_attribute(&fhp->fh_post_attr, inode);