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

nfsd: stop READDIRPLUS returning inconsistent attributes

The NFSv3 READDIRPLUS gets some of the returned attributes from the
readdir, and some from an inode returned from a new lookup. The two
objects could be different thanks to intervening renames.

The attributes in READDIRPLUS are optional, so let's just skip them if
we notice this case.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

NeilBrown and committed by
J. Bruce Fields
43b0e7ea 72faedae

+7 -5
+7 -5
fs/nfsd/nfs3xdr.c
··· 805 805 806 806 static __be32 807 807 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, 808 - const char *name, int namlen) 808 + const char *name, int namlen, u64 ino) 809 809 { 810 810 struct svc_export *exp; 811 811 struct dentry *dparent, *dchild; ··· 830 830 goto out; 831 831 if (d_really_is_negative(dchild)) 832 832 goto out; 833 + if (dchild->d_inode->i_ino != ino) 834 + goto out; 833 835 rv = fh_compose(fhp, exp, dchild, &cd->fh); 834 836 out: 835 837 dput(dchild); 836 838 return rv; 837 839 } 838 840 839 - static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen) 841 + static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino) 840 842 { 841 843 struct svc_fh *fh = &cd->scratch; 842 844 __be32 err; 843 845 844 846 fh_init(fh, NFS3_FHSIZE); 845 - err = compose_entry_fh(cd, fh, name, namlen); 847 + err = compose_entry_fh(cd, fh, name, namlen, ino); 846 848 if (err) { 847 849 *p++ = 0; 848 850 *p++ = 0; ··· 929 927 p = encode_entry_baggage(cd, p, name, namlen, ino); 930 928 931 929 if (plus) 932 - p = encode_entryplus_baggage(cd, p, name, namlen); 930 + p = encode_entryplus_baggage(cd, p, name, namlen, ino); 933 931 num_entry_words = p - cd->buffer; 934 932 } else if (*(page+1) != NULL) { 935 933 /* temporarily encode entry into next page, then move back to ··· 943 941 p1 = encode_entry_baggage(cd, p1, name, namlen, ino); 944 942 945 943 if (plus) 946 - p1 = encode_entryplus_baggage(cd, p1, name, namlen); 944 + p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino); 947 945 948 946 /* determine entry word length and lengths to go in pages */ 949 947 num_entry_words = p1 - tmp;