In our production environment, we noticed that some files are missing when running the ls command in an NFS directory. However, we can still successfully cd into the missing directories. This issue can be illustrated as follows: $ cd nfs $ ls a b c e f <<<< 'd' is missing $ cd d <<<< success I verified the issue with the latest upstream kernel, and it still persists. Further analysis reveals that files go missing when the dtsize is expanded. The default dtsize was reduced from 1MB to 4KB in commit 580f236737d1 ("NFS: Adjust the amount of readahead performed by NFS readdir"). After restoring the default size to 1MB, the issue disappears. I also tried setting the default size to 8KB, and the issue similarly disappears. Upon further analysis, it appears that there is a bad entry being decoded in nfs_readdir_entry_decode(). When a bad entry is encountered, the decoding process breaks without handling the error. We should revert the bad entry in such cases. After implementing this change, the issue is resolved. However, I am unable to reproduce this issue with a simple example; it only occurs on our production servers. Signed-off-by: Yafang Shao <laoar.shao@xxxxxxxxx> --- fs/nfs/dir.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 07a7be27182e..1f5a99888a11 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -310,7 +310,7 @@ static int nfs_readdir_array_can_expand(struct nfs_cache_array *array) static int nfs_readdir_folio_array_append(struct folio *folio, const struct nfs_entry *entry, - u64 *cookie) + u64 *cookie, u64 *prev_cookie) { struct nfs_cache_array *array; struct nfs_cache_array_entry *cache_entry; @@ -342,6 +342,7 @@ static int nfs_readdir_folio_array_append(struct folio *folio, nfs_readdir_array_set_eof(array); out: *cookie = array->last_cookie; + *prev_cookie = cache_entry->cookie; kunmap_local(array); return ret; } @@ -826,10 +827,11 @@ static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc, { struct address_space *mapping = desc->file->f_mapping; struct folio *new, *folio = *arrays; + struct nfs_cache_array *array; struct xdr_stream stream; + u64 cookie, prev_cookie; struct page *scratch; struct xdr_buf buf; - u64 cookie; int status; scratch = alloc_page(GFP_KERNEL); @@ -841,10 +843,20 @@ static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc, do { status = nfs_readdir_entry_decode(desc, entry, &stream); - if (status != 0) + if (status != 0) { + if (status == -EAGAIN && entry->cookie == cookie) { + /* Revert the bad entry */ + array = kmap_local_folio(folio, 0); + array->last_cookie = prev_cookie; + desc->last_cookie = 0; + desc->dir_cookie = 0; + array->size--; + kunmap_local(array); + } break; + } - status = nfs_readdir_folio_array_append(folio, entry, &cookie); + status = nfs_readdir_folio_array_append(folio, entry, &cookie, &prev_cookie); if (status != -ENOSPC) continue; @@ -866,7 +878,7 @@ static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc, folio = new; } desc->folio_index_max++; - status = nfs_readdir_folio_array_append(folio, entry, &cookie); + status = nfs_readdir_folio_array_append(folio, entry, &cookie, &prev_cookie); } while (!status && !entry->eof); switch (status) { -- 2.30.1 (Apple Git-130)