Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Dec 2002 12:25:43 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Alfred Perlstein <bright@mu.org>
Cc:        arch@freebsd.org, <bde@freebsd.org>
Subject:   Re: pipes and FIONBIO breakage?
Message-ID:  <20021222113905.C7736-100000@gamplex.bde.org>
In-Reply-To: <20021221042734.GL23663@elvis.mu.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 20 Dec 2002, Alfred Perlstein wrote:

> * Alfred Perlstein <bright@mu.org> [021220 18:37] wrote:
> > I noticed that the ioctl handler for pipes doesn't do anything for
> > FIONBIO requests, this is in contrast to the socket handling of
> > FIONBIO requests which sets the SS_NBIO flag in the socket structure.
>
> Well the road to hell...
>
> It actually appears that this is a non-issue for pipe versus sockets.
> This is because dup does a shallow copy of struct file.

Things work correctly at the file descriptor level and almost correctly
for ordinary pipes.  kern_descrip.c maintains the FNONBLOCK flag in
the file struct and arranges to pass it to read/write/etc.  pipe_read()
and pipe_write() ignore their `flags' arg and determine the FNONBLOCK
flag by accessing the file struct direct.  This is a layering violation.
Most device drivers can't even think about doing it without it being
a clear violation since they don't have a pointer to the file struct
in scope.  However, accessing the current value of the flag may be
best since the value in the flags arg can't be changed by fcntl() or
FIONBIO and it may be right to permit unblocking of blocked i/o by
changing the flag.

FIONBIO handling is a little different and uglier.  Both
fcntl(... F_SETFL ...) and ioctl(... FIONBIO ...) set the FNONBLOCK
flag in the file struct and call fo_ioctl(... FIONBIO ...) to duplicat
any bogus copies of the flag in lower level structs.  Non-broken lower
levels don't have a bogus copy of the flag so FIONBIO is null at
their level.  The sys_pipe.c level is one of these, so
pipe_ioctl(... FIONBIO ...) returns successfully after doing nothing
except fiddling with locks.

> This _would_
> have been a problem for fifo's, however that code seems to duplicate
> the pipe code somewhat.

Fifos mostly use the socket code.  They get the non-blocking flag
correctly (except it may become stale -- see above) in fifo_read()
and fifo_write() and duplicate it in the socket struct.  The second
part of this is broken -- there may be different file structs with
different flags (one for each open()), but there is only 1 socket
struct.  The flag doesn't get duplicated in the socket struct by
fifo_ioctl() because fifo_ioctl() knows that fifo_read() and
fifo_write() maintain it and just returns without calling soo_ioctl().

> There does appear to be an issue where the fifo code temporarity
> ORs in the non-block state of the struct file into the socket behind
> it when performing reads and writes.  This might cause someone else
> to block when multiple people open a fifo because of races.

Yes, it seems to be easy for processes to clobber other processes'
blocking state state either way.  fifo_read() and fifo_write() don't
even manage to restore the socket struct's copy of the flag to its
initial state.  They always turn it off if they set it, even if it
was initially on.  This implements clobbering of the state from
on to off, but not soon enough to help processes that actually want
it off, since the flag is assumed to be initially off and not changed
in the !(ap->a_ioflag & IO_NDELAY) case until after doing the i/o.

This bug suite seems to mostly not affect normal sockets since open()
doesn't work on them so one copy of the file flags is sufficient.

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




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