Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: drop inode parameter from nfsd4_change_attribute()

The inode that nfs4_open_delegation() passes to this function is
wrong, which throws off the result. The inode will end up getting a
directory-style change attr instead of a regular-file-style one.

Fix up nfs4_delegation_stat() to fetch STATX_MODE, and then drop the
inode parameter from nfsd4_change_attribute(), since it's no longer
needed.

Fixes: c5967721e106 ("NFSD: handle GETATTR conflict with write delegation")
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by

Jeff Layton and committed by
Chuck Lever
f67eef8d ac159338

+16 -14
+2 -3
fs/nfsd/nfs4state.c
··· 5957 5957 path.dentry = file_dentry(nf->nf_file); 5958 5958 5959 5959 rc = vfs_getattr(&path, stat, 5960 - (STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE), 5960 + (STATX_MODE | STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE), 5961 5961 AT_STATX_SYNC_AS_STAT); 5962 5962 5963 5963 nfsd_file_put(nf); ··· 6041 6041 } 6042 6042 open->op_delegate_type = NFS4_OPEN_DELEGATE_WRITE; 6043 6043 dp->dl_cb_fattr.ncf_cur_fsize = stat.size; 6044 - dp->dl_cb_fattr.ncf_initial_cinfo = 6045 - nfsd4_change_attribute(&stat, d_inode(currentfh->fh_dentry)); 6044 + dp->dl_cb_fattr.ncf_initial_cinfo = nfsd4_change_attribute(&stat); 6046 6045 trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid); 6047 6046 } else { 6048 6047 open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
+1 -1
fs/nfsd/nfs4xdr.c
··· 3040 3040 return nfs_ok; 3041 3041 } 3042 3042 3043 - c = nfsd4_change_attribute(&args->stat, d_inode(args->dentry)); 3043 + c = nfsd4_change_attribute(&args->stat); 3044 3044 return nfsd4_encode_changeid4(xdr, c); 3045 3045 } 3046 3046
+12 -8
fs/nfsd/nfsfh.c
··· 667 667 __be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp) 668 668 { 669 669 bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); 670 - struct inode *inode; 671 670 struct kstat stat; 672 671 __be32 err; 673 672 674 673 if (fhp->fh_no_wcc || fhp->fh_pre_saved) 675 674 return nfs_ok; 676 675 677 - inode = d_inode(fhp->fh_dentry); 678 676 err = fh_getattr(fhp, &stat); 679 677 if (err) 680 678 return err; 681 679 682 680 if (v4) 683 - fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); 681 + fhp->fh_pre_change = nfsd4_change_attribute(&stat); 684 682 685 683 fhp->fh_pre_mtime = stat.mtime; 686 684 fhp->fh_pre_ctime = stat.ctime; ··· 695 697 __be32 fh_fill_post_attrs(struct svc_fh *fhp) 696 698 { 697 699 bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); 698 - struct inode *inode = d_inode(fhp->fh_dentry); 699 700 __be32 err; 700 701 701 702 if (fhp->fh_no_wcc) ··· 710 713 fhp->fh_post_saved = true; 711 714 if (v4) 712 715 fhp->fh_post_change = 713 - nfsd4_change_attribute(&fhp->fh_post_attr, inode); 716 + nfsd4_change_attribute(&fhp->fh_post_attr); 714 717 return nfs_ok; 715 718 } 716 719 ··· 801 804 return FSIDSOURCE_DEV; 802 805 } 803 806 804 - /* 807 + /** 808 + * nfsd4_change_attribute - Generate an NFSv4 change_attribute value 809 + * @stat: inode attributes 810 + * 811 + * Caller must fill in @stat before calling, typically by invoking 812 + * vfs_getattr() with STATX_MODE, STATX_CTIME, and STATX_CHANGE_COOKIE. 813 + * Returns an unsigned 64-bit changeid4 value (RFC 8881 Section 3.2). 814 + * 805 815 * We could use i_version alone as the change attribute. However, i_version 806 816 * can go backwards on a regular file after an unclean shutdown. On its own 807 817 * that doesn't necessarily cause a problem, but if i_version goes backwards ··· 825 821 * assume that the new change attr is always logged to stable storage in some 826 822 * fashion before the results can be seen. 827 823 */ 828 - u64 nfsd4_change_attribute(const struct kstat *stat, const struct inode *inode) 824 + u64 nfsd4_change_attribute(const struct kstat *stat) 829 825 { 830 826 u64 chattr; 831 827 832 828 if (stat->result_mask & STATX_CHANGE_COOKIE) { 833 829 chattr = stat->change_cookie; 834 - if (S_ISREG(inode->i_mode) && 830 + if (S_ISREG(stat->mode) && 835 831 !(stat->attributes & STATX_ATTR_CHANGE_MONOTONIC)) { 836 832 chattr += (u64)stat->ctime.tv_sec << 30; 837 833 chattr += stat->ctime.tv_nsec;
+1 -2
fs/nfsd/nfsfh.h
··· 297 297 fhp->fh_pre_saved = false; 298 298 } 299 299 300 - u64 nfsd4_change_attribute(const struct kstat *stat, 301 - const struct inode *inode); 300 + u64 nfsd4_change_attribute(const struct kstat *stat); 302 301 __be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp); 303 302 __be32 fh_fill_post_attrs(struct svc_fh *fhp); 304 303 __be32 __must_check fh_fill_both_attrs(struct svc_fh *fhp);