| From f2e717d655040d632c9015f19aa4275f8b16e7f2 Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Date: Thu, 30 Sep 2021 15:44:41 -0400 |
| Subject: nfsd4: Handle the NFSv4 READDIR 'dircount' hint being zero |
| |
| From: Trond Myklebust <trond.myklebust@hammerspace.com> |
| |
| commit f2e717d655040d632c9015f19aa4275f8b16e7f2 upstream. |
| |
| RFC3530 notes that the 'dircount' field may be zero, in which case the |
| recommendation is to ignore it, and only enforce the 'maxcount' field. |
| In RFC5661, this recommendation to ignore a zero valued field becomes a |
| requirement. |
| |
| Fixes: aee377644146 ("nfsd4: fix rd_dircount enforcement") |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Chuck Lever <chuck.lever@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/nfsd/nfs4xdr.c | 19 +++++++++++-------- |
| 1 file changed, 11 insertions(+), 8 deletions(-) |
| |
| --- a/fs/nfsd/nfs4xdr.c |
| +++ b/fs/nfsd/nfs4xdr.c |
| @@ -3124,15 +3124,18 @@ nfsd4_encode_dirent(void *ccdv, const ch |
| goto fail; |
| cd->rd_maxcount -= entry_bytes; |
| /* |
| - * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so |
| - * let's always let through the first entry, at least: |
| + * RFC 3530 14.2.24 describes rd_dircount as only a "hint", and |
| + * notes that it could be zero. If it is zero, then the server |
| + * should enforce only the rd_maxcount value. |
| */ |
| - if (!cd->rd_dircount) |
| - goto fail; |
| - name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8; |
| - if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) |
| - goto fail; |
| - cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); |
| + if (cd->rd_dircount) { |
| + name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8; |
| + if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) |
| + goto fail; |
| + cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); |
| + if (!cd->rd_dircount) |
| + cd->rd_maxcount = 0; |
| + } |
| |
| cd->cookie_offset = cookie_offset; |
| skip_entry: |