NFS: advance nfs_entry cookie only after decoding completes successfully
authorFrank Sorenson <sorenson@redhat.com>
Mon, 2 Apr 2018 21:12:45 +0000 (16:12 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 10 Apr 2018 20:06:22 +0000 (16:06 -0400)
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>
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c

index 6cd33bd5da87c355c47ade6823e2c2683941e1b2..09ee36dd84262971296138b9945dc843b5926645 100644 (file)
@@ -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))
@@ -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;
 
@@ -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:
index 51264f5d9d2a072a2c697a94b1f469ee3c75b657..aa550fb08d2af3f9f84f7dc4ac9196a753fb8d39 100644 (file)
@@ -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;
@@ -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);
@@ -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: