Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Aug 2017 07:42:36 -0700
From:      Conrad Meyer <cem@freebsd.org>
To:        freebsd-fs@freebsd.org
Subject:   Re: Can telldir() == 0 value be made special?
Message-ID:  <CAG6CVpVViqnbGuVn_JETBC5Q0NoYfC4VJK7iWjEfA7tFurQ2ag@mail.gmail.com>
In-Reply-To: <87bmn7kf3b.fsf@vostro.rath.org>
References:  <87bmn7kf3b.fsf@vostro.rath.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Hi Nikolaus,

As you have surmised, DIR* seekpoints are created dynamically whenever
requested by user's telldir() call:

https://github.com/freebsd/freebsd/blob/master/lib/libc/gen/telldir.c#L53

I believe we could special case zero without breaking ABI
compatibility of correct programs.  Something like this:

--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -70,6 +70,20 @@ telldir(DIR *dirp)
                }
        }
        if (lp =3D=3D NULL) {
+               /* Create special zero telldir entry, similar to Linux */
+               if (dirp->dd_td->td_loccnt =3D=3D 0 && dirp->dd_loc !=3D 0)=
 {
+                       lp =3D malloc(sizeof(struct ddloc));
+                       if (lp =3D=3D NULL) {
+                               if (__isthreaded)
+                                       _pthread_mutex_unlock(&dirp->dd_loc=
k);
+                               return (-1);
+                       }
+                       lp->loc_index =3D dirp->dd_td->td_loccnt++;
+                       lp->loc_seek =3D 0;
+                       lp->loc_loc =3D 0;
+                       LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe=
);
+               }
+
                lp =3D malloc(sizeof(struct ddloc));
                if (lp =3D=3D NULL) {
                        if (__isthreaded)

I don't know if there are any downsides to special-casing zero like
this, other than additional code complexity.

Best,
Conrad

On Tue, Aug 22, 2017 at 4:38 AM, Nikolaus Rath <Nikolaus@rath.org> wrote:
> Hello,
>
> I am trying to debug a test failure of libfuse under FreeBSD. I believe
> I have reduced it to the following root cause:
>
> Consider the following program:
>
> #include <stdio.h>
> #include <dirent.h>
> #include <sys/types.h>
>
> int main(void) {
>     struct dirent *e =3D NULL;
>     DIR *dirp;
>
>     printf("opendir...\n");
>     dirp =3D opendir("/");
>     if(dirp =3D=3D NULL) {
>         perror("opendir");
>         return 1;
>     }
>     printf("telldir: %ld\n", telldir(dirp));
>     e =3D readdir(dirp);
>     printf("readdir: %s\n", e->d_name);
>     printf("telldir: %ld\n", telldir(dirp));
>     e =3D readdir(dirp);
>     printf("readdir: %s\n", e->d_name);
>     printf("closedir..\n");
>     closedir(dirp);
>
>     printf("opendir...\n");
>     dirp =3D opendir("/");
>     if(dirp =3D=3D NULL) {
>         perror("opendir");
>         return 1;
>     }
>     e =3D readdir(dirp);
>     printf("readdir: %s\n", e->d_name);
>     printf("telldir: %ld\n", telldir(dirp));
>     e =3D readdir(dirp);
>     printf("readdir: %s\n", e->d_name);
>     printf("closedir..\n");
>     closedir(dirp);
>
>     return 0;
> }
>
>
> Under FreeBSD, running it gives:
>
> # ./simple
> opendir...
> telldir: 0
> readdir: .
> telldir: 1
> readdir: ..
> closedir..
> opendir...
> readdir: .
> telldir: 0
> readdir: ..
> closedir..
>
> In other words, if telldir() is called right after opendir(), it gives
> an offset of zero. But if telldir() is called only after the first
> readdir() call, it also gives an offset of zero. My hypothesis is that
> FreeBSD actually just enumerates the different telldir() calls - is that
> correct?
>
> Now, the offsets returned by telldir() are documented to be valid only
> within a given *dirp, so FreeBSD isn't doing anything wrong.
>
> However, having different meanings even for an offset of zero causes
> problems for libfuse, because under Linux an offset of zero is
> guaranteed to mean "first entry". This is reflected in the definition of
> the fuse readdir() function which always receives an *offset* parameter
> that needs to have a definite value even when telldir() was never
> called. If zero is suddenly also a valid telldir() return value that may
> indicate some other position in the stream, things get complicated.
>
> Now, I think I managed to work around that by shifting all offsets by
> one, but that is awkward (and I may have overlooked some problems that
> the unit tests don't cover). So I am wondering:
>
> Is there a reason why the FreeBSD kernel could not start enumerating
> telldir() offsets with 1, so that 0 can always have the same meaning?
>
>
> Best,
> -Nikolaus
>
> --
> GPG Fingerprint: ED31 791B 2C5C 1613 AF38 8B8A D113 FCAC 3C4E 599F
>
>              =C2=BBTime flies like an arrow, fruit flies like a Banana.=
=C2=AB
> _______________________________________________
> freebsd-fs@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-fs
> To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAG6CVpVViqnbGuVn_JETBC5Q0NoYfC4VJK7iWjEfA7tFurQ2ag>