summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/sys_pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern/sys_pipe.c')
-rwxr-xr-xfreebsd/sys/kern/sys_pipe.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/freebsd/sys/kern/sys_pipe.c b/freebsd/sys/kern/sys_pipe.c
index 817190b7..d714af89 100755
--- a/freebsd/sys/kern/sys_pipe.c
+++ b/freebsd/sys/kern/sys_pipe.c
@@ -817,7 +817,7 @@ pipe_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
rpipe->pipe_map.pos += size;
rpipe->pipe_map.cnt -= size;
if (rpipe->pipe_map.cnt == 0) {
- rpipe->pipe_state &= ~(PIPE_DIRECTW|PIPE_WANTW);
+ rpipe->pipe_state &= ~PIPE_WANTW;
wakeup(rpipe);
}
#endif
@@ -1020,13 +1020,17 @@ pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio)
}
/*
- * unmap and unwire the process buffer
+ * Unwire the process buffer.
*/
static void
pipe_destroy_write_buffer(struct pipe *wpipe)
{
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0,
+ ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe));
+
+ wpipe->pipe_state &= ~PIPE_DIRECTW;
vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages);
wpipe->pipe_map.npages = 0;
}
@@ -1045,13 +1049,15 @@ pipe_clone_write_buffer(struct pipe *wpipe)
int pos;
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0,
+ ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe));
+
size = wpipe->pipe_map.cnt;
pos = wpipe->pipe_map.pos;
wpipe->pipe_buffer.in = size;
wpipe->pipe_buffer.out = 0;
wpipe->pipe_buffer.cnt = size;
- wpipe->pipe_state &= ~PIPE_DIRECTW;
PIPE_UNLOCK(wpipe);
iov.iov_base = wpipe->pipe_buffer.buffer;
@@ -1090,7 +1096,7 @@ retry:
pipeunlock(wpipe);
goto error1;
}
- while (wpipe->pipe_state & PIPE_DIRECTW) {
+ if (wpipe->pipe_state & PIPE_DIRECTW) {
if (wpipe->pipe_state & PIPE_WANTR) {
wpipe->pipe_state &= ~PIPE_WANTR;
wakeup(wpipe);
@@ -1133,8 +1139,7 @@ retry:
goto error1;
}
- error = 0;
- while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) {
+ while (wpipe->pipe_map.cnt != 0) {
if (wpipe->pipe_state & PIPE_EOF) {
pipe_destroy_write_buffer(wpipe);
pipeselwakeup(wpipe);
@@ -1152,20 +1157,19 @@ retry:
error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH,
"pipdwt", 0);
pipelock(wpipe, 0);
+ if (error != 0)
+ break;
}
if (wpipe->pipe_state & PIPE_EOF)
error = EPIPE;
- if (wpipe->pipe_state & PIPE_DIRECTW) {
- /*
- * this bit of trickery substitutes a kernel buffer for
- * the process that might be going away.
- */
+ if (error == EINTR || error == ERESTART)
pipe_clone_write_buffer(wpipe);
- } else {
+ else
pipe_destroy_write_buffer(wpipe);
- }
pipeunlock(wpipe);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) == 0,
+ ("pipe %p leaked PIPE_DIRECTW", wpipe));
return (error);
error1: