Re: Should close() release locks atomically?

From: Alan Somers <asomers_at_freebsd.org>
Date: Sat, 24 Jun 2023 15:29:01 UTC
On Fri, Jun 23, 2023 at 1:53 PM Alan Somers <asomers@freebsd.org> wrote:
>
> On Fri, Jun 23, 2023 at 1:48 PM Konstantin Belousov <kostikbel@gmail.com> wrote:
> >
> > On Fri, Jun 23, 2023 at 01:11:34PM -0700, Alan Somers wrote:
> > > On Fri, Jun 23, 2023 at 1:03 PM Konstantin Belousov <kostikbel@gmail.com> wrote:
> > > >
> > > > On Fri, Jun 23, 2023 at 12:00:36PM -0700, Alan Somers wrote:
> > > > > The close() syscall automatically releases locks.  Should it do so
> > > > > atomically or is a delay permitted?  I can't find anything in our man
> > > > > pages or the open group specification that says.
> > > > >
> > > > > The distinction matters when using O_NONBLOCK.  For example:
> > > > >
> > > > > fd = open(..., O_DIRECT | O_EXLOCK | O_NONBLOCK); //succeeds
> > > > > // do some I/O
> > > > > close(fd);
> > > > > fd = open(..., O_DIRECT | O_EXLOCK | O_NONBLOCK); //fails with EAGAIN!
> > > > >
> > > > > I see this error frequently on a heavily loaded system.  It isn't a
> > > > > typical thread race though; ktrace shows that only one thread tries to
> > > > > open the file in question.  From the ktrace, I can see that the final
> > > > > open() comes immediately after the close(), with no intervening
> > > > > syscalls from that thread.  It seems that close() doesn't release the
> > > > > lock right away.  I wouldn't notice if I weren't using O_NONBLOCK.
> > > > >
> > > > > Should this be considered a bug?  If so I could try to come up with a
> > > > > minimal test case.  But it's somewhat academic, since I plan to
> > > > > refactor the code in a way that will eliminate the duplicate open().
> > > > What type of the object is behind fd?  O_NONBLOCK affects open itself.
> > > > We release flock after object close method, but before close(2) returns.
> > >
> > > This is a plain file on ZFS.
> >
> > Can you write a self-contained example, and check the same issue e.g. on
> > tmpfs?
>
> I just reproduced it on tmpfs.  A minimal test case will take some more time...

I'm afraid that I haven't been successful in creating a minimal test
case.  My original test case, while it reliably reproduces the
problem, is huge.  I'm sorry, but I think I'm going to declare ENOTIME
and get back to the aforementioned refactoring.