[PATCH]: possible fix for the fifoor problem
Jung-uk Kim
jkim at FreeBSD.org
Wed Nov 8 15:07:51 UTC 2006
On Tuesday 07 November 2006 07:16 pm, Bruce Evans wrote:
> On Tue, 7 Nov 2006, Jung-uk Kim wrote:
> > On Tuesday 07 November 2006 12:19 pm, Divacky Roman wrote:
> >> the patch is wrong.... this forces NONBLOCKing on all opened
> >> files which is wrong.
> >
> > Nope. It does not force anything.
>
> But it does. open() has side effects for some file types, and does
> have signifcant side effects for fifos. The original problem is
> caused by the side effect of blocking. Opening for writing or
> read/write would have the side effect of unblocking all readers
> blocked in open() and letting their open() complete. Opening for
> reading gives more delicate state changes which might be harmless,
> but this is not clear.
Ah, you are correct. I had to think more thoroughly.
> > static void
> > translate_path_major_minor(struct thread *td, char *path, struct
> > stat *buf) {
> > struct proc *p = td->td_proc;
> > struct filedesc *fdp = p->p_fd;
> > struct file *fp;
> > int fd;
> > int temp;
> >
> > temp = td->td_retval[0];
> > if (kern_open(td, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
> > return;
> > fd = td->td_retval[0];
> > td->td_retval[0] = temp;
> > translate_fd_major_minor(td, fd, buf);
> > FILEDESC_LOCK(fdp);
> > fp = fdp->fd_ofiles[fd];
> > FILEDESC_UNLOCK(fdp);
> > fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
> > }
> >
> > As you can see the function is only used internally to convert
> > major/minor and fd is closed at the end of the function.
>
> Anything more than a stat() is too dangerous.
Yeah, it is really ugly hack already.
> >> according to a comment in linux source code linux never blocks
> >> for O_RDWR which is what I tried to implement with my patch
> >
> > We don't advertise it but we do the same, AFAIK. ;-)
>
> I think this happens automatically. The reader would block without
> O_NONBLOCK or a writer, but O_RDWR gives a writer so the only
> possible block is a transient internal one if the implementation
> opens the reader first. The thread doing the O_RDWR open()
> couldn't see this, but other threads might be able to see it if the
> implementation doesn't hold a lock throughout the open().
>
> But utility functions cannot use O_RDWR due to its side effect.
Thanks for the explanation.
> BTW, I never got around to committing the following workaround for
> a related bug in freopen(), since I'm not happy with the patch
> though I have been using it for about 10 years:
>
> %%%
> Index: freopen.c
> ===================================================================
> RCS file: /home/ncvs/src/lib/libc/stdio/freopen.c,v
> retrieving revision 1.13
> diff -u -2 -r1.13 freopen.c
> --- freopen.c 22 May 2004 15:19:41 -0000 1.13
> +++ freopen.c 23 May 2004 04:01:46 -0000
> @@ -64,4 +64,5 @@
> FILE *fp;
> {
> + struct stat st;
> int f;
> int dflags, flags, isopen, oflags, sverrno, wantfd;
> @@ -137,4 +138,7 @@
> * a descriptor, defer closing it; freopen("/dev/stdin", "r",
> stdin) * should work. This is unnecessary if it was not a Unix
> file. + * However, not closing the descriptor is a bug if closing
> it would + * have side effects. We close fifos because completely
> closing a + * fifo flushes it, and the NIST POSIX test suite tests
> for this. */
> if (fp->_flags == 0) {
> @@ -148,5 +152,9 @@
> /* if close is NULL, closing is a no-op, hence pointless */
> isopen = fp->_close != NULL;
> - if ((wantfd = fp->_file) < 0 && isopen) {
> + wantfd = fp->_file;
> + if (isopen &&
> + (wantfd < 0 ||
> + (_fstat(wantfd, &st) == 0 && S_ISFIFO(st.st_mode)
> + && st.st_ino != 0))) {
> (void) (*fp->_close)(fp->_cookie);
> isopen = 0;
> %%%
>
> stat() can be used similarly to give a workaround (that I'm not
> happy with) for translate_path_major_minor(): first stat() the
> path, and don't do anything unless it is a cdev or maybe a bdev
> (translate_fd_major_minor() still supports bdevs). This avoids the
> problem for fifos. However, cdevs must be handled, and opening of
> cdevs can have harmmful side effects (e.g., rewinding of tape
> drives). My fix for freopen() is incomplete because it doesn't
> handle the opposite problem. E.g., the missing close() might break
> setting of file marks on tapes. The problem is just smaller for
> freopen() since stdio shouldn't be used on tape drives, etc., while
> the translation function is used a lot and doesn't require much
> privilege.
Interesting... I knew the proper fix would be harder than my one-line
patch. ;-)
Thanks,
Jung-uk Kim
More information about the freebsd-emulation
mailing list