Date: Thu, 4 Feb 1999 14:19:54 -0800 (PST) From: Matthew Dillon <dillon@apollo.backplane.com> To: current@FreeBSD.ORG Subject: Bug in piperd Message-ID: <199902042219.OAA90785@apollo.backplane.com>
next in thread | raw e-mail | index | archive | help
Ha. I've been slowly reducing MAXMEM on my test box to force it to swap more heavily running buildworld and found a race in the kern/sys_pipe.c module. My buildworld froze up... i.e. just stopped running. Everything else on the box was fine. ps showed an 'as' command stuck in 'piperd'. The problem is simple (pseudo code fragment): pipe read: ... * check for EOF * check for waiting writers * lock the pipe * check for waiting writers * check for non-blocking I/O * sleep in 'piperd' The problem, of course, is that if 'lock the pipe' blocks, it is possible for the writer side to close the pipe. Since EOF is not checked for after the pipe has been locked, the reader enters a 'piperd' state and never gets woken up again. I am testing a fix now and will then commit it. If anyone sees anything obviously wrong with this patch, please email me. -Matt Matthew Dillon <dillon@backplane.com> Index: sys_pipe.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sys_pipe.c,v retrieving revision 1.49 diff -u -r1.49 sys_pipe.c --- sys_pipe.c 1999/01/28 00:57:47 1.49 +++ sys_pipe.c 1999/02/04 22:14:58 @@ -381,12 +381,32 @@ #endif } else { /* + * If there is no more to read in the pipe, reset + * its pointers to the beginning. This improves + * cache hit stats. + * + * We get this over with now because it may block + * and cause the state to change out from under us, + * rather then have to re-test the state both before + * and after this fragment. + */ + + if ((error = pipelock(rpipe,1)) == 0) { + if (rpipe->pipe_buffer.cnt == 0) { + rpipe->pipe_buffer.in = 0; + rpipe->pipe_buffer.out = 0; + } + pipeunlock(rpipe); + } + + /* * detect EOF condition */ if (rpipe->pipe_state & PIPE_EOF) { /* XXX error = ? */ break; } + /* * If the "write-side" has been blocked, wake it up now. */ @@ -394,34 +414,26 @@ rpipe->pipe_state &= ~PIPE_WANTW; wakeup(rpipe); } - if (nread > 0) + + /* + * break if error (signal via pipelock), or if some + * data was read + */ + if (error || nread > 0) break; + /* + * Handle non-blocking mode operation + */ + if (fp->f_flag & FNONBLOCK) { error = EAGAIN; break; } /* - * If there is no more to read in the pipe, reset - * its pointers to the beginning. This improves - * cache hit stats. + * Wait for more data */ - - if ((error = pipelock(rpipe,1)) == 0) { - if (rpipe->pipe_buffer.cnt == 0) { - rpipe->pipe_buffer.in = 0; - rpipe->pipe_buffer.out = 0; - } - pipeunlock(rpipe); - } else { - break; - } - - if (rpipe->pipe_state & PIPE_WANTW) { - rpipe->pipe_state &= ~PIPE_WANTW; - wakeup(rpipe); - } rpipe->pipe_state |= PIPE_WANTR; if ((error = tsleep(rpipe, PRIBIO|PCATCH, "piperd", 0)) != 0) { To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199902042219.OAA90785>