When application has done lseek() to a different offset on a directory fd we skipped one entry too many before we start emitting directory entries from the cache. Also change cifs_filldir() to return -EEXIST when we encouter a dot-directory in the reply from the server. Check for this in the caller and skip caching the entry and skip incprementing ctx->pos or else we end up emitting a sequence of directory entries with holes in the ctx->pos space. Signed-off-by: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> --- fs/cifs/readdir.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 8e060c00c969..0c71a771b256 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -847,14 +847,14 @@ static bool emit_cached_dirents(struct cached_dirents *cde, int rc; list_for_each_entry(dirent, &cde->entries, entry) { - if (ctx->pos >= dirent->pos) + if (ctx->pos > dirent->pos) continue; - ctx->pos = dirent->pos; rc = dir_emit(ctx, dirent->name, dirent->namelen, dirent->fattr.cf_uniqueid, dirent->fattr.cf_dtype); if (!rc) return rc; + ctx->pos++; } return true; } @@ -965,7 +965,7 @@ static int cifs_filldir(char *find_entry, struct file *file, /* skip . and .. since we added them first */ if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) - return 0; + return -EEXIST; if (file_info->srch_inf.unicode) { struct nls_table *nlt = cifs_sb->local_nls; @@ -1183,6 +1183,17 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) *tmp_buf = 0; rc = cifs_filldir(current_entry, file, ctx, tmp_buf, max_len, cfid); + /* + * If we got a dot directory, just skip to the next entry. + * We have already emitted it. + */ + if (rc == -EEXIST) { + current_entry = + nxt_dir_entry(current_entry, end_of_smb, + cifsFile->srch_inf.info_level); + rc = 0; + continue; + } if (rc) { if (rc > 0) rc = 0; @@ -1202,10 +1213,10 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) ctx->pos, tmp_buf); cifs_save_resume_key(current_entry, cifsFile); break; - } else - current_entry = - nxt_dir_entry(current_entry, end_of_smb, - cifsFile->srch_inf.info_level); + } + current_entry = + nxt_dir_entry(current_entry, end_of_smb, + cifsFile->srch_inf.info_level); } kfree(tmp_buf); -- 2.35.3