From fcc4c4d402b331f859c0b1e275748be1a15db470 Mon Sep 17 00:00:00 2001 From: jdolecek Date: Wed, 13 Mar 2002 21:50:24 +0000 Subject: [PATCH] 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 --- sys/kern/sys_pipe.c | 393 ++++++++++++++++++++++++++++++++------------ 1 file changed, 290 insertions(+), 103 deletions(-) diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 2de84b7348c1..08a509a562f0 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -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 -__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 #include @@ -67,8 +67,11 @@ __KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $" #include #include #include +#include +#include #include #include +#include #include #include #include @@ -76,11 +79,9 @@ __KERNEL_RCSID(0, "$NetBSD: sys_pipe.c,v 1.23 2002/03/08 20:48:41 thorpej Exp $" #include #ifdef __FreeBSD__ #include -#include -#include -#elif defined(__NetBSD__) +#endif +#ifdef __NetBSD__ #include -#include #include #include #include @@ -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 */