Skip to content

Commit 58f258f

Browse files
committed
Revert "nfsd: skip some unnecessary stats in the v4 case"
On the wire, I observed NFSv4 OPEN(CREATE) operations sometimes returning a reasonable-looking value in the cinfo.before field and zero in the cinfo.after field. RFC 8881 Section 10.8.1 says: > When a client is making changes to a given directory, it needs to > determine whether there have been changes made to the directory by > other clients. It does this by using the change attribute as > reported before and after the directory operation in the associated > change_info4 value returned for the operation. and > ... The post-operation change > value needs to be saved as the basis for future change_info4 > comparisons. A good quality client implementation therefore saves the zero cinfo.after value. During a subsequent OPEN operation, it will receive a different non-zero value in the cinfo.before field for that directory, and it will incorrectly believe the directory has changed, triggering an undesirable directory cache invalidation. There are filesystem types where fs_supports_change_attribute() returns false, tmpfs being one. On NFSv4 mounts, this means the fh_getattr() call site in fill_pre_wcc() and fill_post_wcc() is never invoked. Subsequently, nfsd4_change_attribute() is invoked with an uninitialized @stat argument. In fill_pre_wcc(), @stat contains stale stack garbage, which is then placed on the wire. In fill_post_wcc(), ->fh_post_wc is all zeroes, so zero is placed on the wire. Both of these values are meaningless. This fix can be applied immediately to stable kernels. Once there are more regression tests in this area, this optimization can be attempted again. Fixes: 428a23d ("nfsd: skip some unnecessary stats in the v4 case") Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 75acacb commit 58f258f

1 file changed

Lines changed: 17 additions & 27 deletions

File tree

fs/nfsd/nfs3xdr.c

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -487,11 +487,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
487487
return true;
488488
}
489489

490-
static bool fs_supports_change_attribute(struct super_block *sb)
491-
{
492-
return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion;
493-
}
494-
495490
/*
496491
* Fill in the pre_op attr for the wcc data
497492
*/
@@ -500,26 +495,24 @@ void fill_pre_wcc(struct svc_fh *fhp)
500495
struct inode *inode;
501496
struct kstat stat;
502497
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
498+
__be32 err;
503499

504500
if (fhp->fh_no_wcc || fhp->fh_pre_saved)
505501
return;
506502
inode = d_inode(fhp->fh_dentry);
507-
if (fs_supports_change_attribute(inode->i_sb) || !v4) {
508-
__be32 err = fh_getattr(fhp, &stat);
509-
510-
if (err) {
511-
/* Grab the times from inode anyway */
512-
stat.mtime = inode->i_mtime;
513-
stat.ctime = inode->i_ctime;
514-
stat.size = inode->i_size;
515-
}
516-
fhp->fh_pre_mtime = stat.mtime;
517-
fhp->fh_pre_ctime = stat.ctime;
518-
fhp->fh_pre_size = stat.size;
503+
err = fh_getattr(fhp, &stat);
504+
if (err) {
505+
/* Grab the times from inode anyway */
506+
stat.mtime = inode->i_mtime;
507+
stat.ctime = inode->i_ctime;
508+
stat.size = inode->i_size;
519509
}
520510
if (v4)
521511
fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
522512

513+
fhp->fh_pre_mtime = stat.mtime;
514+
fhp->fh_pre_ctime = stat.ctime;
515+
fhp->fh_pre_size = stat.size;
523516
fhp->fh_pre_saved = true;
524517
}
525518

@@ -530,23 +523,20 @@ void fill_post_wcc(struct svc_fh *fhp)
530523
{
531524
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
532525
struct inode *inode = d_inode(fhp->fh_dentry);
526+
__be32 err;
533527

534528
if (fhp->fh_no_wcc)
535529
return;
536530

537531
if (fhp->fh_post_saved)
538532
printk("nfsd: inode locked twice during operation.\n");
539533

540-
fhp->fh_post_saved = true;
541-
542-
if (fs_supports_change_attribute(inode->i_sb) || !v4) {
543-
__be32 err = fh_getattr(fhp, &fhp->fh_post_attr);
544-
545-
if (err) {
546-
fhp->fh_post_saved = false;
547-
fhp->fh_post_attr.ctime = inode->i_ctime;
548-
}
549-
}
534+
err = fh_getattr(fhp, &fhp->fh_post_attr);
535+
if (err) {
536+
fhp->fh_post_saved = false;
537+
fhp->fh_post_attr.ctime = inode->i_ctime;
538+
} else
539+
fhp->fh_post_saved = true;
550540
if (v4)
551541
fhp->fh_post_change =
552542
nfsd4_change_attribute(&fhp->fh_post_attr, inode);

0 commit comments

Comments
 (0)