NFS: advance nfs_entry cookie only after decoding completes successfully
In nfs[34]_decode_dirent, the cookie is advanced as soon as it is read, but decoding may still fail later in the function, returning an error. Because the cookie has been advanced, the failing entry is not re-requested from the server, resulting in a missing directory entry. In addition, nfs v3 and v4 read the cookie at different locations in the xdr_stream, so the behavior of the two can be inconsistent. Fix these by reading the cookie into a temporary variable, and only advancing the cookie once the entire entry has been decoded from the xdr_stream successfully. Signed-off-by: Frank Sorenson <sorenson@redhat.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
dbc898ae10
commit
98de9ce6f6
2 changed files with 10 additions and 4 deletions
|
@ -1997,6 +1997,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
struct nfs_entry old = *entry;
|
struct nfs_entry old = *entry;
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
int error;
|
int error;
|
||||||
|
u64 new_cookie;
|
||||||
|
|
||||||
p = xdr_inline_decode(xdr, 4);
|
p = xdr_inline_decode(xdr, 4);
|
||||||
if (unlikely(p == NULL))
|
if (unlikely(p == NULL))
|
||||||
|
@ -2019,8 +2020,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
entry->prev_cookie = entry->cookie;
|
error = decode_cookie3(xdr, &new_cookie);
|
||||||
error = decode_cookie3(xdr, &entry->cookie);
|
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -2054,6 +2054,9 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
zero_nfs_fh3(entry->fh);
|
zero_nfs_fh3(entry->fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry->prev_cookie = entry->cookie;
|
||||||
|
entry->cookie = new_cookie;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_overflow:
|
out_overflow:
|
||||||
|
|
|
@ -7518,6 +7518,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
unsigned int savep;
|
unsigned int savep;
|
||||||
uint32_t bitmap[3] = {0};
|
uint32_t bitmap[3] = {0};
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
uint64_t new_cookie;
|
||||||
__be32 *p = xdr_inline_decode(xdr, 4);
|
__be32 *p = xdr_inline_decode(xdr, 4);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
goto out_overflow;
|
goto out_overflow;
|
||||||
|
@ -7534,8 +7535,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
p = xdr_inline_decode(xdr, 12);
|
p = xdr_inline_decode(xdr, 12);
|
||||||
if (unlikely(!p))
|
if (unlikely(!p))
|
||||||
goto out_overflow;
|
goto out_overflow;
|
||||||
entry->prev_cookie = entry->cookie;
|
p = xdr_decode_hyper(p, &new_cookie);
|
||||||
p = xdr_decode_hyper(p, &entry->cookie);
|
|
||||||
entry->len = be32_to_cpup(p);
|
entry->len = be32_to_cpup(p);
|
||||||
|
|
||||||
p = xdr_inline_decode(xdr, entry->len);
|
p = xdr_inline_decode(xdr, entry->len);
|
||||||
|
@ -7569,6 +7569,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
|
||||||
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
|
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
|
||||||
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
|
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
|
||||||
|
|
||||||
|
entry->prev_cookie = entry->cookie;
|
||||||
|
entry->cookie = new_cookie;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_overflow:
|
out_overflow:
|
||||||
|
|
Loading…
Reference in a new issue