Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/sys_pipe.c
Show First 20 Lines • Show All 703 Lines • ▼ Show 20 Lines | if (rpipe->pipe_buffer.cnt > 0) { | ||||
rpipe->pipe_buffer.in = 0; | rpipe->pipe_buffer.in = 0; | ||||
rpipe->pipe_buffer.out = 0; | rpipe->pipe_buffer.out = 0; | ||||
} | } | ||||
nread += size; | nread += size; | ||||
#ifndef PIPE_NODIRECT | #ifndef PIPE_NODIRECT | ||||
/* | /* | ||||
* Direct copy, bypassing a kernel buffer. | * Direct copy, bypassing a kernel buffer. | ||||
*/ | */ | ||||
} else if ((size = rpipe->pipe_map.cnt) && | } else if ((size = rpipe->pipe_map.cnt) != 0) { | ||||
(rpipe->pipe_state & PIPE_DIRECTW)) { | |||||
if (size > uio->uio_resid) | if (size > uio->uio_resid) | ||||
size = (u_int) uio->uio_resid; | size = (u_int) uio->uio_resid; | ||||
PIPE_UNLOCK(rpipe); | PIPE_UNLOCK(rpipe); | ||||
error = uiomove_fromphys(rpipe->pipe_map.ms, | error = uiomove_fromphys(rpipe->pipe_map.ms, | ||||
rpipe->pipe_map.pos, size, uio); | rpipe->pipe_map.pos, size, uio); | ||||
PIPE_LOCK(rpipe); | PIPE_LOCK(rpipe); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
nread += size; | nread += size; | ||||
rpipe->pipe_map.pos += size; | rpipe->pipe_map.pos += size; | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
* This is similar to a physical write operation. | * This is similar to a physical write operation. | ||||
*/ | */ | ||||
static int | static int | ||||
pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio) | pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio) | ||||
{ | { | ||||
u_int size; | u_int size; | ||||
int i; | int i; | ||||
PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED); | PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | ||||
KASSERT(wpipe->pipe_state & PIPE_DIRECTW, | KASSERT((wpipe->pipe_state & PIPE_DIRECTW) == 0, | ||||
("Clone attempt on non-direct write pipe!")); | ("%s: PIPE_DIRECTW set on %p", __func__, wpipe)); | ||||
KASSERT(wpipe->pipe_map.cnt == 0, | |||||
("%s: pipe map for %p contains residual data", __func__, wpipe)); | |||||
if (uio->uio_iov->iov_len > wpipe->pipe_buffer.size) | if (uio->uio_iov->iov_len > wpipe->pipe_buffer.size) | ||||
size = wpipe->pipe_buffer.size; | size = wpipe->pipe_buffer.size; | ||||
else | else | ||||
size = uio->uio_iov->iov_len; | size = uio->uio_iov->iov_len; | ||||
if ((i = vm_fault_quick_hold_pages(&curproc->p_vmspace->vm_map, | wpipe->pipe_state |= PIPE_DIRECTW; | ||||
PIPE_UNLOCK(wpipe); | |||||
i = vm_fault_quick_hold_pages(&curproc->p_vmspace->vm_map, | |||||
(vm_offset_t)uio->uio_iov->iov_base, size, VM_PROT_READ, | (vm_offset_t)uio->uio_iov->iov_base, size, VM_PROT_READ, | ||||
wpipe->pipe_map.ms, PIPENPAGES)) < 0) | wpipe->pipe_map.ms, PIPENPAGES); | ||||
PIPE_LOCK(wpipe); | |||||
if (i < 0) { | |||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | |||||
return (EFAULT); | return (EFAULT); | ||||
} | |||||
/* | |||||
* set up the control block | |||||
*/ | |||||
wpipe->pipe_map.npages = i; | wpipe->pipe_map.npages = i; | ||||
wpipe->pipe_map.pos = | wpipe->pipe_map.pos = | ||||
((vm_offset_t) uio->uio_iov->iov_base) & PAGE_MASK; | ((vm_offset_t) uio->uio_iov->iov_base) & PAGE_MASK; | ||||
wpipe->pipe_map.cnt = size; | wpipe->pipe_map.cnt = size; | ||||
/* | |||||
* and update the uio data | |||||
*/ | |||||
uio->uio_iov->iov_len -= size; | uio->uio_iov->iov_len -= size; | ||||
uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + size; | uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + size; | ||||
if (uio->uio_iov->iov_len == 0) | if (uio->uio_iov->iov_len == 0) | ||||
uio->uio_iov++; | uio->uio_iov++; | ||||
uio->uio_resid -= size; | uio->uio_resid -= size; | ||||
uio->uio_offset += size; | uio->uio_offset += size; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Unwire the process buffer. | * Unwire the process buffer. | ||||
*/ | */ | ||||
static void | static void | ||||
pipe_destroy_write_buffer(struct pipe *wpipe) | pipe_destroy_write_buffer(struct pipe *wpipe) | ||||
{ | { | ||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | ||||
KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | ||||
("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | ||||
KASSERT(wpipe->pipe_map.cnt == 0, | |||||
("%s: pipe map for %p contains residual data", __func__, wpipe)); | |||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | wpipe->pipe_state &= ~PIPE_DIRECTW; | ||||
vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages); | vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages); | ||||
wpipe->pipe_map.npages = 0; | wpipe->pipe_map.npages = 0; | ||||
} | } | ||||
/* | /* | ||||
* In the case of a signal, the writing process might go away. This | * In the case of a signal, the writing process might go away. This | ||||
Show All 9 Lines | pipe_clone_write_buffer(struct pipe *wpipe) | ||||
int pos; | int pos; | ||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | PIPE_LOCK_ASSERT(wpipe, MA_OWNED); | ||||
KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0, | ||||
("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe)); | ||||
size = wpipe->pipe_map.cnt; | size = wpipe->pipe_map.cnt; | ||||
pos = wpipe->pipe_map.pos; | pos = wpipe->pipe_map.pos; | ||||
wpipe->pipe_map.cnt = 0; | |||||
wpipe->pipe_buffer.in = size; | wpipe->pipe_buffer.in = size; | ||||
wpipe->pipe_buffer.out = 0; | wpipe->pipe_buffer.out = 0; | ||||
wpipe->pipe_buffer.cnt = size; | wpipe->pipe_buffer.cnt = size; | ||||
PIPE_UNLOCK(wpipe); | PIPE_UNLOCK(wpipe); | ||||
iov.iov_base = wpipe->pipe_buffer.buffer; | iov.iov_base = wpipe->pipe_buffer.buffer; | ||||
iov.iov_len = size; | iov.iov_len = size; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (wpipe->pipe_state & PIPE_DIRECTW) { | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = msleep(wpipe, PIPE_MTX(wpipe), | error = msleep(wpipe, PIPE_MTX(wpipe), | ||||
PRIBIO | PCATCH, "pipdww", 0); | PRIBIO | PCATCH, "pipdww", 0); | ||||
if (error) | if (error) | ||||
goto error1; | goto error1; | ||||
else | else | ||||
goto retry; | goto retry; | ||||
} | } | ||||
wpipe->pipe_map.cnt = 0; /* transfer not ready yet */ | |||||
if (wpipe->pipe_buffer.cnt > 0) { | if (wpipe->pipe_buffer.cnt > 0) { | ||||
if (wpipe->pipe_state & PIPE_WANTR) { | if (wpipe->pipe_state & PIPE_WANTR) { | ||||
wpipe->pipe_state &= ~PIPE_WANTR; | wpipe->pipe_state &= ~PIPE_WANTR; | ||||
wakeup(wpipe); | wakeup(wpipe); | ||||
} | } | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
wpipe->pipe_state |= PIPE_WANTW; | wpipe->pipe_state |= PIPE_WANTW; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = msleep(wpipe, PIPE_MTX(wpipe), | error = msleep(wpipe, PIPE_MTX(wpipe), | ||||
PRIBIO | PCATCH, "pipdwc", 0); | PRIBIO | PCATCH, "pipdwc", 0); | ||||
if (error) | if (error) | ||||
goto error1; | goto error1; | ||||
else | else | ||||
goto retry; | goto retry; | ||||
} | } | ||||
wpipe->pipe_state |= PIPE_DIRECTW; | |||||
PIPE_UNLOCK(wpipe); | |||||
error = pipe_build_write_buffer(wpipe, uio); | error = pipe_build_write_buffer(wpipe, uio); | ||||
PIPE_LOCK(wpipe); | |||||
if (error) { | if (error) { | ||||
wpipe->pipe_state &= ~PIPE_DIRECTW; | |||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
goto error1; | goto error1; | ||||
} | } | ||||
while (wpipe->pipe_map.cnt != 0) { | while (wpipe->pipe_map.cnt != 0) { | ||||
if (wpipe->pipe_state & PIPE_EOF) { | if (wpipe->pipe_state & PIPE_EOF) { | ||||
wpipe->pipe_map.cnt = 0; | |||||
pipe_destroy_write_buffer(wpipe); | pipe_destroy_write_buffer(wpipe); | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = EPIPE; | error = EPIPE; | ||||
goto error1; | goto error1; | ||||
} | } | ||||
if (wpipe->pipe_state & PIPE_WANTR) { | if (wpipe->pipe_state & PIPE_WANTR) { | ||||
wpipe->pipe_state &= ~PIPE_WANTR; | wpipe->pipe_state &= ~PIPE_WANTR; | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Pipe buffered writes cannot be coincidental with | * Pipe buffered writes cannot be coincidental with | ||||
* direct writes. We wait until the currently executing | * direct writes. We wait until the currently executing | ||||
* direct write is completed before we start filling the | * direct write is completed before we start filling the | ||||
* pipe buffer. We break out if a signal occurs or the | * pipe buffer. We break out if a signal occurs or the | ||||
* reader goes away. | * reader goes away. | ||||
*/ | */ | ||||
if (wpipe->pipe_state & PIPE_DIRECTW) { | if (wpipe->pipe_map.cnt != 0) { | ||||
if (wpipe->pipe_state & PIPE_WANTR) { | if (wpipe->pipe_state & PIPE_WANTR) { | ||||
wpipe->pipe_state &= ~PIPE_WANTR; | wpipe->pipe_state &= ~PIPE_WANTR; | ||||
wakeup(wpipe); | wakeup(wpipe); | ||||
} | } | ||||
pipeselwakeup(wpipe); | pipeselwakeup(wpipe); | ||||
wpipe->pipe_state |= PIPE_WANTW; | wpipe->pipe_state |= PIPE_WANTW; | ||||
pipeunlock(wpipe); | pipeunlock(wpipe); | ||||
error = msleep(wpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH, | error = msleep(wpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH, | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | case FIOASYNC: | ||||
break; | break; | ||||
case FIONREAD: | case FIONREAD: | ||||
if (!(fp->f_flag & FREAD)) { | if (!(fp->f_flag & FREAD)) { | ||||
*(int *)data = 0; | *(int *)data = 0; | ||||
PIPE_UNLOCK(mpipe); | PIPE_UNLOCK(mpipe); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (mpipe->pipe_state & PIPE_DIRECTW) | if (mpipe->pipe_map.cnt != 0) | ||||
*(int *)data = mpipe->pipe_map.cnt; | *(int *)data = mpipe->pipe_map.cnt; | ||||
else | else | ||||
*(int *)data = mpipe->pipe_buffer.cnt; | *(int *)data = mpipe->pipe_buffer.cnt; | ||||
break; | break; | ||||
case FIOSETOWN: | case FIOSETOWN: | ||||
PIPE_UNLOCK(mpipe); | PIPE_UNLOCK(mpipe); | ||||
error = fsetown(*(int *)data, &mpipe->pipe_sigio); | error = fsetown(*(int *)data, &mpipe->pipe_sigio); | ||||
Show All 39 Lines | #endif | ||||
wpipe = PIPE_PEER(rpipe); | wpipe = PIPE_PEER(rpipe); | ||||
PIPE_LOCK(rpipe); | PIPE_LOCK(rpipe); | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_pipe_check_poll(active_cred, rpipe->pipe_pair); | error = mac_pipe_check_poll(active_cred, rpipe->pipe_pair); | ||||
if (error) | if (error) | ||||
goto locked_error; | goto locked_error; | ||||
#endif | #endif | ||||
if (fp->f_flag & FREAD && events & (POLLIN | POLLRDNORM)) | if (fp->f_flag & FREAD && events & (POLLIN | POLLRDNORM)) | ||||
if ((rpipe->pipe_state & PIPE_DIRECTW) || | if (rpipe->pipe_map.cnt > 0 || rpipe->pipe_buffer.cnt > 0) | ||||
(rpipe->pipe_buffer.cnt > 0)) | |||||
revents |= events & (POLLIN | POLLRDNORM); | revents |= events & (POLLIN | POLLRDNORM); | ||||
if (fp->f_flag & FWRITE && events & (POLLOUT | POLLWRNORM)) | if (fp->f_flag & FWRITE && events & (POLLOUT | POLLWRNORM)) | ||||
if (wpipe->pipe_present != PIPE_ACTIVE || | if (wpipe->pipe_present != PIPE_ACTIVE || | ||||
(wpipe->pipe_state & PIPE_EOF) || | (wpipe->pipe_state & PIPE_EOF) || | ||||
(((wpipe->pipe_state & PIPE_DIRECTW) == 0) && | ((wpipe->pipe_state & PIPE_DIRECTW) == 0 && | ||||
((wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF || | ((wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF || | ||||
wpipe->pipe_buffer.size == 0))) | wpipe->pipe_buffer.size == 0))) | ||||
revents |= events & (POLLOUT | POLLWRNORM); | revents |= events & (POLLOUT | POLLWRNORM); | ||||
levents = events & | levents = events & | ||||
(POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); | (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); | ||||
if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && | if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && | ||||
fp->f_pipegen == rpipe->pipe_wgen) | fp->f_pipegen == rpipe->pipe_wgen) | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (pipe->pipe_state & PIPE_NAMED) { | ||||
return (vnops.fo_stat(fp, ub, active_cred, td)); | return (vnops.fo_stat(fp, ub, active_cred, td)); | ||||
} | } | ||||
PIPE_UNLOCK(pipe); | PIPE_UNLOCK(pipe); | ||||
bzero(ub, sizeof(*ub)); | bzero(ub, sizeof(*ub)); | ||||
ub->st_mode = S_IFIFO; | ub->st_mode = S_IFIFO; | ||||
ub->st_blksize = PAGE_SIZE; | ub->st_blksize = PAGE_SIZE; | ||||
if (pipe->pipe_state & PIPE_DIRECTW) | if (pipe->pipe_map.cnt != 0) | ||||
ub->st_size = pipe->pipe_map.cnt; | ub->st_size = pipe->pipe_map.cnt; | ||||
else | else | ||||
ub->st_size = pipe->pipe_buffer.cnt; | ub->st_size = pipe->pipe_buffer.cnt; | ||||
ub->st_blocks = howmany(ub->st_size, ub->st_blksize); | ub->st_blocks = howmany(ub->st_size, ub->st_blksize); | ||||
ub->st_atim = pipe->pipe_atime; | ub->st_atim = pipe->pipe_atime; | ||||
ub->st_mtim = pipe->pipe_mtime; | ub->st_mtim = pipe->pipe_mtime; | ||||
ub->st_ctim = pipe->pipe_ctime; | ub->st_ctim = pipe->pipe_ctime; | ||||
ub->st_uid = fp->f_cred->cr_uid; | ub->st_uid = fp->f_cred->cr_uid; | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | |||||
filt_piperead(struct knote *kn, long hint) | filt_piperead(struct knote *kn, long hint) | ||||
{ | { | ||||
struct pipe *rpipe = kn->kn_hook; | struct pipe *rpipe = kn->kn_hook; | ||||
struct pipe *wpipe = rpipe->pipe_peer; | struct pipe *wpipe = rpipe->pipe_peer; | ||||
int ret; | int ret; | ||||
PIPE_LOCK_ASSERT(rpipe, MA_OWNED); | PIPE_LOCK_ASSERT(rpipe, MA_OWNED); | ||||
kn->kn_data = rpipe->pipe_buffer.cnt; | kn->kn_data = rpipe->pipe_buffer.cnt; | ||||
if ((kn->kn_data == 0) && (rpipe->pipe_state & PIPE_DIRECTW)) | if (kn->kn_data == 0) | ||||
kn->kn_data = rpipe->pipe_map.cnt; | kn->kn_data = rpipe->pipe_map.cnt; | ||||
if ((rpipe->pipe_state & PIPE_EOF) || | if ((rpipe->pipe_state & PIPE_EOF) || | ||||
wpipe->pipe_present != PIPE_ACTIVE || | wpipe->pipe_present != PIPE_ACTIVE || | ||||
(wpipe->pipe_state & PIPE_EOF)) { | (wpipe->pipe_state & PIPE_EOF)) { | ||||
kn->kn_flags |= EV_EOF; | kn->kn_flags |= EV_EOF; | ||||
return (1); | return (1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |