sys_pipe.c revision 16322
113675Sdyson/* 213675Sdyson * Copyright (c) 1996 John S. Dyson 313675Sdyson * All rights reserved. 413675Sdyson * 513675Sdyson * Redistribution and use in source and binary forms, with or without 613675Sdyson * modification, are permitted provided that the following conditions 713675Sdyson * are met: 813675Sdyson * 1. Redistributions of source code must retain the above copyright 913675Sdyson * notice immediately at the beginning of the file, without modification, 1013675Sdyson * this list of conditions, and the following disclaimer. 1113675Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1213675Sdyson * notice, this list of conditions and the following disclaimer in the 1313675Sdyson * documentation and/or other materials provided with the distribution. 1413675Sdyson * 3. Absolutely no warranty of function or purpose is made by the author 1513675Sdyson * John S. Dyson. 1614037Sdyson * 4. Modifications may be freely made to this file if the above conditions 1713675Sdyson * are met. 1813675Sdyson * 1916322Sgpalmer * $Id: sys_pipe.c,v 1.15 1996/03/25 01:48:28 dyson Exp $ 2013675Sdyson */ 2113675Sdyson 2213675Sdyson#ifndef OLD_PIPE 2313675Sdyson 2413675Sdyson/* 2513675Sdyson * This file contains a high-performance replacement for the socket-based 2613675Sdyson * pipes scheme originally used in FreeBSD/4.4Lite. It does not support 2713675Sdyson * all features of sockets, but does do everything that pipes normally 2813675Sdyson * do. 2913675Sdyson */ 3013675Sdyson 3113907Sdyson/* 3213907Sdyson * This code has two modes of operation, a small write mode and a large 3313907Sdyson * write mode. The small write mode acts like conventional pipes with 3413907Sdyson * a kernel buffer. If the buffer is less than PIPE_MINDIRECT, then the 3513907Sdyson * "normal" pipe buffering is done. If the buffer is between PIPE_MINDIRECT 3613907Sdyson * and PIPE_SIZE in size, it is fully mapped and wired into the kernel, and 3713907Sdyson * the receiving process can copy it directly from the pages in the sending 3813907Sdyson * process. 3913907Sdyson * 4013907Sdyson * If the sending process receives a signal, it is possible that it will 4113913Sdyson * go away, and certainly its address space can change, because control 4213907Sdyson * is returned back to the user-mode side. In that case, the pipe code 4313907Sdyson * arranges to copy the buffer supplied by the user process, to a pageable 4413907Sdyson * kernel buffer, and the receiving process will grab the data from the 4513907Sdyson * pageable kernel buffer. Since signals don't happen all that often, 4613907Sdyson * the copy operation is normally eliminated. 4713907Sdyson * 4813907Sdyson * The constant PIPE_MINDIRECT is chosen to make sure that buffering will 4913907Sdyson * happen for small transfers so that the system will not spend all of 5013913Sdyson * its time context switching. PIPE_SIZE is constrained by the 5113907Sdyson * amount of kernel virtual memory. 5213907Sdyson */ 5313907Sdyson 5413675Sdyson#include <sys/param.h> 5513675Sdyson#include <sys/systm.h> 5613675Sdyson#include <sys/proc.h> 5713675Sdyson#include <sys/file.h> 5813675Sdyson#include <sys/protosw.h> 5913675Sdyson#include <sys/stat.h> 6013675Sdyson#include <sys/filedesc.h> 6113675Sdyson#include <sys/malloc.h> 6213675Sdyson#include <sys/ioctl.h> 6313675Sdyson#include <sys/stat.h> 6413675Sdyson#include <sys/select.h> 6513675Sdyson#include <sys/signalvar.h> 6613675Sdyson#include <sys/errno.h> 6713675Sdyson#include <sys/queue.h> 6813675Sdyson#include <sys/vmmeter.h> 6913675Sdyson#include <sys/kernel.h> 7013675Sdyson#include <sys/sysproto.h> 7113675Sdyson#include <sys/pipe.h> 7213675Sdyson 7313675Sdyson#include <vm/vm.h> 7413675Sdyson#include <vm/vm_prot.h> 7513675Sdyson#include <vm/vm_param.h> 7613675Sdyson#include <vm/lock.h> 7713675Sdyson#include <vm/vm_object.h> 7813675Sdyson#include <vm/vm_kern.h> 7913675Sdyson#include <vm/vm_extern.h> 8013675Sdyson#include <vm/pmap.h> 8113675Sdyson#include <vm/vm_map.h> 8213907Sdyson#include <vm/vm_page.h> 8313675Sdyson 8414037Sdyson/* 8514037Sdyson * Use this define if you want to disable *fancy* VM things. Expect an 8614037Sdyson * approx 30% decrease in transfer rate. This could be useful for 8714037Sdyson * NetBSD or OpenBSD. 8814037Sdyson */ 8914037Sdyson/* #define PIPE_NODIRECT */ 9014037Sdyson 9114037Sdyson/* 9214037Sdyson * interfaces to the outside world 9314037Sdyson */ 9413675Sdysonstatic int pipe_read __P((struct file *fp, struct uio *uio, 9513675Sdyson struct ucred *cred)); 9613675Sdysonstatic int pipe_write __P((struct file *fp, struct uio *uio, 9713675Sdyson struct ucred *cred)); 9813675Sdysonstatic int pipe_close __P((struct file *fp, struct proc *p)); 9913675Sdysonstatic int pipe_select __P((struct file *fp, int which, struct proc *p)); 10013675Sdysonstatic int pipe_ioctl __P((struct file *fp, int cmd, caddr_t data, struct proc *p)); 10113675Sdyson 10213675Sdysonstatic struct fileops pipeops = 10313675Sdyson { pipe_read, pipe_write, pipe_ioctl, pipe_select, pipe_close }; 10413675Sdyson 10513675Sdyson/* 10613675Sdyson * Default pipe buffer size(s), this can be kind-of large now because pipe 10713675Sdyson * space is pageable. The pipe code will try to maintain locality of 10813675Sdyson * reference for performance reasons, so small amounts of outstanding I/O 10913675Sdyson * will not wipe the cache. 11013675Sdyson */ 11113907Sdyson#define MINPIPESIZE (PIPE_SIZE/3) 11213907Sdyson#define MAXPIPESIZE (2*PIPE_SIZE/3) 11313675Sdyson 11413907Sdyson/* 11513907Sdyson * Maximum amount of kva for pipes -- this is kind-of a soft limit, but 11613907Sdyson * is there so that on large systems, we don't exhaust it. 11713907Sdyson */ 11813907Sdyson#define MAXPIPEKVA (8*1024*1024) 11913907Sdyson 12013907Sdyson/* 12113907Sdyson * Limit for direct transfers, we cannot, of course limit 12213907Sdyson * the amount of kva for pipes in general though. 12313907Sdyson */ 12413907Sdyson#define LIMITPIPEKVA (16*1024*1024) 12513907Sdysonint amountpipekva; 12613907Sdyson 12713675Sdysonstatic void pipeclose __P((struct pipe *cpipe)); 12813675Sdysonstatic void pipeinit __P((struct pipe *cpipe)); 12913907Sdysonstatic __inline int pipelock __P((struct pipe *cpipe, int catch)); 13013675Sdysonstatic __inline void pipeunlock __P((struct pipe *cpipe)); 13114122Speterstatic __inline void pipeselwakeup __P((struct pipe *cpipe)); 13214037Sdyson#ifndef PIPE_NODIRECT 13313907Sdysonstatic int pipe_build_write_buffer __P((struct pipe *wpipe, struct uio *uio)); 13413907Sdysonstatic void pipe_destroy_write_buffer __P((struct pipe *wpipe)); 13513907Sdysonstatic int pipe_direct_write __P((struct pipe *wpipe, struct uio *uio)); 13613907Sdysonstatic void pipe_clone_write_buffer __P((struct pipe *wpipe)); 13714037Sdyson#endif 13813907Sdysonstatic int pipewrite __P((struct pipe *wpipe, struct uio *uio, int nbio)); 13913907Sdysonstatic void pipespace __P((struct pipe *cpipe)); 14013675Sdyson 14113675Sdyson/* 14213675Sdyson * The pipe system call for the DTYPE_PIPE type of pipes 14313675Sdyson */ 14413675Sdyson 14513675Sdyson/* ARGSUSED */ 14613675Sdysonint 14713675Sdysonpipe(p, uap, retval) 14813675Sdyson struct proc *p; 14913675Sdyson struct pipe_args /* { 15013675Sdyson int dummy; 15113675Sdyson } */ *uap; 15213675Sdyson int retval[]; 15313675Sdyson{ 15413675Sdyson register struct filedesc *fdp = p->p_fd; 15513675Sdyson struct file *rf, *wf; 15613675Sdyson struct pipe *rpipe, *wpipe; 15713675Sdyson int fd, error; 15813675Sdyson 15913675Sdyson rpipe = malloc( sizeof (*rpipe), M_TEMP, M_WAITOK); 16013675Sdyson pipeinit(rpipe); 16113907Sdyson rpipe->pipe_state |= PIPE_DIRECTOK; 16213675Sdyson wpipe = malloc( sizeof (*wpipe), M_TEMP, M_WAITOK); 16313675Sdyson pipeinit(wpipe); 16413907Sdyson wpipe->pipe_state |= PIPE_DIRECTOK; 16513675Sdyson 16613675Sdyson error = falloc(p, &rf, &fd); 16713675Sdyson if (error) 16813675Sdyson goto free2; 16913675Sdyson retval[0] = fd; 17013675Sdyson rf->f_flag = FREAD | FWRITE; 17113675Sdyson rf->f_type = DTYPE_PIPE; 17213675Sdyson rf->f_ops = &pipeops; 17313675Sdyson rf->f_data = (caddr_t)rpipe; 17413675Sdyson error = falloc(p, &wf, &fd); 17513675Sdyson if (error) 17613675Sdyson goto free3; 17713675Sdyson wf->f_flag = FREAD | FWRITE; 17813675Sdyson wf->f_type = DTYPE_PIPE; 17913675Sdyson wf->f_ops = &pipeops; 18013675Sdyson wf->f_data = (caddr_t)wpipe; 18113675Sdyson retval[1] = fd; 18213675Sdyson 18313675Sdyson rpipe->pipe_peer = wpipe; 18413675Sdyson wpipe->pipe_peer = rpipe; 18513675Sdyson 18613675Sdyson return (0); 18713675Sdysonfree3: 18813675Sdyson ffree(rf); 18913675Sdyson fdp->fd_ofiles[retval[0]] = 0; 19013675Sdysonfree2: 19113675Sdyson (void)pipeclose(wpipe); 19213675Sdysonfree1: 19313675Sdyson (void)pipeclose(rpipe); 19413675Sdyson return (error); 19513675Sdyson} 19613675Sdyson 19713909Sdyson/* 19813909Sdyson * Allocate kva for pipe circular buffer, the space is pageable 19913909Sdyson */ 20013675Sdysonstatic void 20113907Sdysonpipespace(cpipe) 20213675Sdyson struct pipe *cpipe; 20313675Sdyson{ 20413688Sdyson int npages, error; 20513675Sdyson 20613907Sdyson npages = round_page(cpipe->pipe_buffer.size)/PAGE_SIZE; 20713675Sdyson /* 20813675Sdyson * Create an object, I don't like the idea of paging to/from 20913675Sdyson * kernel_object. 21014037Sdyson * XXX -- minor change needed here for NetBSD/OpenBSD VM systems. 21113675Sdyson */ 21213675Sdyson cpipe->pipe_buffer.object = vm_object_allocate(OBJT_DEFAULT, npages); 21313688Sdyson cpipe->pipe_buffer.buffer = (caddr_t) vm_map_min(kernel_map); 21413675Sdyson 21513675Sdyson /* 21613675Sdyson * Insert the object into the kernel map, and allocate kva for it. 21713675Sdyson * The map entry is, by default, pageable. 21814037Sdyson * XXX -- minor change needed here for NetBSD/OpenBSD VM systems. 21913675Sdyson */ 22013688Sdyson error = vm_map_find(kernel_map, cpipe->pipe_buffer.object, 0, 22113907Sdyson (vm_offset_t *) &cpipe->pipe_buffer.buffer, 22213907Sdyson cpipe->pipe_buffer.size, 1, 22313688Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 22413675Sdyson 22513688Sdyson if (error != KERN_SUCCESS) 22613688Sdyson panic("pipeinit: cannot allocate pipe -- out of kvm -- code = %d", error); 22713907Sdyson amountpipekva += cpipe->pipe_buffer.size; 22813907Sdyson} 22913688Sdyson 23013907Sdyson/* 23113907Sdyson * initialize and allocate VM and memory for pipe 23213907Sdyson */ 23313907Sdysonstatic void 23413907Sdysonpipeinit(cpipe) 23513907Sdyson struct pipe *cpipe; 23613907Sdyson{ 23713913Sdyson int s; 23813907Sdyson 23913675Sdyson cpipe->pipe_buffer.in = 0; 24013675Sdyson cpipe->pipe_buffer.out = 0; 24113675Sdyson cpipe->pipe_buffer.cnt = 0; 24213907Sdyson cpipe->pipe_buffer.size = PIPE_SIZE; 24313907Sdyson /* Buffer kva gets dynamically allocated */ 24413907Sdyson cpipe->pipe_buffer.buffer = NULL; 24513675Sdyson 24613675Sdyson cpipe->pipe_state = 0; 24713675Sdyson cpipe->pipe_peer = NULL; 24813675Sdyson cpipe->pipe_busy = 0; 24913913Sdyson s = splhigh(); 25013675Sdyson cpipe->pipe_ctime = time; 25113675Sdyson cpipe->pipe_atime = time; 25213675Sdyson cpipe->pipe_mtime = time; 25313913Sdyson splx(s); 25413675Sdyson bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel); 25513907Sdyson 25614037Sdyson#ifndef PIPE_NODIRECT 25713907Sdyson /* 25813907Sdyson * pipe data structure initializations to support direct pipe I/O 25913907Sdyson */ 26013907Sdyson cpipe->pipe_map.cnt = 0; 26113907Sdyson cpipe->pipe_map.kva = 0; 26213907Sdyson cpipe->pipe_map.pos = 0; 26313907Sdyson cpipe->pipe_map.npages = 0; 26414037Sdyson#endif 26513675Sdyson} 26613675Sdyson 26713675Sdyson 26813675Sdyson/* 26913675Sdyson * lock a pipe for I/O, blocking other access 27013675Sdyson */ 27113675Sdysonstatic __inline int 27213907Sdysonpipelock(cpipe, catch) 27313675Sdyson struct pipe *cpipe; 27413907Sdyson int catch; 27513675Sdyson{ 27613776Sdyson int error; 27713675Sdyson while (cpipe->pipe_state & PIPE_LOCK) { 27813675Sdyson cpipe->pipe_state |= PIPE_LWANT; 27914177Sdyson if (error = tsleep( cpipe, 28013907Sdyson catch?(PRIBIO|PCATCH):PRIBIO, "pipelk", 0)) { 28113776Sdyson return error; 28213675Sdyson } 28313675Sdyson } 28413675Sdyson cpipe->pipe_state |= PIPE_LOCK; 28513675Sdyson return 0; 28613675Sdyson} 28713675Sdyson 28813675Sdyson/* 28913675Sdyson * unlock a pipe I/O lock 29013675Sdyson */ 29113675Sdysonstatic __inline void 29213675Sdysonpipeunlock(cpipe) 29313675Sdyson struct pipe *cpipe; 29413675Sdyson{ 29513675Sdyson cpipe->pipe_state &= ~PIPE_LOCK; 29613675Sdyson if (cpipe->pipe_state & PIPE_LWANT) { 29713675Sdyson cpipe->pipe_state &= ~PIPE_LWANT; 29814177Sdyson wakeup(cpipe); 29913675Sdyson } 30013675Sdyson return; 30113675Sdyson} 30213675Sdyson 30314037Sdysonstatic __inline void 30414037Sdysonpipeselwakeup(cpipe) 30514037Sdyson struct pipe *cpipe; 30614037Sdyson{ 30714037Sdyson if (cpipe->pipe_state & PIPE_SEL) { 30814037Sdyson cpipe->pipe_state &= ~PIPE_SEL; 30914037Sdyson selwakeup(&cpipe->pipe_sel); 31014037Sdyson } 31114037Sdyson} 31214037Sdyson 31314037Sdyson#ifndef PIPE_NODIRECT 31413907Sdyson#if 0 31513907Sdysonstatic void 31613907Sdysonpipe_mark_pages_clean(cpipe) 31713907Sdyson struct pipe *cpipe; 31813907Sdyson{ 31913907Sdyson vm_size_t off; 32013907Sdyson vm_page_t m; 32113907Sdyson 32213907Sdyson for(off = 0; off < cpipe->pipe_buffer.object->size; off += 1) { 32313907Sdyson m = vm_page_lookup(cpipe->pipe_buffer.object, off); 32413907Sdyson if ((m != NULL) && (m->busy == 0) && (m->flags & PG_BUSY) == 0) { 32513907Sdyson m->dirty = 0; 32613907Sdyson pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 32713907Sdyson } 32813907Sdyson } 32913907Sdyson} 33013907Sdyson#endif 33114037Sdyson#endif 33213907Sdyson 33313675Sdyson/* ARGSUSED */ 33413675Sdysonstatic int 33513675Sdysonpipe_read(fp, uio, cred) 33613675Sdyson struct file *fp; 33713675Sdyson struct uio *uio; 33813675Sdyson struct ucred *cred; 33913675Sdyson{ 34013675Sdyson 34113675Sdyson struct pipe *rpipe = (struct pipe *) fp->f_data; 34213675Sdyson int error = 0; 34313675Sdyson int nread = 0; 34413907Sdyson int size; 34513675Sdyson 34613675Sdyson ++rpipe->pipe_busy; 34713675Sdyson while (uio->uio_resid) { 34813907Sdyson /* 34913907Sdyson * normal pipe buffer receive 35013907Sdyson */ 35113675Sdyson if (rpipe->pipe_buffer.cnt > 0) { 35213675Sdyson int size = rpipe->pipe_buffer.size - rpipe->pipe_buffer.out; 35313675Sdyson if (size > rpipe->pipe_buffer.cnt) 35413675Sdyson size = rpipe->pipe_buffer.cnt; 35513675Sdyson if (size > uio->uio_resid) 35613675Sdyson size = uio->uio_resid; 35713907Sdyson if ((error = pipelock(rpipe,1)) == 0) { 35813675Sdyson error = uiomove( &rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out], 35913675Sdyson size, uio); 36013675Sdyson pipeunlock(rpipe); 36113675Sdyson } 36213675Sdyson if (error) { 36313675Sdyson break; 36413675Sdyson } 36513675Sdyson rpipe->pipe_buffer.out += size; 36613675Sdyson if (rpipe->pipe_buffer.out >= rpipe->pipe_buffer.size) 36713675Sdyson rpipe->pipe_buffer.out = 0; 36813675Sdyson 36913675Sdyson rpipe->pipe_buffer.cnt -= size; 37013675Sdyson nread += size; 37114037Sdyson#ifndef PIPE_NODIRECT 37213907Sdyson /* 37313907Sdyson * Direct copy, bypassing a kernel buffer. 37413907Sdyson */ 37513907Sdyson } else if ((size = rpipe->pipe_map.cnt) && 37613907Sdyson (rpipe->pipe_state & PIPE_DIRECTW)) { 37713907Sdyson caddr_t va; 37813907Sdyson if (size > uio->uio_resid) 37913907Sdyson size = uio->uio_resid; 38013907Sdyson if ((error = pipelock(rpipe,1)) == 0) { 38113907Sdyson va = (caddr_t) rpipe->pipe_map.kva + rpipe->pipe_map.pos; 38213907Sdyson error = uiomove(va, size, uio); 38313907Sdyson pipeunlock(rpipe); 38413907Sdyson } 38513907Sdyson if (error) 38613907Sdyson break; 38713907Sdyson nread += size; 38813907Sdyson rpipe->pipe_map.pos += size; 38913907Sdyson rpipe->pipe_map.cnt -= size; 39013907Sdyson if (rpipe->pipe_map.cnt == 0) { 39113907Sdyson rpipe->pipe_state &= ~PIPE_DIRECTW; 39213907Sdyson wakeup(rpipe); 39313907Sdyson } 39414037Sdyson#endif 39513675Sdyson } else { 39613675Sdyson /* 39713675Sdyson * detect EOF condition 39813675Sdyson */ 39913675Sdyson if (rpipe->pipe_state & PIPE_EOF) { 40014802Sdyson /* XXX error = ? */ 40113675Sdyson break; 40213675Sdyson } 40313675Sdyson /* 40413675Sdyson * If the "write-side" has been blocked, wake it up now. 40513675Sdyson */ 40613675Sdyson if (rpipe->pipe_state & PIPE_WANTW) { 40713675Sdyson rpipe->pipe_state &= ~PIPE_WANTW; 40813675Sdyson wakeup(rpipe); 40913675Sdyson } 41013774Sdyson if (nread > 0) 41113675Sdyson break; 41213774Sdyson if (rpipe->pipe_state & PIPE_NBIO) { 41313774Sdyson error = EAGAIN; 41413774Sdyson break; 41513774Sdyson } 41613675Sdyson 41713675Sdyson /* 41813675Sdyson * If there is no more to read in the pipe, reset 41913913Sdyson * its pointers to the beginning. This improves 42013675Sdyson * cache hit stats. 42113675Sdyson */ 42213675Sdyson 42313907Sdyson if ((error = pipelock(rpipe,1)) == 0) { 42413675Sdyson if (rpipe->pipe_buffer.cnt == 0) { 42513675Sdyson rpipe->pipe_buffer.in = 0; 42613675Sdyson rpipe->pipe_buffer.out = 0; 42713675Sdyson } 42813675Sdyson pipeunlock(rpipe); 42913675Sdyson } else { 43013675Sdyson break; 43113675Sdyson } 43214177Sdyson 43314177Sdyson if (rpipe->pipe_state & PIPE_WANTW) { 43414177Sdyson rpipe->pipe_state &= ~PIPE_WANTW; 43514177Sdyson wakeup(rpipe); 43614177Sdyson } 43714177Sdyson 43813675Sdyson rpipe->pipe_state |= PIPE_WANTR; 43913776Sdyson if (error = tsleep(rpipe, PRIBIO|PCATCH, "piperd", 0)) { 44013675Sdyson break; 44113675Sdyson } 44213675Sdyson } 44313675Sdyson } 44413675Sdyson 44513913Sdyson if (error == 0) { 44613913Sdyson int s = splhigh(); 44713913Sdyson rpipe->pipe_atime = time; 44813913Sdyson splx(s); 44913913Sdyson } 45013913Sdyson 45113675Sdyson --rpipe->pipe_busy; 45213675Sdyson if ((rpipe->pipe_busy == 0) && (rpipe->pipe_state & PIPE_WANT)) { 45313675Sdyson rpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTW); 45413675Sdyson wakeup(rpipe); 45513675Sdyson } else if (rpipe->pipe_buffer.cnt < MINPIPESIZE) { 45613675Sdyson /* 45713675Sdyson * If there is no more to read in the pipe, reset 45813913Sdyson * its pointers to the beginning. This improves 45913675Sdyson * cache hit stats. 46013675Sdyson */ 46113907Sdyson if ((error == 0) && (error = pipelock(rpipe,1)) == 0) { 46213675Sdyson if (rpipe->pipe_buffer.cnt == 0) { 46313907Sdyson#if 0 46413907Sdyson pipe_mark_pages_clean(rpipe); 46513907Sdyson#endif 46613675Sdyson rpipe->pipe_buffer.in = 0; 46713675Sdyson rpipe->pipe_buffer.out = 0; 46813675Sdyson } 46913675Sdyson pipeunlock(rpipe); 47013675Sdyson } 47113675Sdyson 47213675Sdyson /* 47313675Sdyson * If the "write-side" has been blocked, wake it up now. 47413675Sdyson */ 47513675Sdyson if (rpipe->pipe_state & PIPE_WANTW) { 47613675Sdyson rpipe->pipe_state &= ~PIPE_WANTW; 47713675Sdyson wakeup(rpipe); 47813675Sdyson } 47913675Sdyson } 48014037Sdyson 48114802Sdyson if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF) 48214037Sdyson pipeselwakeup(rpipe); 48314037Sdyson 48413675Sdyson return error; 48513675Sdyson} 48613675Sdyson 48714037Sdyson#ifndef PIPE_NODIRECT 48813907Sdyson/* 48913907Sdyson * Map the sending processes' buffer into kernel space and wire it. 49013907Sdyson * This is similar to a physical write operation. 49113907Sdyson */ 49213675Sdysonstatic int 49313907Sdysonpipe_build_write_buffer(wpipe, uio) 49413907Sdyson struct pipe *wpipe; 49513675Sdyson struct uio *uio; 49613675Sdyson{ 49713907Sdyson int size; 49813907Sdyson int i; 49913907Sdyson vm_offset_t addr, endaddr, paddr; 50013907Sdyson 50113907Sdyson size = uio->uio_iov->iov_len; 50213907Sdyson if (size > wpipe->pipe_buffer.size) 50313907Sdyson size = wpipe->pipe_buffer.size; 50413907Sdyson 50513907Sdyson endaddr = round_page(uio->uio_iov->iov_base + size); 50613907Sdyson for(i = 0, addr = trunc_page(uio->uio_iov->iov_base); 50713907Sdyson addr < endaddr; 50813907Sdyson addr += PAGE_SIZE, i+=1) { 50913907Sdyson 51013907Sdyson vm_page_t m; 51113907Sdyson 51213909Sdyson vm_fault_quick( (caddr_t) addr, VM_PROT_READ); 51313907Sdyson paddr = pmap_kextract(addr); 51413907Sdyson if (!paddr) { 51513907Sdyson int j; 51613907Sdyson for(j=0;j<i;j++) 51713907Sdyson vm_page_unwire(wpipe->pipe_map.ms[j]); 51813907Sdyson return EFAULT; 51913907Sdyson } 52013907Sdyson 52113907Sdyson m = PHYS_TO_VM_PAGE(paddr); 52213907Sdyson vm_page_wire(m); 52313907Sdyson wpipe->pipe_map.ms[i] = m; 52413907Sdyson } 52513907Sdyson 52613907Sdyson/* 52713907Sdyson * set up the control block 52813907Sdyson */ 52913907Sdyson wpipe->pipe_map.npages = i; 53013907Sdyson wpipe->pipe_map.pos = ((vm_offset_t) uio->uio_iov->iov_base) & PAGE_MASK; 53113907Sdyson wpipe->pipe_map.cnt = size; 53213907Sdyson 53313907Sdyson/* 53413907Sdyson * and map the buffer 53513907Sdyson */ 53613907Sdyson if (wpipe->pipe_map.kva == 0) { 53713912Sdyson /* 53813912Sdyson * We need to allocate space for an extra page because the 53913912Sdyson * address range might (will) span pages at times. 54013912Sdyson */ 54113907Sdyson wpipe->pipe_map.kva = kmem_alloc_pageable(kernel_map, 54213912Sdyson wpipe->pipe_buffer.size + PAGE_SIZE); 54313912Sdyson amountpipekva += wpipe->pipe_buffer.size + PAGE_SIZE; 54413907Sdyson } 54513907Sdyson pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms, 54613907Sdyson wpipe->pipe_map.npages); 54713907Sdyson 54813907Sdyson/* 54913907Sdyson * and update the uio data 55013907Sdyson */ 55113907Sdyson 55213907Sdyson uio->uio_iov->iov_len -= size; 55313907Sdyson uio->uio_iov->iov_base += size; 55413907Sdyson if (uio->uio_iov->iov_len == 0) 55513907Sdyson uio->uio_iov++; 55613907Sdyson uio->uio_resid -= size; 55713907Sdyson uio->uio_offset += size; 55813907Sdyson return 0; 55913907Sdyson} 56013907Sdyson 56113907Sdyson/* 56213907Sdyson * unmap and unwire the process buffer 56313907Sdyson */ 56413907Sdysonstatic void 56513907Sdysonpipe_destroy_write_buffer(wpipe) 56613907Sdysonstruct pipe *wpipe; 56713907Sdyson{ 56813907Sdyson int i; 56913907Sdyson pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages); 57013907Sdyson 57113907Sdyson if (wpipe->pipe_map.kva) { 57213907Sdyson if (amountpipekva > MAXPIPEKVA) { 57313907Sdyson vm_offset_t kva = wpipe->pipe_map.kva; 57413907Sdyson wpipe->pipe_map.kva = 0; 57513907Sdyson kmem_free(kernel_map, kva, 57613912Sdyson wpipe->pipe_buffer.size + PAGE_SIZE); 57713912Sdyson amountpipekva -= wpipe->pipe_buffer.size + PAGE_SIZE; 57813907Sdyson } 57913907Sdyson } 58013907Sdyson for (i=0;i<wpipe->pipe_map.npages;i++) 58113907Sdyson vm_page_unwire(wpipe->pipe_map.ms[i]); 58213907Sdyson} 58313907Sdyson 58413907Sdyson/* 58513907Sdyson * In the case of a signal, the writing process might go away. This 58613907Sdyson * code copies the data into the circular buffer so that the source 58713907Sdyson * pages can be freed without loss of data. 58813907Sdyson */ 58913907Sdysonstatic void 59013907Sdysonpipe_clone_write_buffer(wpipe) 59113907Sdysonstruct pipe *wpipe; 59213907Sdyson{ 59313907Sdyson int size; 59413907Sdyson int pos; 59513907Sdyson 59613907Sdyson size = wpipe->pipe_map.cnt; 59713907Sdyson pos = wpipe->pipe_map.pos; 59813907Sdyson bcopy((caddr_t) wpipe->pipe_map.kva+pos, 59913907Sdyson (caddr_t) wpipe->pipe_buffer.buffer, 60013907Sdyson size); 60113907Sdyson 60213907Sdyson wpipe->pipe_buffer.in = size; 60313907Sdyson wpipe->pipe_buffer.out = 0; 60413907Sdyson wpipe->pipe_buffer.cnt = size; 60513907Sdyson wpipe->pipe_state &= ~PIPE_DIRECTW; 60613907Sdyson 60713907Sdyson pipe_destroy_write_buffer(wpipe); 60813907Sdyson} 60913907Sdyson 61013907Sdyson/* 61113907Sdyson * This implements the pipe buffer write mechanism. Note that only 61213907Sdyson * a direct write OR a normal pipe write can be pending at any given time. 61313907Sdyson * If there are any characters in the pipe buffer, the direct write will 61413907Sdyson * be deferred until the receiving process grabs all of the bytes from 61513907Sdyson * the pipe buffer. Then the direct mapping write is set-up. 61613907Sdyson */ 61713907Sdysonstatic int 61813907Sdysonpipe_direct_write(wpipe, uio) 61913907Sdyson struct pipe *wpipe; 62013907Sdyson struct uio *uio; 62113907Sdyson{ 62213907Sdyson int error; 62313951Sdysonretry: 62413907Sdyson while (wpipe->pipe_state & PIPE_DIRECTW) { 62513951Sdyson if ( wpipe->pipe_state & PIPE_WANTR) { 62613951Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 62713951Sdyson wakeup(wpipe); 62813951Sdyson } 62913992Sdyson wpipe->pipe_state |= PIPE_WANTW; 63013907Sdyson error = tsleep(wpipe, 63113907Sdyson PRIBIO|PCATCH, "pipdww", 0); 63214802Sdyson if (error) 63313907Sdyson goto error1; 63414802Sdyson if (wpipe->pipe_state & PIPE_EOF) { 63514802Sdyson error = EPIPE; 63614802Sdyson goto error1; 63714802Sdyson } 63813907Sdyson } 63913907Sdyson wpipe->pipe_map.cnt = 0; /* transfer not ready yet */ 64013951Sdyson if (wpipe->pipe_buffer.cnt > 0) { 64113951Sdyson if ( wpipe->pipe_state & PIPE_WANTR) { 64213951Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 64313951Sdyson wakeup(wpipe); 64413951Sdyson } 64513951Sdyson 64613992Sdyson wpipe->pipe_state |= PIPE_WANTW; 64713907Sdyson error = tsleep(wpipe, 64813907Sdyson PRIBIO|PCATCH, "pipdwc", 0); 64914802Sdyson if (error) 65013907Sdyson goto error1; 65114802Sdyson if (wpipe->pipe_state & PIPE_EOF) { 65214802Sdyson error = EPIPE; 65314802Sdyson goto error1; 65413907Sdyson } 65513951Sdyson goto retry; 65613907Sdyson } 65713907Sdyson 65813951Sdyson wpipe->pipe_state |= PIPE_DIRECTW; 65913951Sdyson 66013907Sdyson error = pipe_build_write_buffer(wpipe, uio); 66113907Sdyson if (error) { 66213907Sdyson wpipe->pipe_state &= ~PIPE_DIRECTW; 66313907Sdyson goto error1; 66413907Sdyson } 66513907Sdyson 66613907Sdyson error = 0; 66713907Sdyson while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) { 66813907Sdyson if (wpipe->pipe_state & PIPE_EOF) { 66913907Sdyson pipelock(wpipe, 0); 67013907Sdyson pipe_destroy_write_buffer(wpipe); 67113907Sdyson pipeunlock(wpipe); 67214037Sdyson pipeselwakeup(wpipe); 67314802Sdyson error = EPIPE; 67414802Sdyson goto error1; 67513907Sdyson } 67613992Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 67713992Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 67813992Sdyson wakeup(wpipe); 67913992Sdyson } 68014037Sdyson pipeselwakeup(wpipe); 68113907Sdyson error = tsleep(wpipe, PRIBIO|PCATCH, "pipdwt", 0); 68213907Sdyson } 68313907Sdyson 68413907Sdyson pipelock(wpipe,0); 68513907Sdyson if (wpipe->pipe_state & PIPE_DIRECTW) { 68613907Sdyson /* 68713907Sdyson * this bit of trickery substitutes a kernel buffer for 68813907Sdyson * the process that might be going away. 68913907Sdyson */ 69013907Sdyson pipe_clone_write_buffer(wpipe); 69113907Sdyson } else { 69213907Sdyson pipe_destroy_write_buffer(wpipe); 69313907Sdyson } 69413907Sdyson pipeunlock(wpipe); 69513907Sdyson return error; 69613907Sdyson 69713907Sdysonerror1: 69813907Sdyson wakeup(wpipe); 69913907Sdyson return error; 70013907Sdyson} 70114037Sdyson#endif 70213907Sdyson 70313907Sdysonstatic __inline int 70413907Sdysonpipewrite(wpipe, uio, nbio) 70513907Sdyson struct pipe *wpipe; 70613907Sdyson struct uio *uio; 70713907Sdyson int nbio; 70813907Sdyson{ 70913675Sdyson int error = 0; 71013913Sdyson int orig_resid; 71113675Sdyson 71213675Sdyson /* 71313675Sdyson * detect loss of pipe read side, issue SIGPIPE if lost. 71413675Sdyson */ 71513675Sdyson if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF)) { 71613774Sdyson return EPIPE; 71713675Sdyson } 71813675Sdyson 71913907Sdyson if( wpipe->pipe_buffer.buffer == NULL) { 72013907Sdyson if ((error = pipelock(wpipe,1)) == 0) { 72113907Sdyson pipespace(wpipe); 72213907Sdyson pipeunlock(wpipe); 72313907Sdyson } else { 72413907Sdyson return error; 72513907Sdyson } 72613907Sdyson } 72713907Sdyson 72813675Sdyson ++wpipe->pipe_busy; 72913913Sdyson orig_resid = uio->uio_resid; 73013675Sdyson while (uio->uio_resid) { 73113907Sdyson int space; 73214037Sdyson#ifndef PIPE_NODIRECT 73313907Sdyson /* 73413907Sdyson * If the transfer is large, we can gain performance if 73513907Sdyson * we do process-to-process copies directly. 73613907Sdyson */ 73713907Sdyson if ((amountpipekva < LIMITPIPEKVA) && 73813907Sdyson (uio->uio_iov->iov_len >= PIPE_MINDIRECT)) { 73913907Sdyson error = pipe_direct_write( wpipe, uio); 74013907Sdyson if (error) { 74113907Sdyson break; 74213907Sdyson } 74313907Sdyson continue; 74413907Sdyson } 74514037Sdyson#endif 74613907Sdyson 74713907Sdyson /* 74813907Sdyson * Pipe buffered writes cannot be coincidental with 74913907Sdyson * direct writes. We wait until the currently executing 75013907Sdyson * direct write is completed before we start filling the 75113907Sdyson * pipe buffer. 75213907Sdyson */ 75313907Sdyson retrywrite: 75413907Sdyson while (wpipe->pipe_state & PIPE_DIRECTW) { 75513992Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 75613992Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 75713992Sdyson wakeup(wpipe); 75813992Sdyson } 75913907Sdyson error = tsleep(wpipe, 76013907Sdyson PRIBIO|PCATCH, "pipbww", 0); 76113907Sdyson if (error) 76213907Sdyson break; 76313907Sdyson } 76413907Sdyson 76513907Sdyson space = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt; 76614644Sdyson 76714644Sdyson /* Writes of size <= PIPE_BUF must be atomic. */ 76814644Sdyson /* XXX perhaps they need to be contiguous to be atomic? */ 76913913Sdyson if ((space < uio->uio_resid) && (orig_resid <= PIPE_BUF)) 77013913Sdyson space = 0; 77113907Sdyson 77213913Sdyson if (space > 0) { 77313675Sdyson int size = wpipe->pipe_buffer.size - wpipe->pipe_buffer.in; 77413675Sdyson if (size > space) 77513675Sdyson size = space; 77613675Sdyson if (size > uio->uio_resid) 77713675Sdyson size = uio->uio_resid; 77813907Sdyson if ((error = pipelock(wpipe,1)) == 0) { 77913907Sdyson /* 78013907Sdyson * It is possible for a direct write to 78113907Sdyson * slip in on us... handle it here... 78213907Sdyson */ 78313907Sdyson if (wpipe->pipe_state & PIPE_DIRECTW) { 78413907Sdyson pipeunlock(wpipe); 78513907Sdyson goto retrywrite; 78613907Sdyson } 78713675Sdyson error = uiomove( &wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in], 78813675Sdyson size, uio); 78913675Sdyson pipeunlock(wpipe); 79013675Sdyson } 79113675Sdyson if (error) 79213675Sdyson break; 79313675Sdyson 79413675Sdyson wpipe->pipe_buffer.in += size; 79513675Sdyson if (wpipe->pipe_buffer.in >= wpipe->pipe_buffer.size) 79613675Sdyson wpipe->pipe_buffer.in = 0; 79713675Sdyson 79813675Sdyson wpipe->pipe_buffer.cnt += size; 79913675Sdyson } else { 80013675Sdyson /* 80113675Sdyson * If the "read-side" has been blocked, wake it up now. 80213675Sdyson */ 80313675Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 80413675Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 80513675Sdyson wakeup(wpipe); 80613675Sdyson } 80714037Sdyson 80813675Sdyson /* 80913675Sdyson * don't block on non-blocking I/O 81013675Sdyson */ 81113907Sdyson if (nbio) { 81213907Sdyson error = EAGAIN; 81313675Sdyson break; 81413675Sdyson } 81513907Sdyson 81614037Sdyson /* 81714037Sdyson * We have no more space and have something to offer, 81814037Sdyson * wake up selects. 81914037Sdyson */ 82014037Sdyson pipeselwakeup(wpipe); 82114037Sdyson 82213675Sdyson wpipe->pipe_state |= PIPE_WANTW; 82313776Sdyson if (error = tsleep(wpipe, (PRIBIO+1)|PCATCH, "pipewr", 0)) { 82413675Sdyson break; 82513675Sdyson } 82613675Sdyson /* 82713675Sdyson * If read side wants to go away, we just issue a signal 82813675Sdyson * to ourselves. 82913675Sdyson */ 83013675Sdyson if (wpipe->pipe_state & PIPE_EOF) { 83113774Sdyson error = EPIPE; 83213907Sdyson break; 83313675Sdyson } 83413675Sdyson } 83513675Sdyson } 83613675Sdyson 83714644Sdyson --wpipe->pipe_busy; 83813675Sdyson if ((wpipe->pipe_busy == 0) && 83913675Sdyson (wpipe->pipe_state & PIPE_WANT)) { 84013675Sdyson wpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTR); 84113675Sdyson wakeup(wpipe); 84213675Sdyson } else if (wpipe->pipe_buffer.cnt > 0) { 84313675Sdyson /* 84413675Sdyson * If we have put any characters in the buffer, we wake up 84513675Sdyson * the reader. 84613675Sdyson */ 84713675Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 84813675Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 84913675Sdyson wakeup(wpipe); 85013675Sdyson } 85113675Sdyson } 85213909Sdyson 85313909Sdyson /* 85413909Sdyson * Don't return EPIPE if I/O was successful 85513909Sdyson */ 85613907Sdyson if ((wpipe->pipe_buffer.cnt == 0) && 85713907Sdyson (uio->uio_resid == 0) && 85813907Sdyson (error == EPIPE)) 85913907Sdyson error = 0; 86013913Sdyson 86114802Sdyson if (error == 0) { 86213913Sdyson int s = splhigh(); 86313913Sdyson wpipe->pipe_mtime = time; 86413913Sdyson splx(s); 86513913Sdyson } 86614037Sdyson /* 86714037Sdyson * We have something to offer, 86814037Sdyson * wake up select. 86914037Sdyson */ 87014177Sdyson if (wpipe->pipe_buffer.cnt) 87114037Sdyson pipeselwakeup(wpipe); 87213907Sdyson 87313675Sdyson return error; 87413675Sdyson} 87513675Sdyson 87613907Sdyson/* ARGSUSED */ 87713907Sdysonstatic int 87813907Sdysonpipe_write(fp, uio, cred) 87913907Sdyson struct file *fp; 88013907Sdyson struct uio *uio; 88113907Sdyson struct ucred *cred; 88213907Sdyson{ 88313907Sdyson struct pipe *rpipe = (struct pipe *) fp->f_data; 88413907Sdyson struct pipe *wpipe = rpipe->pipe_peer; 88513907Sdyson return pipewrite(wpipe, uio, (rpipe->pipe_state & PIPE_NBIO)?1:0); 88613907Sdyson} 88713907Sdyson 88813675Sdyson/* 88913675Sdyson * we implement a very minimal set of ioctls for compatibility with sockets. 89013675Sdyson */ 89113675Sdysonint 89213675Sdysonpipe_ioctl(fp, cmd, data, p) 89313675Sdyson struct file *fp; 89413675Sdyson int cmd; 89513675Sdyson register caddr_t data; 89613675Sdyson struct proc *p; 89713675Sdyson{ 89813675Sdyson register struct pipe *mpipe = (struct pipe *)fp->f_data; 89913675Sdyson 90013675Sdyson switch (cmd) { 90113675Sdyson 90213675Sdyson case FIONBIO: 90313675Sdyson if (*(int *)data) 90413675Sdyson mpipe->pipe_state |= PIPE_NBIO; 90513675Sdyson else 90613675Sdyson mpipe->pipe_state &= ~PIPE_NBIO; 90713675Sdyson return (0); 90813675Sdyson 90913675Sdyson case FIOASYNC: 91013675Sdyson if (*(int *)data) { 91113675Sdyson mpipe->pipe_state |= PIPE_ASYNC; 91213675Sdyson } else { 91313675Sdyson mpipe->pipe_state &= ~PIPE_ASYNC; 91413675Sdyson } 91513675Sdyson return (0); 91613675Sdyson 91713675Sdyson case FIONREAD: 91814037Sdyson if (mpipe->pipe_state & PIPE_DIRECTW) 91914037Sdyson *(int *)data = mpipe->pipe_map.cnt; 92014037Sdyson else 92114037Sdyson *(int *)data = mpipe->pipe_buffer.cnt; 92213675Sdyson return (0); 92313675Sdyson 92413675Sdyson case SIOCSPGRP: 92513675Sdyson mpipe->pipe_pgid = *(int *)data; 92613675Sdyson return (0); 92713675Sdyson 92813675Sdyson case SIOCGPGRP: 92913675Sdyson *(int *)data = mpipe->pipe_pgid; 93013675Sdyson return (0); 93113675Sdyson 93213675Sdyson } 93313675Sdyson return ENOSYS; 93413675Sdyson} 93513675Sdyson 93613675Sdysonint 93713675Sdysonpipe_select(fp, which, p) 93813675Sdyson struct file *fp; 93913675Sdyson int which; 94013675Sdyson struct proc *p; 94113675Sdyson{ 94213675Sdyson register struct pipe *rpipe = (struct pipe *)fp->f_data; 94313675Sdyson struct pipe *wpipe; 94413675Sdyson 94513675Sdyson wpipe = rpipe->pipe_peer; 94613675Sdyson switch (which) { 94713675Sdyson 94813675Sdyson case FREAD: 94914177Sdyson if ( (rpipe->pipe_state & PIPE_DIRECTW) || 95014177Sdyson (rpipe->pipe_buffer.cnt > 0) || 95113907Sdyson (rpipe->pipe_state & PIPE_EOF)) { 95213675Sdyson return (1); 95313675Sdyson } 95413675Sdyson selrecord(p, &rpipe->pipe_sel); 95513675Sdyson rpipe->pipe_state |= PIPE_SEL; 95613675Sdyson break; 95713675Sdyson 95813675Sdyson case FWRITE: 95913907Sdyson if ((wpipe == NULL) || 96013907Sdyson (wpipe->pipe_state & PIPE_EOF) || 96114177Sdyson (((wpipe->pipe_state & PIPE_DIRECTW) == 0) && 96214177Sdyson (wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF)) { 96313675Sdyson return (1); 96413675Sdyson } 96513675Sdyson selrecord(p, &wpipe->pipe_sel); 96613675Sdyson wpipe->pipe_state |= PIPE_SEL; 96713675Sdyson break; 96813675Sdyson 96913675Sdyson case 0: 97013907Sdyson if ((rpipe->pipe_state & PIPE_EOF) || 97113907Sdyson (wpipe == NULL) || 97213907Sdyson (wpipe->pipe_state & PIPE_EOF)) { 97313907Sdyson return (1); 97413907Sdyson } 97513907Sdyson 97613675Sdyson selrecord(p, &rpipe->pipe_sel); 97713675Sdyson rpipe->pipe_state |= PIPE_SEL; 97813675Sdyson break; 97913675Sdyson } 98013675Sdyson return (0); 98113675Sdyson} 98213675Sdyson 98313675Sdysonint 98413675Sdysonpipe_stat(pipe, ub) 98513675Sdyson register struct pipe *pipe; 98613675Sdyson register struct stat *ub; 98713675Sdyson{ 98813675Sdyson bzero((caddr_t)ub, sizeof (*ub)); 98913675Sdyson ub->st_mode = S_IFSOCK; 99013907Sdyson ub->st_blksize = pipe->pipe_buffer.size; 99113675Sdyson ub->st_size = pipe->pipe_buffer.cnt; 99213675Sdyson ub->st_blocks = (ub->st_size + ub->st_blksize - 1) / ub->st_blksize; 99313675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_atime, &ub->st_atimespec); 99413675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_mtime, &ub->st_mtimespec); 99513675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_ctime, &ub->st_ctimespec); 99613675Sdyson return 0; 99713675Sdyson} 99813675Sdyson 99913675Sdyson/* ARGSUSED */ 100013675Sdysonstatic int 100113675Sdysonpipe_close(fp, p) 100213675Sdyson struct file *fp; 100313675Sdyson struct proc *p; 100413675Sdyson{ 100513675Sdyson struct pipe *cpipe = (struct pipe *)fp->f_data; 100616322Sgpalmer 100713675Sdyson pipeclose(cpipe); 100813675Sdyson fp->f_data = NULL; 100913675Sdyson return 0; 101013675Sdyson} 101113675Sdyson 101213675Sdyson/* 101313675Sdyson * shutdown the pipe 101413675Sdyson */ 101513675Sdysonstatic void 101613675Sdysonpipeclose(cpipe) 101713675Sdyson struct pipe *cpipe; 101813675Sdyson{ 101913907Sdyson struct pipe *ppipe; 102013675Sdyson if (cpipe) { 102113907Sdyson 102214037Sdyson pipeselwakeup(cpipe); 102313907Sdyson 102413675Sdyson /* 102513675Sdyson * If the other side is blocked, wake it up saying that 102613675Sdyson * we want to close it down. 102713675Sdyson */ 102813675Sdyson while (cpipe->pipe_busy) { 102913675Sdyson wakeup(cpipe); 103013675Sdyson cpipe->pipe_state |= PIPE_WANT|PIPE_EOF; 103113675Sdyson tsleep(cpipe, PRIBIO, "pipecl", 0); 103213675Sdyson } 103313675Sdyson 103413675Sdyson /* 103513675Sdyson * Disconnect from peer 103613675Sdyson */ 103713907Sdyson if (ppipe = cpipe->pipe_peer) { 103814037Sdyson pipeselwakeup(ppipe); 103913907Sdyson 104013907Sdyson ppipe->pipe_state |= PIPE_EOF; 104113907Sdyson wakeup(ppipe); 104213907Sdyson ppipe->pipe_peer = NULL; 104313675Sdyson } 104413675Sdyson 104513675Sdyson /* 104613675Sdyson * free resources 104713675Sdyson */ 104813907Sdyson if (cpipe->pipe_buffer.buffer) { 104913907Sdyson amountpipekva -= cpipe->pipe_buffer.size; 105013907Sdyson kmem_free(kernel_map, 105113907Sdyson (vm_offset_t)cpipe->pipe_buffer.buffer, 105213907Sdyson cpipe->pipe_buffer.size); 105313907Sdyson } 105414037Sdyson#ifndef PIPE_NODIRECT 105513907Sdyson if (cpipe->pipe_map.kva) { 105613912Sdyson amountpipekva -= cpipe->pipe_buffer.size + PAGE_SIZE; 105713907Sdyson kmem_free(kernel_map, 105813907Sdyson cpipe->pipe_map.kva, 105913912Sdyson cpipe->pipe_buffer.size + PAGE_SIZE); 106013907Sdyson } 106114037Sdyson#endif 106213675Sdyson free(cpipe, M_TEMP); 106313675Sdyson } 106413675Sdyson} 106513675Sdyson#endif 1066