diff options
author | Matthew Dillon <dillon@FreeBSD.org> | 2001-06-04 04:04:45 +0000 |
---|---|---|
committer | Matthew Dillon <dillon@FreeBSD.org> | 2001-06-04 04:04:45 +0000 |
commit | 1b3e974a71a6d7596d307e5315746cdfe8cb9066 (patch) | |
tree | 7e4c9fa98258777945f5173b14be6fa1946ebe66 /sys/kern/sys_pipe.c | |
parent | 34c4099770dacb6527715d4e803d88cc8b6fe6bd (diff) | |
download | src-1b3e974a71a6d7596d307e5315746cdfe8cb9066.tar.gz src-1b3e974a71a6d7596d307e5315746cdfe8cb9066.zip |
The pipe_write() code was locking the pipe without busying it first in
certain cases, and a close() by another process could potentially rip the
pipe out from under the (blocked) locking operation.
Reported-by: Alexander Viro <viro@math.psu.edu>
Notes
Notes:
svn path=/head/; revision=77676
Diffstat (limited to 'sys/kern/sys_pipe.c')
-rw-r--r-- | sys/kern/sys_pipe.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index c347a5852161..6c0e17e23d8d 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -777,6 +777,7 @@ pipe_write(fp, uio, cred, flags, p) if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) { return (EPIPE); } + ++wpipe->pipe_busy; /* * If it is advantageous to resize the pipe buffer, do @@ -792,15 +793,27 @@ pipe_write(fp, uio, cred, flags, p) if (pipespace(wpipe, BIG_PIPE_SIZE) == 0) nbigpipe++; pipeunlock(wpipe); - } else { - return (error); } } + + /* + * If an early error occured unbusy and return, waking up any pending + * readers. + */ + if (error) { + --wpipe->pipe_busy; + if ((wpipe->pipe_busy == 0) && + (wpipe->pipe_state & PIPE_WANT)) { + wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR); + wakeup(wpipe); + } + return(error); + } KASSERT(wpipe->pipe_buffer.buffer != NULL, ("pipe buffer gone")); - ++wpipe->pipe_busy; orig_resid = uio->uio_resid; + while (uio->uio_resid) { int space; @@ -977,6 +990,7 @@ pipe_write(fp, uio, cred, flags, p) } --wpipe->pipe_busy; + if ((wpipe->pipe_busy == 0) && (wpipe->pipe_state & PIPE_WANT)) { wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR); wakeup(wpipe); @@ -995,9 +1009,10 @@ pipe_write(fp, uio, cred, flags, p) * Don't return EPIPE if I/O was successful */ if ((wpipe->pipe_buffer.cnt == 0) && - (uio->uio_resid == 0) && - (error == EPIPE)) + (uio->uio_resid == 0) && + (error == EPIPE)) { error = 0; + } if (error == 0) vfs_timestamp(&wpipe->pipe_mtime); |