Merge the update to FreeBSD rev 1.95.
Changes: * MP locking changes (mostly FreeBSD specific) XXXSMP the MP locking macros are noops on NetBSD for now * kevent fix (FreeBSD rev. 1.87): when the last reader/writer disconnects, ensure that anybody who is waiting for the kevent on the other end of the pipe gets EV_EOF * kill __P
This commit is contained in:
parent
42aa648b4c
commit
fcc4c4d402
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $ */
|
||||
/* $NetBSD: sys_pipe.c,v 1.24 2002/03/13 21:50:24 jdolecek Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 John S. Dyson
|
||||
|
@ -18,7 +18,7 @@
|
|||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
*
|
||||
* $FreeBSD: src/sys/kern/sys_pipe.c,v 1.82 2001/06/15 20:45:01 jlemon Exp $
|
||||
* $FreeBSD: src/sys/kern/sys_pipe.c,v 1.95 2002/03/09 22:06:31 alfred Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -58,7 +58,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.24 2002/03/13 21:50:24 jdolecek Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -67,8 +67,11 @@ __KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $"
|
|||
#include <sys/file.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/ttycom.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/vnode.h>
|
||||
|
@ -76,11 +79,9 @@ __KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $"
|
|||
#include <sys/lock.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/sysproto.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/select.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/syscallargs.h>
|
||||
#include <uvm/uvm.h>
|
||||
|
@ -110,16 +111,16 @@ __KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $"
|
|||
* interfaces to the outside world
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
static int pipe_read __P((struct file *fp, struct uio *uio,
|
||||
struct ucred *cred, int flags, struct proc *p));
|
||||
static int pipe_write __P((struct file *fp, struct uio *uio,
|
||||
struct ucred *cred, int flags, struct proc *p));
|
||||
static int pipe_close __P((struct file *fp, struct proc *p));
|
||||
static int pipe_poll __P((struct file *fp, int events, struct ucred *cred,
|
||||
struct proc *p));
|
||||
static int pipe_kqfilter __P((struct file *fp, struct knote *kn));
|
||||
static int pipe_stat __P((struct file *fp, struct stat *sb, struct proc *p));
|
||||
static int pipe_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct proc *p));
|
||||
static int pipe_read(struct file *fp, struct uio *uio,
|
||||
struct ucred *cred, int flags, struct thread *td);
|
||||
static int pipe_write(struct file *fp, struct uio *uio,
|
||||
struct ucred *cred, int flags, struct thread *td);
|
||||
static int pipe_close(struct file *fp, struct thread *td);
|
||||
static int pipe_poll(struct file *fp, int events, struct ucred *cred,
|
||||
struct thread *td);
|
||||
static int pipe_kqfilter(struct file *fp, struct knote *kn);
|
||||
static int pipe_stat(struct file *fp, struct stat *sb, struct thread *td);
|
||||
static int pipe_ioctl(struct file *fp, u_long cmd, caddr_t data, struct thread *td);
|
||||
|
||||
static struct fileops pipeops = {
|
||||
pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_kqfilter,
|
||||
|
@ -134,23 +135,42 @@ static struct filterops pipe_rfiltops =
|
|||
{ 1, NULL, filt_pipedetach, filt_piperead };
|
||||
static struct filterops pipe_wfiltops =
|
||||
{ 1, NULL, filt_pipedetach, filt_pipewrite };
|
||||
|
||||
#define PIPE_GET_GIANT(pipe) \
|
||||
do { \
|
||||
PIPE_UNLOCK(wpipe); \
|
||||
mtx_lock(&Giant); \
|
||||
} while (0)
|
||||
|
||||
#define PIPE_DROP_GIANT(pipe) \
|
||||
do { \
|
||||
mtx_unlock(&Giant); \
|
||||
PIPE_LOCK(wpipe); \
|
||||
} while (0)
|
||||
|
||||
#endif /* FreeBSD */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
static int pipe_read __P((struct file *fp, off_t *offset, struct uio *uio,
|
||||
struct ucred *cred, int flags));
|
||||
static int pipe_write __P((struct file *fp, off_t *offset, struct uio *uio,
|
||||
struct ucred *cred, int flags));
|
||||
static int pipe_close __P((struct file *fp, struct proc *p));
|
||||
static int pipe_poll __P((struct file *fp, int events, struct proc *p));
|
||||
static int pipe_fcntl __P((struct file *fp, u_int com, caddr_t data,
|
||||
struct proc *p));
|
||||
static int pipe_stat __P((struct file *fp, struct stat *sb, struct proc *p));
|
||||
static int pipe_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct proc *p));
|
||||
static int pipe_read(struct file *fp, off_t *offset, struct uio *uio,
|
||||
struct ucred *cred, int flags);
|
||||
static int pipe_write(struct file *fp, off_t *offset, struct uio *uio,
|
||||
struct ucred *cred, int flags);
|
||||
static int pipe_close(struct file *fp, struct proc *p);
|
||||
static int pipe_poll(struct file *fp, int events, struct proc *p);
|
||||
static int pipe_fcntl(struct file *fp, u_int com, caddr_t data,
|
||||
struct proc *p);
|
||||
static int pipe_stat(struct file *fp, struct stat *sb, struct proc *p);
|
||||
static int pipe_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p);
|
||||
|
||||
static struct fileops pipeops =
|
||||
{ pipe_read, pipe_write, pipe_ioctl, pipe_fcntl, pipe_poll,
|
||||
pipe_stat, pipe_close };
|
||||
|
||||
/* XXXSMP perhaps use spinlocks & KERNEL_PROC_(UN)LOCK() ? just clear now */
|
||||
#define PIPE_GET_GIANT(pipe)
|
||||
#define PIPE_DROP_GIANT(pipe)
|
||||
#define GIANT_REQUIRED
|
||||
|
||||
#endif /* NetBSD */
|
||||
|
||||
/*
|
||||
|
@ -188,35 +208,46 @@ static int nbigpipe = 0;
|
|||
*/
|
||||
static int amountpipekva = 0;
|
||||
|
||||
static void pipeclose __P((struct pipe *));
|
||||
static void pipe_free_kmem __P((struct pipe *));
|
||||
static int pipe_create __P((struct pipe **, int));
|
||||
static __inline int pipelock __P((struct pipe *, int));
|
||||
static __inline void pipeunlock __P((struct pipe *));
|
||||
static __inline void pipeselwakeup __P((struct pipe *, struct pipe *));
|
||||
static int pipespace __P((struct pipe *, int));
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static void pipeclose(struct pipe *cpipe);
|
||||
static void pipe_free_kmem(struct pipe *cpipe);
|
||||
static int pipe_create(struct pipe **cpipep, int allockva);
|
||||
static __inline int pipelock(struct pipe *cpipe, int catch);
|
||||
static __inline void pipeunlock(struct pipe *cpipe);
|
||||
static __inline void pipeselwakeup(struct pipe *cpipe, struct pipe *sigp);
|
||||
#ifndef PIPE_NODIRECT
|
||||
static int pipe_build_write_buffer __P((struct pipe *wpipe, struct uio *uio));
|
||||
static void pipe_destroy_write_buffer __P((struct pipe *wpipe));
|
||||
static int pipe_direct_write __P((struct pipe *wpipe, struct uio *uio));
|
||||
static void pipe_clone_write_buffer __P((struct pipe *wpipe));
|
||||
static int pipe_direct_write(struct pipe *wpipe, struct uio *uio);
|
||||
#endif
|
||||
|
||||
static vm_zone_t pipe_zone;
|
||||
#endif /* FreeBSD */
|
||||
static int pipespace(struct pipe *cpipe, int size);
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#ifndef PIPE_NODIRECT
|
||||
static int pipe_direct_write __P((struct pipe *, struct uio *));
|
||||
static int pipe_loan_alloc __P((struct pipe *, int));
|
||||
static void pipe_loan_free __P((struct pipe *));
|
||||
static int pipe_loan_alloc(struct pipe *, int);
|
||||
static void pipe_loan_free(struct pipe *);
|
||||
#endif /* PIPE_NODIRECT */
|
||||
|
||||
static struct pool pipe_pool;
|
||||
#endif /* NetBSD */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static vm_zone_t pipe_zone;
|
||||
|
||||
static void pipeinit(void *dummy __unused);
|
||||
#ifndef PIPE_NODIRECT
|
||||
static int pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio);
|
||||
static void pipe_destroy_write_buffer(struct pipe *wpipe);
|
||||
static void pipe_clone_write_buffer(struct pipe *wpipe);
|
||||
#endif
|
||||
|
||||
SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, pipeinit, NULL);
|
||||
|
||||
static void
|
||||
pipeinit(void *dummy __unused)
|
||||
{
|
||||
|
||||
pipe_zone = zinit("PIPE", sizeof(struct pipe), 0, 0, 4);
|
||||
}
|
||||
#endif /* FreeBSD */
|
||||
|
||||
/*
|
||||
* The pipe system call for the DTYPE_PIPE type of pipes
|
||||
*/
|
||||
|
@ -224,8 +255,8 @@ static struct pool pipe_pool;
|
|||
/* ARGSUSED */
|
||||
#ifdef __FreeBSD__
|
||||
int
|
||||
pipe(p, uap)
|
||||
struct proc *p;
|
||||
pipe(td, uap)
|
||||
struct thread *td;
|
||||
struct pipe_args /* {
|
||||
int dummy;
|
||||
} */ *uap;
|
||||
|
@ -240,26 +271,30 @@ sys_pipe(p, v, retval)
|
|||
struct file *rf, *wf;
|
||||
struct pipe *rpipe, *wpipe;
|
||||
int fd, error;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (pipe_zone == NULL)
|
||||
pipe_zone = zinit("PIPE", sizeof(struct pipe), 0, 0, 4);
|
||||
struct mtx *pmtx;
|
||||
|
||||
KASSERT(pipe_zone != NULL, ("pipe_zone not initialized"));
|
||||
|
||||
pmtx = malloc(sizeof(*pmtx), M_TEMP, M_WAITOK | M_ZERO);
|
||||
|
||||
rpipe = wpipe = NULL;
|
||||
if (pipe_create(&rpipe, 1) || pipe_create(&wpipe, 1)) {
|
||||
pipeclose(rpipe);
|
||||
pipeclose(wpipe);
|
||||
pipeclose(rpipe);
|
||||
pipeclose(wpipe);
|
||||
free(pmtx, M_TEMP);
|
||||
return (ENFILE);
|
||||
}
|
||||
|
||||
error = falloc(p, &rf, &fd);
|
||||
error = falloc(td, &rf, &fd);
|
||||
if (error) {
|
||||
pipeclose(rpipe);
|
||||
pipeclose(wpipe);
|
||||
free(pmtx, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
fhold(rf);
|
||||
p->p_retval[0] = fd;
|
||||
td->td_retval[0] = fd;
|
||||
|
||||
/*
|
||||
* Warning: once we've gotten past allocation of the fd for the
|
||||
|
@ -267,32 +302,39 @@ sys_pipe(p, v, retval)
|
|||
* to avoid races against processes which manage to dup() the read
|
||||
* side while we are blocked trying to allocate the write side.
|
||||
*/
|
||||
FILE_LOCK(rf);
|
||||
rf->f_flag = FREAD | FWRITE;
|
||||
rf->f_type = DTYPE_PIPE;
|
||||
rf->f_data = (caddr_t)rpipe;
|
||||
rf->f_ops = &pipeops;
|
||||
error = falloc(p, &wf, &fd);
|
||||
FILE_UNLOCK(rf);
|
||||
error = falloc(td, &wf, &fd);
|
||||
if (error) {
|
||||
struct filedesc *fdp = p->p_fd;
|
||||
|
||||
if (fdp->fd_ofiles[p->p_retval[0]] == rf) {
|
||||
fdp->fd_ofiles[p->p_retval[0]] = NULL;
|
||||
fdrop(rf, p);
|
||||
}
|
||||
fdrop(rf, p);
|
||||
struct filedesc *fdp = td->td_proc->p_fd;
|
||||
FILEDESC_LOCK(fdp);
|
||||
if (fdp->fd_ofiles[td->td_retval[0]] == rf) {
|
||||
fdp->fd_ofiles[td->td_retval[0]] = NULL;
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
fdrop(rf, td);
|
||||
} else
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
fdrop(rf, td);
|
||||
/* rpipe has been closed by fdrop(). */
|
||||
pipeclose(wpipe);
|
||||
free(pmtx, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
FILE_LOCK(wf);
|
||||
wf->f_flag = FREAD | FWRITE;
|
||||
wf->f_type = DTYPE_PIPE;
|
||||
wf->f_data = (caddr_t)wpipe;
|
||||
wf->f_ops = &pipeops;
|
||||
p->p_retval[1] = fd;
|
||||
|
||||
rpipe->pipe_peer = wpipe;
|
||||
wpipe->pipe_peer = rpipe;
|
||||
fdrop(rf, p);
|
||||
mtx_init(pmtx, "pipe mutex", MTX_DEF);
|
||||
rpipe->pipe_mtxp = wpipe->pipe_mtxp = pmtx;
|
||||
fdrop(rf, td);
|
||||
#endif /* FreeBSD */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
|
@ -365,12 +407,15 @@ pipespace(cpipe, size)
|
|||
struct vm_object *object;
|
||||
int npages, error;
|
||||
|
||||
GIANT_REQUIRED;
|
||||
KASSERT(cpipe->pipe_mtxp == NULL || !mtx_owned(PIPE_MTX(cpipe)),
|
||||
("pipespace: pipe mutex locked"));
|
||||
|
||||
npages = round_page(size)/PAGE_SIZE;
|
||||
/*
|
||||
* Create an object, I don't like the idea of paging to/from
|
||||
* kernel_object.
|
||||
*/
|
||||
mtx_lock(&vm_mtx);
|
||||
object = vm_object_allocate(OBJT_DEFAULT, npages);
|
||||
buffer = (caddr_t) vm_map_min(kernel_map);
|
||||
|
||||
|
@ -384,7 +429,6 @@ pipespace(cpipe, size)
|
|||
|
||||
if (error != KERN_SUCCESS) {
|
||||
vm_object_deallocate(object);
|
||||
mtx_unlock(&vm_mtx);
|
||||
return (ENOMEM);
|
||||
}
|
||||
#endif /* FreeBSD */
|
||||
|
@ -402,7 +446,6 @@ pipespace(cpipe, size)
|
|||
/* free old resources if we're resizing */
|
||||
pipe_free_kmem(cpipe);
|
||||
#ifdef __FreeBSD__
|
||||
mtx_unlock(&vm_mtx);
|
||||
cpipe->pipe_buffer.object = object;
|
||||
#endif
|
||||
cpipe->pipe_buffer.buffer = buffer;
|
||||
|
@ -440,6 +483,9 @@ pipe_create(cpipep, allockva)
|
|||
memset(cpipe, 0, sizeof(*cpipe));
|
||||
cpipe->pipe_state = PIPE_SIGNALR;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
cpipe->pipe_mtxp = NULL; /* avoid pipespace assertion */
|
||||
#endif
|
||||
if (allockva && (error = pipespace(cpipe, PIPE_SIZE)))
|
||||
return (error);
|
||||
|
||||
|
@ -466,14 +512,16 @@ pipelock(cpipe, catch)
|
|||
int error;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
while (cpipe->pipe_state & PIPE_LOCK) {
|
||||
PIPE_LOCK_ASSERT(cpipe, MA_OWNED);
|
||||
while (cpipe->pipe_state & PIPE_LOCKFL) {
|
||||
cpipe->pipe_state |= PIPE_LWANT;
|
||||
error = tsleep(cpipe, catch ? (PRIBIO | PCATCH) : PRIBIO,
|
||||
error = msleep(cpipe, PIPE_MTX(cpipe),
|
||||
catch ? (PRIBIO | PCATCH) : PRIBIO,
|
||||
"pipelk", 0);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
cpipe->pipe_state |= PIPE_LOCK;
|
||||
cpipe->pipe_state |= PIPE_LOCKFL;
|
||||
return (0);
|
||||
#endif
|
||||
|
||||
|
@ -492,8 +540,10 @@ static __inline void
|
|||
pipeunlock(cpipe)
|
||||
struct pipe *cpipe;
|
||||
{
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
cpipe->pipe_state &= ~PIPE_LOCK;
|
||||
PIPE_LOCK_ASSERT(cpipe, MA_OWNED);
|
||||
cpipe->pipe_state &= ~PIPE_LOCKFL;
|
||||
if (cpipe->pipe_state & PIPE_LWANT) {
|
||||
cpipe->pipe_state &= ~PIPE_LWANT;
|
||||
wakeup(cpipe);
|
||||
|
@ -539,10 +589,11 @@ pipeselwakeup(selp, sigp)
|
|||
/* ARGSUSED */
|
||||
#ifdef __FreeBSD__
|
||||
static int
|
||||
pipe_read(fp, uio, cred, flags, p)
|
||||
pipe_read(fp, uio, cred, flags, td)
|
||||
struct file *fp;
|
||||
struct uio *uio;
|
||||
struct ucred *cred;
|
||||
struct thread *td;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
#elif defined(__NetBSD__)
|
||||
|
@ -561,6 +612,7 @@ pipe_read(fp, offset, uio, cred, flags)
|
|||
size_t size;
|
||||
size_t ocnt;
|
||||
|
||||
PIPE_LOCK(rpipe);
|
||||
++rpipe->pipe_busy;
|
||||
error = pipelock(rpipe, 1);
|
||||
if (error)
|
||||
|
@ -579,8 +631,10 @@ pipe_read(fp, offset, uio, cred, flags)
|
|||
if (size > uio->uio_resid)
|
||||
size = uio->uio_resid;
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
error = uiomove(&rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out],
|
||||
size, uio);
|
||||
PIPE_LOCK(rpipe);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
|
@ -612,7 +666,9 @@ pipe_read(fp, offset, uio, cred, flags)
|
|||
|
||||
va = (caddr_t) rpipe->pipe_map.kva +
|
||||
rpipe->pipe_map.pos;
|
||||
PIPE_UNLOCK(rpipe);
|
||||
error = uiomove(va, size, uio);
|
||||
PIPE_LOCK(rpipe);
|
||||
if (error)
|
||||
break;
|
||||
nread += size;
|
||||
|
@ -666,13 +722,19 @@ pipe_read(fp, offset, uio, cred, flags)
|
|||
pipeselwakeup(rpipe, rpipe->pipe_peer);
|
||||
|
||||
rpipe->pipe_state |= PIPE_WANTR;
|
||||
#ifdef __FreeBSD__
|
||||
error = msleep(rpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH,
|
||||
"piperd", 0);
|
||||
#else
|
||||
error = tsleep(rpipe, PRIBIO | PCATCH, "piperd", 0);
|
||||
#endif
|
||||
if (error != 0 || (error = pipelock(rpipe, 1)))
|
||||
goto unlocked_error;
|
||||
}
|
||||
}
|
||||
pipeunlock(rpipe);
|
||||
|
||||
/* XXX: should probably do this before getting any locks. */
|
||||
if (error == 0)
|
||||
vfs_timestamp(&rpipe->pipe_atime);
|
||||
unlocked_error:
|
||||
|
@ -705,6 +767,7 @@ unlocked_error:
|
|||
rpipe->pipe_state &= ~PIPE_SIGNALR;
|
||||
}
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -723,12 +786,14 @@ pipe_build_write_buffer(wpipe, uio)
|
|||
int i;
|
||||
vm_offset_t addr, endaddr, paddr;
|
||||
|
||||
GIANT_REQUIRED;
|
||||
PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
|
||||
|
||||
size = uio->uio_iov->iov_len;
|
||||
if (size > wpipe->pipe_buffer.size)
|
||||
size = wpipe->pipe_buffer.size;
|
||||
|
||||
endaddr = round_page((vm_offset_t)uio->uio_iov->iov_base + size);
|
||||
mtx_lock(&vm_mtx);
|
||||
addr = trunc_page((vm_offset_t)uio->uio_iov->iov_base);
|
||||
for (i = 0; addr < endaddr; addr += PAGE_SIZE, i++) {
|
||||
vm_page_t m;
|
||||
|
@ -739,7 +804,6 @@ pipe_build_write_buffer(wpipe, uio)
|
|||
|
||||
for (j = 0; j < i; j++)
|
||||
vm_page_unwire(wpipe->pipe_map.ms[j], 1);
|
||||
mtx_unlock(&vm_mtx);
|
||||
return (EFAULT);
|
||||
}
|
||||
|
||||
|
@ -771,7 +835,6 @@ pipe_build_write_buffer(wpipe, uio)
|
|||
pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms,
|
||||
wpipe->pipe_map.npages);
|
||||
|
||||
mtx_unlock(&vm_mtx);
|
||||
/*
|
||||
* and update the uio data
|
||||
*/
|
||||
|
@ -794,7 +857,9 @@ pipe_destroy_write_buffer(wpipe)
|
|||
{
|
||||
int i;
|
||||
|
||||
mtx_lock(&vm_mtx);
|
||||
GIANT_REQUIRED;
|
||||
PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
|
||||
|
||||
if (wpipe->pipe_map.kva) {
|
||||
pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);
|
||||
|
||||
|
@ -808,7 +873,7 @@ pipe_destroy_write_buffer(wpipe)
|
|||
}
|
||||
for (i = 0; i < wpipe->pipe_map.npages; i++)
|
||||
vm_page_unwire(wpipe->pipe_map.ms[i], 1);
|
||||
mtx_unlock(&vm_mtx);
|
||||
wpipe->pipe_map.npages = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -823,6 +888,7 @@ pipe_clone_write_buffer(wpipe)
|
|||
int size;
|
||||
int pos;
|
||||
|
||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
|
||||
size = wpipe->pipe_map.cnt;
|
||||
pos = wpipe->pipe_map.pos;
|
||||
memcpy((caddr_t) wpipe->pipe_buffer.buffer,
|
||||
|
@ -833,7 +899,9 @@ pipe_clone_write_buffer(wpipe)
|
|||
wpipe->pipe_buffer.cnt = size;
|
||||
wpipe->pipe_state &= ~PIPE_DIRECTW;
|
||||
|
||||
PIPE_GET_GIANT(wpipe);
|
||||
pipe_destroy_write_buffer(wpipe);
|
||||
PIPE_DROP_GIANT(wpipe);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -851,13 +919,15 @@ pipe_direct_write(wpipe, uio)
|
|||
int error;
|
||||
|
||||
retry:
|
||||
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
|
||||
while (wpipe->pipe_state & PIPE_DIRECTW) {
|
||||
if (wpipe->pipe_state & PIPE_WANTR) {
|
||||
wpipe->pipe_state &= ~PIPE_WANTR;
|
||||
wakeup(wpipe);
|
||||
}
|
||||
wpipe->pipe_state |= PIPE_WANTW;
|
||||
error = tsleep(wpipe, PRIBIO | PCATCH, "pipdww", 0);
|
||||
error = msleep(wpipe, PIPE_MTX(wpipe),
|
||||
PRIBIO | PCATCH, "pipdww", 0);
|
||||
if (error)
|
||||
goto error1;
|
||||
if (wpipe->pipe_state & PIPE_EOF) {
|
||||
|
@ -873,7 +943,8 @@ retry:
|
|||
}
|
||||
|
||||
wpipe->pipe_state |= PIPE_WANTW;
|
||||
error = tsleep(wpipe, PRIBIO | PCATCH, "pipdwc", 0);
|
||||
error = msleep(wpipe, PIPE_MTX(wpipe),
|
||||
PRIBIO | PCATCH, "pipdwc", 0);
|
||||
if (error)
|
||||
goto error1;
|
||||
if (wpipe->pipe_state & PIPE_EOF) {
|
||||
|
@ -885,7 +956,9 @@ retry:
|
|||
|
||||
wpipe->pipe_state |= PIPE_DIRECTW;
|
||||
|
||||
PIPE_GET_GIANT(wpipe);
|
||||
error = pipe_build_write_buffer(wpipe, uio);
|
||||
PIPE_DROP_GIANT(wpipe);
|
||||
if (error) {
|
||||
wpipe->pipe_state &= ~PIPE_DIRECTW;
|
||||
goto error1;
|
||||
|
@ -895,7 +968,9 @@ retry:
|
|||
while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) {
|
||||
if (wpipe->pipe_state & PIPE_EOF) {
|
||||
pipelock(wpipe, 0);
|
||||
PIPE_GET_GIANT(wpipe);
|
||||
pipe_destroy_write_buffer(wpipe);
|
||||
PIPE_DROP_GIANT(wpipe);
|
||||
pipeunlock(wpipe);
|
||||
pipeselwakeup(wpipe, wpipe);
|
||||
error = EPIPE;
|
||||
|
@ -906,7 +981,8 @@ retry:
|
|||
wakeup(wpipe);
|
||||
}
|
||||
pipeselwakeup(wpipe, wpipe);
|
||||
error = tsleep(wpipe, PRIBIO | PCATCH, "pipdwt", 0);
|
||||
error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH,
|
||||
"pipdwt", 0);
|
||||
}
|
||||
|
||||
pipelock(wpipe,0);
|
||||
|
@ -917,7 +993,9 @@ retry:
|
|||
*/
|
||||
pipe_clone_write_buffer(wpipe);
|
||||
} else {
|
||||
PIPE_GET_GIANT(wpipe);
|
||||
pipe_destroy_write_buffer(wpipe);
|
||||
PIPE_DROP_GIANT(wpipe);
|
||||
}
|
||||
pipeunlock(wpipe);
|
||||
return (error);
|
||||
|
@ -1136,13 +1214,13 @@ error:
|
|||
|
||||
#ifdef __FreeBSD__
|
||||
static int
|
||||
pipe_write(fp, uio, cred, flags, p)
|
||||
pipe_write(fp, uio, cred, flags, td)
|
||||
struct file *fp;
|
||||
off_t *offset;
|
||||
struct uio *uio;
|
||||
struct ucred *cred;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
struct thread *td;
|
||||
#elif defined(__NetBSD__)
|
||||
static int
|
||||
pipe_write(fp, offset, uio, cred, flags)
|
||||
|
@ -1159,11 +1237,14 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
rpipe = (struct pipe *) fp->f_data;
|
||||
wpipe = rpipe->pipe_peer;
|
||||
|
||||
PIPE_LOCK(rpipe);
|
||||
/*
|
||||
* detect loss of pipe read side, issue SIGPIPE if lost.
|
||||
*/
|
||||
if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF))
|
||||
if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (EPIPE);
|
||||
}
|
||||
|
||||
++wpipe->pipe_busy;
|
||||
|
||||
|
@ -1180,8 +1261,10 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
(wpipe->pipe_buffer.cnt == 0)) {
|
||||
|
||||
if ((error = pipelock(wpipe,1)) == 0) {
|
||||
PIPE_GET_GIANT(rpipe);
|
||||
if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)
|
||||
nbigpipe++;
|
||||
PIPE_DROP_GIANT(rpipe);
|
||||
pipeunlock(wpipe);
|
||||
} else {
|
||||
/*
|
||||
|
@ -1201,6 +1284,21 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return(error);
|
||||
}
|
||||
|
||||
KASSERT(wpipe->pipe_buffer.buffer != NULL, ("pipe buffer gone"));
|
||||
#endif
|
||||
|
||||
|
@ -1250,7 +1348,12 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
wpipe->pipe_state &= ~PIPE_WANTR;
|
||||
wakeup(wpipe);
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
error = msleep(wpipe, PIPE_MTX(rpipe), PRIBIO | PCATCH,
|
||||
"pipbww", 0);
|
||||
#else
|
||||
error = tsleep(wpipe, PRIBIO | PCATCH, "pipbww", 0);
|
||||
#endif
|
||||
if (wpipe->pipe_state & PIPE_EOF)
|
||||
break;
|
||||
if (error)
|
||||
|
@ -1317,8 +1420,10 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
|
||||
/* Transfer first segment */
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
error = uiomove(&wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in],
|
||||
segsize, uio);
|
||||
PIPE_LOCK(rpipe);
|
||||
|
||||
if (error == 0 && segsize < size) {
|
||||
/*
|
||||
|
@ -1332,8 +1437,10 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
panic("Expected pipe buffer wraparound disappeared");
|
||||
#endif
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
error = uiomove(&wpipe->pipe_buffer.buffer[0],
|
||||
size - segsize, uio);
|
||||
PIPE_LOCK(rpipe);
|
||||
}
|
||||
if (error == 0) {
|
||||
wpipe->pipe_buffer.in += size;
|
||||
|
@ -1379,7 +1486,12 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
pipeselwakeup(wpipe, wpipe);
|
||||
|
||||
wpipe->pipe_state |= PIPE_WANTW;
|
||||
#ifdef __FreeBSD__
|
||||
error = msleep(wpipe, PIPE_MTX(rpipe),
|
||||
PRIBIO | PCATCH, "pipewr", 0);
|
||||
#else
|
||||
error = tsleep(wpipe, PRIBIO | PCATCH, "pipewr", 0);
|
||||
#endif
|
||||
if (error != 0)
|
||||
break;
|
||||
/*
|
||||
|
@ -1431,6 +1543,7 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
*/
|
||||
wpipe->pipe_state |= PIPE_SIGNALR;
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -1438,11 +1551,19 @@ pipe_write(fp, offset, uio, cred, flags)
|
|||
* we implement a very minimal set of ioctls for compatibility with sockets.
|
||||
*/
|
||||
int
|
||||
#ifdef __FreeBSD__
|
||||
pipe_ioctl(fp, cmd, data, td)
|
||||
struct file *fp;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
struct thread *td;
|
||||
#else
|
||||
pipe_ioctl(fp, cmd, data, p)
|
||||
struct file *fp;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
struct proc *p;
|
||||
#endif
|
||||
{
|
||||
struct pipe *mpipe = (struct pipe *)fp->f_data;
|
||||
|
||||
|
@ -1452,20 +1573,24 @@ pipe_ioctl(fp, cmd, data, p)
|
|||
return (0);
|
||||
|
||||
case FIOASYNC:
|
||||
PIPE_LOCK(mpipe);
|
||||
if (*(int *)data) {
|
||||
mpipe->pipe_state |= PIPE_ASYNC;
|
||||
} else {
|
||||
mpipe->pipe_state &= ~PIPE_ASYNC;
|
||||
}
|
||||
PIPE_UNLOCK(mpipe);
|
||||
return (0);
|
||||
|
||||
case FIONREAD:
|
||||
PIPE_LOCK(mpipe);
|
||||
#ifndef PIPE_NODIRECT
|
||||
if (mpipe->pipe_state & PIPE_DIRECTW)
|
||||
*(int *)data = mpipe->pipe_map.cnt;
|
||||
else
|
||||
#endif
|
||||
*(int *)data = mpipe->pipe_buffer.cnt;
|
||||
PIPE_UNLOCK(mpipe);
|
||||
return (0);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
@ -1500,16 +1625,25 @@ pipe_ioctl(fp, cmd, data, p)
|
|||
}
|
||||
|
||||
int
|
||||
pipe_poll(fp, events, p)
|
||||
#ifdef __FreeBSD__
|
||||
pipe_poll(fp, events, cred, td)
|
||||
struct file *fp;
|
||||
int events;
|
||||
struct proc *p;
|
||||
struct ucred *cred;
|
||||
struct thread *td;
|
||||
#elif defined(__NetBSD__)
|
||||
pipe_poll(fp, events, td)
|
||||
struct file *fp;
|
||||
int events;
|
||||
struct proc *td;
|
||||
#endif
|
||||
{
|
||||
struct pipe *rpipe = (struct pipe *)fp->f_data;
|
||||
struct pipe *wpipe;
|
||||
int revents = 0;
|
||||
|
||||
wpipe = rpipe->pipe_peer;
|
||||
PIPE_LOCK(rpipe);
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
if ((rpipe->pipe_buffer.cnt > 0) ||
|
||||
#ifndef PIPE_NODIRECT
|
||||
|
@ -1534,24 +1668,32 @@ pipe_poll(fp, events, p)
|
|||
|
||||
if (revents == 0) {
|
||||
if (events & (POLLIN | POLLRDNORM)) {
|
||||
selrecord(p, &rpipe->pipe_sel);
|
||||
selrecord(td, &rpipe->pipe_sel);
|
||||
rpipe->pipe_state |= PIPE_SEL;
|
||||
}
|
||||
|
||||
if (events & (POLLOUT | POLLWRNORM)) {
|
||||
selrecord(p, &wpipe->pipe_sel);
|
||||
selrecord(td, &wpipe->pipe_sel);
|
||||
wpipe->pipe_state |= PIPE_SEL;
|
||||
}
|
||||
}
|
||||
PIPE_UNLOCK(rpipe);
|
||||
|
||||
return (revents);
|
||||
}
|
||||
|
||||
static int
|
||||
pipe_stat(fp, ub, p)
|
||||
#ifdef __FreeBSD__
|
||||
pipe_stat(fp, ub, td)
|
||||
struct file *fp;
|
||||
struct stat *ub;
|
||||
struct proc *p;
|
||||
struct thread *td;
|
||||
#else
|
||||
pipe_stat(fp, ub, td)
|
||||
struct file *fp;
|
||||
struct stat *ub;
|
||||
struct proc *td;
|
||||
#endif
|
||||
{
|
||||
struct pipe *pipe = (struct pipe *)fp->f_data;
|
||||
|
||||
|
@ -1581,9 +1723,15 @@ pipe_stat(fp, ub, p)
|
|||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
pipe_close(fp, p)
|
||||
#ifdef __FreeBSD__
|
||||
pipe_close(fp, td)
|
||||
struct file *fp;
|
||||
struct proc *p;
|
||||
struct thread *td;
|
||||
#else
|
||||
pipe_close(fp, td)
|
||||
struct file *fp;
|
||||
struct proc *td;
|
||||
#endif
|
||||
{
|
||||
struct pipe *cpipe = (struct pipe *)fp->f_data;
|
||||
|
||||
|
@ -1602,8 +1750,12 @@ pipe_free_kmem(cpipe)
|
|||
{
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
mtx_assert(&vm_mtx, MA_OWNED);
|
||||
|
||||
GIANT_REQUIRED;
|
||||
KASSERT(cpipe->pipe_mtxp == NULL || !mtx_owned(PIPE_MTX(cpipe)),
|
||||
("pipespace: pipe mutex locked"));
|
||||
#endif
|
||||
|
||||
if (cpipe->pipe_buffer.buffer != NULL) {
|
||||
if (cpipe->pipe_buffer.size > PIPE_SIZE)
|
||||
--nbigpipe;
|
||||
|
@ -1645,10 +1797,17 @@ pipeclose(cpipe)
|
|||
struct pipe *cpipe;
|
||||
{
|
||||
struct pipe *ppipe;
|
||||
#ifdef __FreeBSD__
|
||||
int hadpeer = 0;
|
||||
#endif
|
||||
|
||||
if (!cpipe)
|
||||
if (cpipe == NULL)
|
||||
return;
|
||||
|
||||
/* partially created pipes won't have a valid mutex. */
|
||||
if (PIPE_MTX(cpipe) != NULL)
|
||||
PIPE_LOCK(cpipe);
|
||||
|
||||
pipeselwakeup(cpipe, cpipe);
|
||||
|
||||
/*
|
||||
|
@ -1658,34 +1817,50 @@ pipeclose(cpipe)
|
|||
while (cpipe->pipe_busy) {
|
||||
wakeup(cpipe);
|
||||
cpipe->pipe_state |= PIPE_WANTCLOSE | PIPE_EOF;
|
||||
#ifdef __FreeBSD__
|
||||
msleep(cpipe, PIPE_MTX(cpipe), PRIBIO, "pipecl", 0);
|
||||
#else
|
||||
tsleep(cpipe, PRIBIO, "pipecl", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect from peer
|
||||
*/
|
||||
if ((ppipe = cpipe->pipe_peer) != NULL) {
|
||||
#ifdef __FreeBSD__
|
||||
hadpeer++;
|
||||
#endif
|
||||
pipeselwakeup(ppipe, ppipe);
|
||||
|
||||
ppipe->pipe_state |= PIPE_EOF;
|
||||
wakeup(ppipe);
|
||||
#ifdef __FreeBSD__
|
||||
KNOTE(&ppipe->pipe_sel.si_note, 0);
|
||||
#endif
|
||||
ppipe->pipe_peer = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* free resources
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
mtx_lock(&vm_mtx);
|
||||
if (PIPE_MTX(cpipe) != NULL) {
|
||||
PIPE_UNLOCK(cpipe);
|
||||
if (!hadpeer) {
|
||||
mtx_destroy(PIPE_MTX(cpipe));
|
||||
free(PIPE_MTX(cpipe), M_TEMP);
|
||||
}
|
||||
}
|
||||
mtx_lock(&Giant);
|
||||
pipe_free_kmem(cpipe);
|
||||
/* XXX: erm, doesn't zalloc already have its own locks and
|
||||
* not need the giant vm lock?
|
||||
*/
|
||||
zfree(pipe_zone, cpipe);
|
||||
mtx_unlock(&vm_mtx);
|
||||
#endif /* FreeBSD */
|
||||
mtx_unlock(&Giant);
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
if (PIPE_MTX(cpipe) != NULL)
|
||||
PIPE_UNLOCK(cpipe);
|
||||
|
||||
pipe_free_kmem(cpipe);
|
||||
(void) lockmgr(&cpipe->pipe_lock, LK_DRAIN, NULL);
|
||||
pool_put(&pipe_pool, cpipe);
|
||||
|
@ -1697,8 +1872,9 @@ pipeclose(cpipe)
|
|||
static int
|
||||
pipe_kqfilter(struct file *fp, struct knote *kn)
|
||||
{
|
||||
struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data;
|
||||
struct pipe *cpipe;
|
||||
|
||||
cpipe = (struct pipe *)kn->kn_fp->f_data;
|
||||
switch (kn->kn_filter) {
|
||||
case EVFILT_READ:
|
||||
kn->kn_fop = &pipe_rfiltops;
|
||||
|
@ -1711,7 +1887,10 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
|
|||
return (1);
|
||||
}
|
||||
kn->kn_hook = (caddr_t)cpipe;
|
||||
|
||||
PIPE_LOCK(cpipe);
|
||||
SLIST_INSERT_HEAD(&cpipe->pipe_sel.si_note, kn, kn_selnext);
|
||||
PIPE_UNLOCK(cpipe);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1899,9 @@ filt_pipedetach(struct knote *kn)
|
|||
{
|
||||
struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data;
|
||||
|
||||
PIPE_LOCK(cpipe);
|
||||
SLIST_REMOVE(&cpipe->pipe_sel.si_note, kn, knote, kn_selnext);
|
||||
PIPE_UNLOCK(cpipe);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
|
@ -1730,15 +1911,18 @@ filt_piperead(struct knote *kn, long hint)
|
|||
struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
|
||||
struct pipe *wpipe = rpipe->pipe_peer;
|
||||
|
||||
PIPE_LOCK(rpipe);
|
||||
kn->kn_data = rpipe->pipe_buffer.cnt;
|
||||
if ((kn->kn_data == 0) && (rpipe->pipe_state & PIPE_DIRECTW))
|
||||
kn->kn_data = rpipe->pipe_map.cnt;
|
||||
|
||||
if ((rpipe->pipe_state & PIPE_EOF) ||
|
||||
(wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
|
||||
kn->kn_flags |= EV_EOF;
|
||||
kn->kn_flags |= EV_EOF;
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (1);
|
||||
}
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (kn->kn_data > 0);
|
||||
}
|
||||
|
||||
|
@ -1749,15 +1933,18 @@ filt_pipewrite(struct knote *kn, long hint)
|
|||
struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
|
||||
struct pipe *wpipe = rpipe->pipe_peer;
|
||||
|
||||
PIPE_LOCK(rpipe);
|
||||
if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
|
||||
kn->kn_data = 0;
|
||||
kn->kn_flags |= EV_EOF;
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (1);
|
||||
}
|
||||
kn->kn_data = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
|
||||
if (wpipe->pipe_state & PIPE_DIRECTW)
|
||||
kn->kn_data = 0;
|
||||
|
||||
PIPE_UNLOCK(rpipe);
|
||||
return (kn->kn_data >= PIPE_BUF);
|
||||
}
|
||||
#endif /* FreeBSD */
|
||||
|
|
Loading…
Reference in New Issue