Skip to content

Commit

Permalink
NFS: advance nfs_entry cookie only after decoding completes successfully
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Frank Sorenson authored and Anna Schumaker committed Apr 10, 2018
1 parent dbc898a commit 98de9ce
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 4 deletions.
7 changes: 5 additions & 2 deletions fs/nfs/nfs3xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1997,6 +1997,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
struct nfs_entry old = *entry;
__be32 *p;
int error;
u64 new_cookie;

p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL))
Expand All @@ -2019,8 +2020,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (unlikely(error))
return error;

entry->prev_cookie = entry->cookie;
error = decode_cookie3(xdr, &entry->cookie);
error = decode_cookie3(xdr, &new_cookie);
if (unlikely(error))
return error;

Expand Down Expand Up @@ -2054,6 +2054,9 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
zero_nfs_fh3(entry->fh);
}

entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;

return 0;

out_overflow:
Expand Down
7 changes: 5 additions & 2 deletions fs/nfs/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -7518,6 +7518,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
unsigned int savep;
uint32_t bitmap[3] = {0};
uint32_t len;
uint64_t new_cookie;
__be32 *p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
Expand All @@ -7534,8 +7535,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
p = xdr_inline_decode(xdr, 12);
if (unlikely(!p))
goto out_overflow;
entry->prev_cookie = entry->cookie;
p = xdr_decode_hyper(p, &entry->cookie);
p = xdr_decode_hyper(p, &new_cookie);
entry->len = be32_to_cpup(p);

p = xdr_inline_decode(xdr, entry->len);
Expand Down Expand Up @@ -7569,6 +7569,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);

entry->prev_cookie = entry->cookie;
entry->cookie = new_cookie;

return 0;

out_overflow:
Expand Down

0 comments on commit 98de9ce

Please sign in to comment.