Date: Tue, 28 Apr 2015 00:44:29 +0800 From: Julian Elischer <julian@freebsd.org> To: John Baldwin <jhb@freebsd.org> Cc: freebsd-current@freebsd.org Subject: Re: readdir/telldir/seekdir problem (i think) Message-ID: <553E676D.1020902@freebsd.org> In-Reply-To: <4718551.Y2ZnMk6NSM@ralph.baldwin.cx> References: <55386505.70708@freebsd.org> <553A7DB0.8080308@freebsd.org> <553A8D28.7090901@freebsd.org> <4718551.Y2ZnMk6NSM@ralph.baldwin.cx>
next in thread | previous in thread | raw e-mail | index | archive | help
On 4/25/15 4:28 AM, John Baldwin wrote: > On Saturday, April 25, 2015 02:36:24 AM Julian Elischer wrote: >> On 4/25/15 1:30 AM, Julian Elischer wrote: >>> On 4/24/15 10:59 PM, John Baldwin wrote: >>>> Index: head/lib/libc/gen/telldir.c >>>> =================================================================== >>>> --- head/lib/libc/gen/telldir.c (revision 281929) >>>> +++ head/lib/libc/gen/telldir.c (working copy) >>>> @@ -101,8 +101,10 @@ >>>> return; >>>> if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == >>>> dirp->dd_seek) >>>> return; >>>> - (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); >>>> - dirp->dd_seek = lp->loc_seek; >>>> + if (lp->loc_seek != dirp->dd_seek) { >>>> + (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, >>>> SEEK_SET); >>>> + dirp->dd_seek = lp->loc_seek; >>>> + } >>> yes I did that yesterday but it still fails when you transition >>> blocks.. (badly). >>> >>> I also tried bigger blocks.. also fails (eventually) >>> >>> I did find a way to make it work... you had to seek back >>> to the first block you deleted on each set.. >>> then work forward from there again.. unfortunately since >>> I'm trying to make a microsoft program not fail (via samba) >>> I have no control over how it does things and seekdir doesn't >>> know what was deleted anyway... (so the fix is fine for the >>> test program but not for real life) >>> >>> I think I can make the BSD one act like the linux one by changing >>> the lseek being done to use the offset (loc) plus the buffer seek >>> address of the target, instead of just going for the buffer base and >>> stepping forward through the entries.. >>> >>> maybe tomorrow. >>> >> The following conditional code makes ours behave the same as the linux >> one. >> it breaks several 'rules' but works where ours is clean but fails.. >> as Rick said.. "maybe that's what we should do too." >> >> >> this is at the end of seekdir() >> >> >> The new code does what linux does.. and shouldn't work.. but does >> // at least in the limited conditions I need it to. >> // We'll probably need to do this at work...: >> >> >> The original code is what we have now, but gets mightily confused >> sometimes. >> // This is clean(er) but fails in specific situations(when >> doing commands >> // from Microft windows, via samba). >> >> >> root@vps1:/tmp # diff -u dir.c.orig dir.c >> --- dir.c.orig 2015-04-24 11:29:36.855317000 -0700 >> +++ dir.c 2015-04-24 11:15:49.058500000 -0700 >> @@ -1105,6 +1105,13 @@ >> dirp->dd_loc = lp->loc_loc; >> return; >> } >> +#ifdef GLIBC_SEEK >> + (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek + lp->loc_loc, >> SEEK_SET); >> + dirp->dd_seek = lp->loc_seek + lp->loc_loc; >> + dirp->dd_loc = 0; >> + lp->loc_seek = dirp->dd_seek; >> + lp->loc_loc = 0; >> +#else >> (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET); >> dirp->dd_seek = lp->loc_seek; >> dirp->dd_loc = 0; >> @@ -1114,6 +1121,7 @@ >> if (dp == NULL) >> break; >> } >> +#endif >> } > Yes, this isn't at all safe. There's no guarantee whatsoever that > the offset on the directory fd that isn't something returned by > getdirentries has any meaning. In particular, the size of the > directory entry in a random filesystem might be a different size > than the structure returned by getdirentries (since it converts > things into a FS-independent format). > > This might work for UFS by accident, but this is probably why ZFS > doesn't work. > > However, this might be properly fixed by the thing that ino64 is > doing where each directory entry returned by getdirentries gives > you a seek offset that you _can_ directly seek to (as opposed to > seeking to the start of the block and then walking forward N > entries until you get an inter-block entry that is the same). I just made the stunning discovery that our seekdir/readdir/telldir code in libc works with FreeBSD 8.0. so maybe the problem is that the kernel changed it's behaviour, and no-one thought to fix libc.. (at least it works on one of our 8.0 base appliances.. I'll do more testing tomorrow.. it's past midnight.) >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?553E676D.1020902>