aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Sorenson <sorenson@redhat.com>2018-04-02 17:12:45 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2018-04-10 16:06:22 -0400
commit98de9ce6f6660d02aa72d7b9b17696fa68a2ed9b (patch)
tree982362bc07561f05a8bd60385b40fe29c8e713ae
parentdbc898ae107104ef49fd977a593e521fcefab5aa (diff)
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>
-rw-r--r--fs/nfs/nfs3xdr.c7
-rw-r--r--fs/nfs/nfs4xdr.c7
2 files changed, 10 insertions, 4 deletions
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 6cd33bd5da87..09ee36dd8426 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -1997,6 +1997,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1997 struct nfs_entry old = *entry; 1997 struct nfs_entry old = *entry;
1998 __be32 *p; 1998 __be32 *p;
1999 int error; 1999 int error;
2000 u64 new_cookie;
2000 2001
2001 p = xdr_inline_decode(xdr, 4); 2002 p = xdr_inline_decode(xdr, 4);
2002 if (unlikely(p == NULL)) 2003 if (unlikely(p == NULL))
@@ -2019,8 +2020,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
2019 if (unlikely(error)) 2020 if (unlikely(error))
2020 return error; 2021 return error;
2021 2022
2022 entry->prev_cookie = entry->cookie; 2023 error = decode_cookie3(xdr, &new_cookie);
2023 error = decode_cookie3(xdr, &entry->cookie);
2024 if (unlikely(error)) 2024 if (unlikely(error))
2025 return error; 2025 return error;
2026 2026
@@ -2054,6 +2054,9 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
2054 zero_nfs_fh3(entry->fh); 2054 zero_nfs_fh3(entry->fh);
2055 } 2055 }
2056 2056
2057 entry->prev_cookie = entry->cookie;
2058 entry->cookie = new_cookie;
2059
2057 return 0; 2060 return 0;
2058 2061
2059out_overflow: 2062out_overflow:
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 51264f5d9d2a..aa550fb08d2a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7518,6 +7518,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
7518 unsigned int savep; 7518 unsigned int savep;
7519 uint32_t bitmap[3] = {0}; 7519 uint32_t bitmap[3] = {0};
7520 uint32_t len; 7520 uint32_t len;
7521 uint64_t new_cookie;
7521 __be32 *p = xdr_inline_decode(xdr, 4); 7522 __be32 *p = xdr_inline_decode(xdr, 4);
7522 if (unlikely(!p)) 7523 if (unlikely(!p))
7523 goto out_overflow; 7524 goto out_overflow;
@@ -7534,8 +7535,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
7534 p = xdr_inline_decode(xdr, 12); 7535 p = xdr_inline_decode(xdr, 12);
7535 if (unlikely(!p)) 7536 if (unlikely(!p))
7536 goto out_overflow; 7537 goto out_overflow;
7537 entry->prev_cookie = entry->cookie; 7538 p = xdr_decode_hyper(p, &new_cookie);
7538 p = xdr_decode_hyper(p, &entry->cookie);
7539 entry->len = be32_to_cpup(p); 7539 entry->len = be32_to_cpup(p);
7540 7540
7541 p = xdr_inline_decode(xdr, entry->len); 7541 p = xdr_inline_decode(xdr, entry->len);
@@ -7569,6 +7569,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
7569 if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) 7569 if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
7570 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 7570 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
7571 7571
7572 entry->prev_cookie = entry->cookie;
7573 entry->cookie = new_cookie;
7574
7572 return 0; 7575 return 0;
7573 7576
7574out_overflow: 7577out_overflow: