diff mbox series

cifs: fix skipping to incorrect offset in emit_cached_dirents

Message ID 20221006043609.1193398-2-lsahlber@redhat.com
State New
Headers show
Series cifs: fix skipping to incorrect offset in emit_cached_dirents | expand

Commit Message

Ronnie Sahlberg Oct. 6, 2022, 4:36 a.m. UTC
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.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 fs/cifs/readdir.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

Comments

Steve French Oct. 6, 2022, 5:18 a.m. UTC | #1
here is the updated version of patch 4 which I was planning to use
(minor rebase, and trivial checkpatch cleanup).  Let me know if ok


On Wed, Oct 5, 2022 at 11:36 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> 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.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/cifs/readdir.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index 8e060c00c969..da0d1e188432 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -847,9 +847,13 @@ static bool emit_cached_dirents(struct cached_dirents *cde,
>         int rc;
>
>         list_for_each_entry(dirent, &cde->entries, entry) {
> -               if (ctx->pos >= dirent->pos)
> +               /*
> +                * Skip ahead until we get to the current position of the
> +                * directory.
> +                */
> +               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);
> --
> 2.35.3
>
Steve French Oct. 6, 2022, 5:21 a.m. UTC | #2
tentatively added to cifs-2.6.git for-next pending testing

On Wed, Oct 5, 2022 at 11:36 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> 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.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/cifs/readdir.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index 8e060c00c969..da0d1e188432 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -847,9 +847,13 @@ static bool emit_cached_dirents(struct cached_dirents *cde,
>         int rc;
>
>         list_for_each_entry(dirent, &cde->entries, entry) {
> -               if (ctx->pos >= dirent->pos)
> +               /*
> +                * Skip ahead until we get to the current position of the
> +                * directory.
> +                */
> +               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);
> --
> 2.35.3
>
Steve French Oct. 8, 2022, 3:21 p.m. UTC | #3
Adding this one patch onto for-next, it went from passing all (except
452 which is known issue with refcount and umount/mount) of buildbot
cifs-testing group to hanging on generic/010 and generic/024 to
Windows (interestingly 024 did not hang when run to Samba)

On Wed, Oct 5, 2022 at 11:36 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> 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.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/cifs/readdir.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index 8e060c00c969..da0d1e188432 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -847,9 +847,13 @@ static bool emit_cached_dirents(struct cached_dirents *cde,
>         int rc;
>
>         list_for_each_entry(dirent, &cde->entries, entry) {
> -               if (ctx->pos >= dirent->pos)
> +               /*
> +                * Skip ahead until we get to the current position of the
> +                * directory.
> +                */
> +               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);
> --
> 2.35.3
>
Aurélien Aptel Oct. 9, 2022, 5:54 p.m. UTC | #4
Hi,

Make sure you're not re-introducing the bug where the first few files
are missing when mounting the root of a Windows drive.

See fix https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/cifs/smb2ops.c?id=0595751f267994c3c7027377058e4185b3a28e75

And bug https://bugzilla.samba.org/show_bug.cgi?id=13107

Cheers,
ronnie sahlberg Oct. 10, 2022, 5:12 a.m. UTC | #5
On Mon, 10 Oct 2022 at 04:04, Aurélien Aptel <aurelien.aptel@gmail.com> wrote:
>
> Hi,
>
> Make sure you're not re-introducing the bug where the first few files
> are missing when mounting the root of a Windows drive.
>
> See fix https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/cifs/smb2ops.c?id=0595751f267994c3c7027377058e4185b3a28e75
>
> And bug https://bugzilla.samba.org/show_bug.cgi?id=13107

Yeah.
What confuses things is that we do not create a contignous sequence of
index positions when we emit a directory.
For the dir_context, ctx->pos starts at 0 for the first entry and then
increments by one for each other entry.
We do not currently create a contignous space but one with one or two
holes in it.
We start by explicitely emitting '.' and '..' and these are at
position 0 and 2 respectively.
But then, for a server that for example DOES return entries for '.'
and '..' we skip emitting these entries but still increment pos,
thus we end up with a sequence for index positions of the entries of
0,1,4,5,6,7,...
I.e. there is a hole in the sequence where 2 and 3 are missing becasue
these were the dot directories that the server responded
and that we did not emit, but we incremented pos.

This should ideally be fixed because otherwise, what would lseek(3), mean ?
>
> Cheers,
diff mbox series

Patch

diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 8e060c00c969..da0d1e188432 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -847,9 +847,13 @@  static bool emit_cached_dirents(struct cached_dirents *cde,
 	int rc;
 
 	list_for_each_entry(dirent, &cde->entries, entry) {
-		if (ctx->pos >= dirent->pos)
+		/*
+		 * Skip ahead until we get to the current position of the
+		 * directory.
+		 */
+		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);