Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Apr 2015 23:52:49 +0200
From:      Jilles Tjoelker <jilles@stack.nl>
To:        John Baldwin <jhb@freebsd.org>
Cc:        Julian Elischer <julian@freebsd.org>, freebsd-current@freebsd.org
Subject:   Re: readdir/telldir/seekdir problem (i think)
Message-ID:  <20150424215249.GA96554@stack.nl>
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 Fri, Apr 24, 2015 at 04:28:12PM -0400, John Baldwin wrote:
> 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).

The ino64 branch only reserves space for d_off and does not use it in
any way. This is appropriate since actually using d_off is a major
feature addition.

A proper d_off would still be useful even if UFS's readdir keeps masking
off the offset so a directory read always starts at the beginning of a
512-byte directory block, since this allows more distinct offset values
than safely using getdirentries()'s *basep. With d_off, one outer loop
must read at least one directory block to avoid spinning indefinitely,
while using getdirentries()'s *basep requires reading the whole
getdirentries() buffer.

Some Linux filesystems go further and provide a unique d_off for each
entry.

Another idea would be to store the last d_ino instead of dd_loc into the
struct ddloc. On seekdir(), this would seek to loc_seek as before and
skip entries until that d_ino is found, or to the start of the buffer if
not found (and possibly return some entries again that should not be
returned, but Samba copes with that).

-- 
Jilles Tjoelker



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