aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2015-05-02 19:16:53 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-05-07 11:47:00 -0400
commit43b0e7ea590b51052384ecedf4ad7c8d7898e8e7 (patch)
tree506113d48acf247d47ec07ee33b31c5332a00087
parent72faedae8bc3504ee4252cebf14737a23677cb8f (diff)
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>
-rw-r--r--fs/nfsd/nfs3xdr.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index e4b2b4322553..f6e7cbabac5a 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -805,7 +805,7 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
805 805
806static __be32 806static __be32
807compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, 807compose_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 struct svc_export *exp; 810 struct svc_export *exp;
811 struct dentry *dparent, *dchild; 811 struct dentry *dparent, *dchild;
@@ -830,19 +830,21 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
830 goto out; 830 goto out;
831 if (d_really_is_negative(dchild)) 831 if (d_really_is_negative(dchild))
832 goto out; 832 goto out;
833 if (dchild->d_inode->i_ino != ino)
834 goto out;
833 rv = fh_compose(fhp, exp, dchild, &cd->fh); 835 rv = fh_compose(fhp, exp, dchild, &cd->fh);
834out: 836out:
835 dput(dchild); 837 dput(dchild);
836 return rv; 838 return rv;
837} 839}
838 840
839static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen) 841static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino)
840{ 842{
841 struct svc_fh *fh = &cd->scratch; 843 struct svc_fh *fh = &cd->scratch;
842 __be32 err; 844 __be32 err;
843 845
844 fh_init(fh, NFS3_FHSIZE); 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 if (err) { 848 if (err) {
847 *p++ = 0; 849 *p++ = 0;
848 *p++ = 0; 850 *p++ = 0;
@@ -927,7 +929,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
927 p = encode_entry_baggage(cd, p, name, namlen, ino); 929 p = encode_entry_baggage(cd, p, name, namlen, ino);
928 930
929 if (plus) 931 if (plus)
930 p = encode_entryplus_baggage(cd, p, name, namlen); 932 p = encode_entryplus_baggage(cd, p, name, namlen, ino);
931 num_entry_words = p - cd->buffer; 933 num_entry_words = p - cd->buffer;
932 } else if (*(page+1) != NULL) { 934 } else if (*(page+1) != NULL) {
933 /* temporarily encode entry into next page, then move back to 935 /* temporarily encode entry into next page, then move back to
@@ -941,7 +943,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
941 p1 = encode_entry_baggage(cd, p1, name, namlen, ino); 943 p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
942 944
943 if (plus) 945 if (plus)
944 p1 = encode_entryplus_baggage(cd, p1, name, namlen); 946 p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);
945 947
946 /* determine entry word length and lengths to go in pages */ 948 /* determine entry word length and lengths to go in pages */
947 num_entry_words = p1 - tmp; 949 num_entry_words = p1 - tmp;