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>
This commit is contained in:
parent
72faedae8b
commit
43b0e7ea59
|
@ -805,7 +805,7 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
|
compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
|
||||||
const char *name, int namlen)
|
const char *name, int namlen, u64 ino)
|
||||||
{
|
{
|
||||||
struct svc_export *exp;
|
struct svc_export *exp;
|
||||||
struct dentry *dparent, *dchild;
|
struct dentry *dparent, *dchild;
|
||||||
|
@ -830,19 +830,21 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
|
||||||
goto out;
|
goto out;
|
||||||
if (d_really_is_negative(dchild))
|
if (d_really_is_negative(dchild))
|
||||||
goto out;
|
goto out;
|
||||||
|
if (dchild->d_inode->i_ino != ino)
|
||||||
|
goto out;
|
||||||
rv = fh_compose(fhp, exp, dchild, &cd->fh);
|
rv = fh_compose(fhp, exp, dchild, &cd->fh);
|
||||||
out:
|
out:
|
||||||
dput(dchild);
|
dput(dchild);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
|
static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino)
|
||||||
{
|
{
|
||||||
struct svc_fh *fh = &cd->scratch;
|
struct svc_fh *fh = &cd->scratch;
|
||||||
__be32 err;
|
__be32 err;
|
||||||
|
|
||||||
fh_init(fh, NFS3_FHSIZE);
|
fh_init(fh, NFS3_FHSIZE);
|
||||||
err = compose_entry_fh(cd, fh, name, namlen);
|
err = compose_entry_fh(cd, fh, name, namlen, ino);
|
||||||
if (err) {
|
if (err) {
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
|
@ -927,7 +929,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
|
||||||
p = encode_entry_baggage(cd, p, name, namlen, ino);
|
p = encode_entry_baggage(cd, p, name, namlen, ino);
|
||||||
|
|
||||||
if (plus)
|
if (plus)
|
||||||
p = encode_entryplus_baggage(cd, p, name, namlen);
|
p = encode_entryplus_baggage(cd, p, name, namlen, ino);
|
||||||
num_entry_words = p - cd->buffer;
|
num_entry_words = p - cd->buffer;
|
||||||
} else if (*(page+1) != NULL) {
|
} else if (*(page+1) != NULL) {
|
||||||
/* temporarily encode entry into next page, then move back to
|
/* 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,
|
||||||
p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
|
p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
|
||||||
|
|
||||||
if (plus)
|
if (plus)
|
||||||
p1 = encode_entryplus_baggage(cd, p1, name, namlen);
|
p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);
|
||||||
|
|
||||||
/* determine entry word length and lengths to go in pages */
|
/* determine entry word length and lengths to go in pages */
|
||||||
num_entry_words = p1 - tmp;
|
num_entry_words = p1 - tmp;
|
||||||
|
|
Loading…
Reference in New Issue