From owner-freebsd-current@FreeBSD.ORG Mon Apr 27 16:44:49 2015 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 856495BD; Mon, 27 Apr 2015 16:44:49 +0000 (UTC) Received: from vps1.elischer.org (vps1.elischer.org [204.109.63.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "vps1.elischer.org", Issuer "CA Cert Signing Authority" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 655E11D17; Mon, 27 Apr 2015 16:44:49 +0000 (UTC) Received: from Julian-MBP3.local (ppp121-45-241-118.lns20.per4.internode.on.net [121.45.241.118]) (authenticated bits=0) by vps1.elischer.org (8.14.9/8.14.9) with ESMTP id t3RGiauP041206 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Mon, 27 Apr 2015 09:44:41 -0700 (PDT) (envelope-from julian@freebsd.org) Message-ID: <553E676D.1020902@freebsd.org> Date: Tue, 28 Apr 2015 00:44:29 +0800 From: Julian Elischer User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 MIME-Version: 1.0 To: John Baldwin CC: freebsd-current@freebsd.org Subject: Re: readdir/telldir/seekdir problem (i think) References: <55386505.70708@freebsd.org> <553A7DB0.8080308@freebsd.org> <553A8D28.7090901@freebsd.org> <4718551.Y2ZnMk6NSM@ralph.baldwin.cx> In-Reply-To: <4718551.Y2ZnMk6NSM@ralph.baldwin.cx> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Apr 2015 16:44:49 -0000 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.) >