sys_pipe.c revision 13907
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.
1613675Sdyson * 4. This work was done expressly for inclusion into FreeBSD.  Other use
1713675Sdyson *    is allowed if this notation is included.
1813675Sdyson * 5. Modifications may be freely made to this file if the above conditions
1913675Sdyson *    are met.
2013675Sdyson *
2113907Sdyson * $Id: sys_pipe.c,v 1.2 1996/01/29 02:57:33 dyson Exp $
2213675Sdyson */
2313675Sdyson
2413675Sdyson#ifndef OLD_PIPE
2513675Sdyson
2613675Sdyson/*
2713675Sdyson * This file contains a high-performance replacement for the socket-based
2813675Sdyson * pipes scheme originally used in FreeBSD/4.4Lite.  It does not support
2913675Sdyson * all features of sockets, but does do everything that pipes normally
3013675Sdyson * do.
3113675Sdyson */
3213675Sdyson
3313907Sdyson/*
3413907Sdyson * This code has two modes of operation, a small write mode and a large
3513907Sdyson * write mode.  The small write mode acts like conventional pipes with
3613907Sdyson * a kernel buffer.  If the buffer is less than PIPE_MINDIRECT, then the
3713907Sdyson * "normal" pipe buffering is done.  If the buffer is between PIPE_MINDIRECT
3813907Sdyson * and PIPE_SIZE in size, it is fully mapped and wired into the kernel, and
3913907Sdyson * the receiving process can copy it directly from the pages in the sending
4013907Sdyson * process.
4113907Sdyson *
4213907Sdyson * If the sending process receives a signal, it is possible that it will
4313907Sdyson * go away, and certainly it's address space can change, because control
4413907Sdyson * is returned back to the user-mode side.  In that case, the pipe code
4513907Sdyson * arranges to copy the buffer supplied by the user process, to a pageable
4613907Sdyson * kernel buffer, and the receiving process will grab the data from the
4713907Sdyson * pageable kernel buffer.  Since signals don't happen all that often,
4813907Sdyson * the copy operation is normally eliminated.
4913907Sdyson *
5013907Sdyson * The constant PIPE_MINDIRECT is chosen to make sure that buffering will
5113907Sdyson * happen for small transfers so that the system will not spend all of
5213907Sdyson * it's time context switching.  PIPE_SIZE is constrained by the
5313907Sdyson * amount of kernel virtual memory.
5413907Sdyson */
5513907Sdyson
5613675Sdyson#include <sys/param.h>
5713675Sdyson#include <sys/systm.h>
5813675Sdyson#include <sys/proc.h>
5913675Sdyson#include <sys/file.h>
6013675Sdyson#include <sys/protosw.h>
6113675Sdyson#include <sys/stat.h>
6213675Sdyson#include <sys/filedesc.h>
6313675Sdyson#include <sys/malloc.h>
6413675Sdyson#include <sys/ioctl.h>
6513675Sdyson#include <sys/stat.h>
6613675Sdyson#include <sys/select.h>
6713675Sdyson#include <sys/signalvar.h>
6813675Sdyson#include <sys/errno.h>
6913675Sdyson#include <sys/queue.h>
7013675Sdyson#include <sys/vmmeter.h>
7113675Sdyson#include <sys/kernel.h>
7213675Sdyson#include <sys/sysproto.h>
7313675Sdyson#include <sys/pipe.h>
7413675Sdyson
7513675Sdyson#include <vm/vm.h>
7613675Sdyson#include <vm/vm_prot.h>
7713675Sdyson#include <vm/vm_param.h>
7813675Sdyson#include <vm/lock.h>
7913675Sdyson#include <vm/vm_object.h>
8013675Sdyson#include <vm/vm_kern.h>
8113675Sdyson#include <vm/vm_extern.h>
8213675Sdyson#include <vm/pmap.h>
8313675Sdyson#include <vm/vm_map.h>
8413907Sdyson#include <vm/vm_page.h>
8513675Sdyson
8613675Sdysonstatic int pipe_read __P((struct file *fp, struct uio *uio,
8713675Sdyson		struct ucred *cred));
8813675Sdysonstatic int pipe_write __P((struct file *fp, struct uio *uio,
8913675Sdyson		struct ucred *cred));
9013675Sdysonstatic int pipe_close __P((struct file *fp, struct proc *p));
9113675Sdysonstatic int pipe_select __P((struct file *fp, int which, struct proc *p));
9213675Sdysonstatic int pipe_ioctl __P((struct file *fp, int cmd, caddr_t data, struct proc *p));
9313675Sdyson
9413675Sdysonstatic struct fileops pipeops =
9513675Sdyson    { pipe_read, pipe_write, pipe_ioctl, pipe_select, pipe_close };
9613675Sdyson
9713675Sdyson/*
9813675Sdyson * Default pipe buffer size(s), this can be kind-of large now because pipe
9913675Sdyson * space is pageable.  The pipe code will try to maintain locality of
10013675Sdyson * reference for performance reasons, so small amounts of outstanding I/O
10113675Sdyson * will not wipe the cache.
10213675Sdyson */
10313907Sdyson#define MINPIPESIZE (PIPE_SIZE/3)
10413907Sdyson#define MAXPIPESIZE (2*PIPE_SIZE/3)
10513675Sdyson
10613907Sdyson/*
10713907Sdyson * Maximum amount of kva for pipes -- this is kind-of a soft limit, but
10813907Sdyson * is there so that on large systems, we don't exhaust it.
10913907Sdyson */
11013907Sdyson#define MAXPIPEKVA (8*1024*1024)
11113907Sdyson
11213907Sdyson/*
11313907Sdyson * Limit for direct transfers, we cannot, of course limit
11413907Sdyson * the amount of kva for pipes in general though.
11513907Sdyson */
11613907Sdyson#define LIMITPIPEKVA (16*1024*1024)
11713907Sdysonint amountpipekva;
11813907Sdyson
11913675Sdysonstatic void pipeclose __P((struct pipe *cpipe));
12013675Sdysonstatic void pipebufferinit __P((struct pipe *cpipe));
12113675Sdysonstatic void pipeinit __P((struct pipe *cpipe));
12213907Sdysonstatic __inline int pipelock __P((struct pipe *cpipe, int catch));
12313675Sdysonstatic __inline void pipeunlock __P((struct pipe *cpipe));
12413907Sdysonstatic int pipe_build_write_buffer __P((struct pipe *wpipe, struct uio *uio));
12513907Sdysonstatic void pipe_destroy_write_buffer __P((struct pipe *wpipe));
12613907Sdysonstatic int pipe_direct_write __P((struct pipe *wpipe, struct uio *uio));
12713907Sdysonstatic void pipe_clone_write_buffer __P((struct pipe *wpipe));
12813907Sdysonstatic void pipe_mark_pages_clean __P((struct pipe *cpipe));
12913907Sdysonstatic int pipewrite __P((struct pipe *wpipe, struct uio *uio, int nbio));
13013907Sdysonstatic void pipespace __P((struct pipe *cpipe));
13113675Sdyson
13213675Sdyson/*
13313675Sdyson * The pipe system call for the DTYPE_PIPE type of pipes
13413675Sdyson */
13513675Sdyson
13613675Sdyson/* ARGSUSED */
13713675Sdysonint
13813675Sdysonpipe(p, uap, retval)
13913675Sdyson	struct proc *p;
14013675Sdyson	struct pipe_args /* {
14113675Sdyson		int	dummy;
14213675Sdyson	} */ *uap;
14313675Sdyson	int retval[];
14413675Sdyson{
14513675Sdyson	register struct filedesc *fdp = p->p_fd;
14613675Sdyson	struct file *rf, *wf;
14713675Sdyson	struct pipe *rpipe, *wpipe;
14813675Sdyson	int fd, error;
14913675Sdyson
15013675Sdyson	rpipe = malloc( sizeof (*rpipe), M_TEMP, M_WAITOK);
15113675Sdyson	pipeinit(rpipe);
15213907Sdyson	rpipe->pipe_state |= PIPE_DIRECTOK;
15313675Sdyson	wpipe = malloc( sizeof (*wpipe), M_TEMP, M_WAITOK);
15413675Sdyson	pipeinit(wpipe);
15513907Sdyson	wpipe->pipe_state |= PIPE_DIRECTOK;
15613675Sdyson
15713675Sdyson	error = falloc(p, &rf, &fd);
15813675Sdyson	if (error)
15913675Sdyson		goto free2;
16013675Sdyson	retval[0] = fd;
16113675Sdyson	rf->f_flag = FREAD | FWRITE;
16213675Sdyson	rf->f_type = DTYPE_PIPE;
16313675Sdyson	rf->f_ops = &pipeops;
16413675Sdyson	rf->f_data = (caddr_t)rpipe;
16513675Sdyson	error = falloc(p, &wf, &fd);
16613675Sdyson	if (error)
16713675Sdyson		goto free3;
16813675Sdyson	wf->f_flag = FREAD | FWRITE;
16913675Sdyson	wf->f_type = DTYPE_PIPE;
17013675Sdyson	wf->f_ops = &pipeops;
17113675Sdyson	wf->f_data = (caddr_t)wpipe;
17213675Sdyson	retval[1] = fd;
17313675Sdyson
17413675Sdyson	rpipe->pipe_peer = wpipe;
17513675Sdyson	wpipe->pipe_peer = rpipe;
17613675Sdyson
17713675Sdyson	return (0);
17813675Sdysonfree3:
17913675Sdyson	ffree(rf);
18013675Sdyson	fdp->fd_ofiles[retval[0]] = 0;
18113675Sdysonfree2:
18213675Sdyson	(void)pipeclose(wpipe);
18313675Sdysonfree1:
18413675Sdyson	(void)pipeclose(rpipe);
18513675Sdyson	return (error);
18613675Sdyson}
18713675Sdyson
18813675Sdysonstatic void
18913907Sdysonpipespace(cpipe)
19013675Sdyson	struct pipe *cpipe;
19113675Sdyson{
19213688Sdyson	int npages, error;
19313675Sdyson
19413907Sdyson	npages = round_page(cpipe->pipe_buffer.size)/PAGE_SIZE;
19513675Sdyson	/*
19613675Sdyson	 * Create an object, I don't like the idea of paging to/from
19713675Sdyson	 * kernel_object.
19813675Sdyson	 */
19913675Sdyson	cpipe->pipe_buffer.object = vm_object_allocate(OBJT_DEFAULT, npages);
20013688Sdyson	cpipe->pipe_buffer.buffer = (caddr_t) vm_map_min(kernel_map);
20113675Sdyson
20213675Sdyson	/*
20313675Sdyson	 * Insert the object into the kernel map, and allocate kva for it.
20413675Sdyson	 * The map entry is, by default, pageable.
20513675Sdyson	 */
20613688Sdyson	error = vm_map_find(kernel_map, cpipe->pipe_buffer.object, 0,
20713907Sdyson		(vm_offset_t *) &cpipe->pipe_buffer.buffer,
20813907Sdyson		cpipe->pipe_buffer.size, 1,
20913688Sdyson		VM_PROT_ALL, VM_PROT_ALL, 0);
21013675Sdyson
21113688Sdyson	if (error != KERN_SUCCESS)
21213688Sdyson		panic("pipeinit: cannot allocate pipe -- out of kvm -- code = %d", error);
21313907Sdyson	amountpipekva += cpipe->pipe_buffer.size;
21413907Sdyson}
21513688Sdyson
21613907Sdyson/*
21713907Sdyson * initialize and allocate VM and memory for pipe
21813907Sdyson */
21913907Sdysonstatic void
22013907Sdysonpipeinit(cpipe)
22113907Sdyson	struct pipe *cpipe;
22213907Sdyson{
22313907Sdyson
22413675Sdyson	cpipe->pipe_buffer.in = 0;
22513675Sdyson	cpipe->pipe_buffer.out = 0;
22613675Sdyson	cpipe->pipe_buffer.cnt = 0;
22713907Sdyson	cpipe->pipe_buffer.size = PIPE_SIZE;
22813907Sdyson	/* Buffer kva gets dynamically allocated */
22913907Sdyson	cpipe->pipe_buffer.buffer = NULL;
23013675Sdyson
23113675Sdyson	cpipe->pipe_state = 0;
23213675Sdyson	cpipe->pipe_peer = NULL;
23313675Sdyson	cpipe->pipe_busy = 0;
23413675Sdyson	cpipe->pipe_ctime = time;
23513675Sdyson	cpipe->pipe_atime = time;
23613675Sdyson	cpipe->pipe_mtime = time;
23713675Sdyson	bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel);
23813907Sdyson
23913907Sdyson	/*
24013907Sdyson	 * pipe data structure initializations to support direct pipe I/O
24113907Sdyson	 */
24213907Sdyson	cpipe->pipe_map.cnt = 0;
24313907Sdyson	cpipe->pipe_map.kva = 0;
24413907Sdyson	cpipe->pipe_map.pos = 0;
24513907Sdyson	cpipe->pipe_map.npages = 0;
24613675Sdyson}
24713675Sdyson
24813675Sdyson
24913675Sdyson/*
25013675Sdyson * lock a pipe for I/O, blocking other access
25113675Sdyson */
25213675Sdysonstatic __inline int
25313907Sdysonpipelock(cpipe, catch)
25413675Sdyson	struct pipe *cpipe;
25513907Sdyson	int catch;
25613675Sdyson{
25713776Sdyson	int error;
25813675Sdyson	while (cpipe->pipe_state & PIPE_LOCK) {
25913675Sdyson		cpipe->pipe_state |= PIPE_LWANT;
26013907Sdyson		if (error = tsleep( &cpipe->pipe_state,
26113907Sdyson			catch?(PRIBIO|PCATCH):PRIBIO, "pipelk", 0)) {
26213776Sdyson			return error;
26313675Sdyson		}
26413675Sdyson	}
26513675Sdyson	cpipe->pipe_state |= PIPE_LOCK;
26613675Sdyson	return 0;
26713675Sdyson}
26813675Sdyson
26913675Sdyson/*
27013675Sdyson * unlock a pipe I/O lock
27113675Sdyson */
27213675Sdysonstatic __inline void
27313675Sdysonpipeunlock(cpipe)
27413675Sdyson	struct pipe *cpipe;
27513675Sdyson{
27613675Sdyson	cpipe->pipe_state &= ~PIPE_LOCK;
27713675Sdyson	if (cpipe->pipe_state & PIPE_LWANT) {
27813675Sdyson		cpipe->pipe_state &= ~PIPE_LWANT;
27913675Sdyson		wakeup(&cpipe->pipe_state);
28013675Sdyson	}
28113675Sdyson	return;
28213675Sdyson}
28313675Sdyson
28413907Sdyson#if 0
28513907Sdysonstatic void
28613907Sdysonpipe_mark_pages_clean(cpipe)
28713907Sdyson	struct pipe *cpipe;
28813907Sdyson{
28913907Sdyson	vm_size_t off;
29013907Sdyson	vm_page_t m;
29113907Sdyson
29213907Sdyson	for(off = 0; off < cpipe->pipe_buffer.object->size; off += 1) {
29313907Sdyson		m = vm_page_lookup(cpipe->pipe_buffer.object, off);
29413907Sdyson		if ((m != NULL) && (m->busy == 0) && (m->flags & PG_BUSY) == 0) {
29513907Sdyson			m->dirty = 0;
29613907Sdyson			pmap_clear_modify(VM_PAGE_TO_PHYS(m));
29713907Sdyson		}
29813907Sdyson	}
29913907Sdyson}
30013907Sdyson#endif
30113907Sdyson
30213675Sdyson/* ARGSUSED */
30313675Sdysonstatic int
30413675Sdysonpipe_read(fp, uio, cred)
30513675Sdyson	struct file *fp;
30613675Sdyson	struct uio *uio;
30713675Sdyson	struct ucred *cred;
30813675Sdyson{
30913675Sdyson
31013675Sdyson	struct pipe *rpipe = (struct pipe *) fp->f_data;
31113675Sdyson	int error = 0;
31213675Sdyson	int nread = 0;
31313907Sdyson	int size;
31413675Sdyson
31513675Sdyson	++rpipe->pipe_busy;
31613675Sdyson	while (uio->uio_resid) {
31713907Sdyson		/*
31813907Sdyson		 * normal pipe buffer receive
31913907Sdyson		 */
32013675Sdyson		if (rpipe->pipe_buffer.cnt > 0) {
32113675Sdyson			int size = rpipe->pipe_buffer.size - rpipe->pipe_buffer.out;
32213675Sdyson			if (size > rpipe->pipe_buffer.cnt)
32313675Sdyson				size = rpipe->pipe_buffer.cnt;
32413675Sdyson			if (size > uio->uio_resid)
32513675Sdyson				size = uio->uio_resid;
32613907Sdyson			if ((error = pipelock(rpipe,1)) == 0) {
32713675Sdyson				error = uiomove( &rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out],
32813675Sdyson					size, uio);
32913675Sdyson				pipeunlock(rpipe);
33013675Sdyson			}
33113675Sdyson			if (error) {
33213675Sdyson				break;
33313675Sdyson			}
33413675Sdyson			rpipe->pipe_buffer.out += size;
33513675Sdyson			if (rpipe->pipe_buffer.out >= rpipe->pipe_buffer.size)
33613675Sdyson				rpipe->pipe_buffer.out = 0;
33713675Sdyson
33813675Sdyson			rpipe->pipe_buffer.cnt -= size;
33913675Sdyson			nread += size;
34013675Sdyson			rpipe->pipe_atime = time;
34113907Sdyson		/*
34213907Sdyson		 * Direct copy, bypassing a kernel buffer.
34313907Sdyson		 */
34413907Sdyson		} else if ((size = rpipe->pipe_map.cnt) &&
34513907Sdyson			(rpipe->pipe_state & PIPE_DIRECTW)) {
34613907Sdyson			caddr_t va;
34713907Sdyson			if (size > uio->uio_resid)
34813907Sdyson				size = uio->uio_resid;
34913907Sdyson			if ((error = pipelock(rpipe,1)) == 0) {
35013907Sdyson				va = (caddr_t) rpipe->pipe_map.kva + rpipe->pipe_map.pos;
35113907Sdyson				error = uiomove(va, size, uio);
35213907Sdyson				pipeunlock(rpipe);
35313907Sdyson			}
35413907Sdyson			if (error)
35513907Sdyson				break;
35613907Sdyson			nread += size;
35713907Sdyson			rpipe->pipe_atime = time;
35813907Sdyson			rpipe->pipe_map.pos += size;
35913907Sdyson			rpipe->pipe_map.cnt -= size;
36013907Sdyson			if (rpipe->pipe_map.cnt == 0) {
36113907Sdyson				rpipe->pipe_state &= ~PIPE_DIRECTW;
36213907Sdyson				wakeup(rpipe);
36313907Sdyson			}
36413675Sdyson		} else {
36513675Sdyson			/*
36613675Sdyson			 * detect EOF condition
36713675Sdyson			 */
36813675Sdyson			if (rpipe->pipe_state & PIPE_EOF) {
36913675Sdyson				break;
37013675Sdyson			}
37113675Sdyson			/*
37213675Sdyson			 * If the "write-side" has been blocked, wake it up now.
37313675Sdyson			 */
37413675Sdyson			if (rpipe->pipe_state & PIPE_WANTW) {
37513675Sdyson				rpipe->pipe_state &= ~PIPE_WANTW;
37613675Sdyson				wakeup(rpipe);
37713675Sdyson			}
37813774Sdyson			if (nread > 0)
37913675Sdyson				break;
38013774Sdyson			if (rpipe->pipe_state & PIPE_NBIO) {
38113774Sdyson				error = EAGAIN;
38213774Sdyson				break;
38313774Sdyson			}
38413675Sdyson
38513675Sdyson			/*
38613675Sdyson			 * If there is no more to read in the pipe, reset
38713675Sdyson			 * it's pointers to the beginning.  This improves
38813675Sdyson			 * cache hit stats.
38913675Sdyson			 */
39013675Sdyson
39113907Sdyson			if ((error = pipelock(rpipe,1)) == 0) {
39213675Sdyson				if (rpipe->pipe_buffer.cnt == 0) {
39313675Sdyson					rpipe->pipe_buffer.in = 0;
39413675Sdyson					rpipe->pipe_buffer.out = 0;
39513675Sdyson				}
39613675Sdyson				pipeunlock(rpipe);
39713675Sdyson			} else {
39813675Sdyson				break;
39913675Sdyson			}
40013675Sdyson			rpipe->pipe_state |= PIPE_WANTR;
40113776Sdyson			if (error = tsleep(rpipe, PRIBIO|PCATCH, "piperd", 0)) {
40213675Sdyson				break;
40313675Sdyson			}
40413675Sdyson		}
40513675Sdyson	}
40613675Sdyson
40713675Sdyson	--rpipe->pipe_busy;
40813675Sdyson	if ((rpipe->pipe_busy == 0) && (rpipe->pipe_state & PIPE_WANT)) {
40913675Sdyson		rpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTW);
41013675Sdyson		wakeup(rpipe);
41113675Sdyson	} else if (rpipe->pipe_buffer.cnt < MINPIPESIZE) {
41213675Sdyson		/*
41313675Sdyson		 * If there is no more to read in the pipe, reset
41413675Sdyson		 * it's pointers to the beginning.  This improves
41513675Sdyson		 * cache hit stats.
41613675Sdyson		 */
41713907Sdyson		if ((error == 0) && (error = pipelock(rpipe,1)) == 0) {
41813675Sdyson			if (rpipe->pipe_buffer.cnt == 0) {
41913907Sdyson#if 0
42013907Sdyson				pipe_mark_pages_clean(rpipe);
42113907Sdyson#endif
42213675Sdyson				rpipe->pipe_buffer.in = 0;
42313675Sdyson				rpipe->pipe_buffer.out = 0;
42413675Sdyson			}
42513675Sdyson			pipeunlock(rpipe);
42613675Sdyson		}
42713675Sdyson
42813675Sdyson		/*
42913675Sdyson		 * If the "write-side" has been blocked, wake it up now.
43013675Sdyson		 */
43113675Sdyson		if (rpipe->pipe_state & PIPE_WANTW) {
43213675Sdyson			rpipe->pipe_state &= ~PIPE_WANTW;
43313675Sdyson			wakeup(rpipe);
43413675Sdyson		}
43513675Sdyson	}
43613675Sdyson	if (rpipe->pipe_state & PIPE_SEL) {
43713675Sdyson		rpipe->pipe_state &= ~PIPE_SEL;
43813675Sdyson		selwakeup(&rpipe->pipe_sel);
43913675Sdyson	}
44013675Sdyson	return error;
44113675Sdyson}
44213675Sdyson
44313907Sdyson/*
44413907Sdyson * Map the sending processes' buffer into kernel space and wire it.
44513907Sdyson * This is similar to a physical write operation.
44613907Sdyson */
44713675Sdysonstatic int
44813907Sdysonpipe_build_write_buffer(wpipe, uio)
44913907Sdyson	struct pipe *wpipe;
45013675Sdyson	struct uio *uio;
45113675Sdyson{
45213907Sdyson	int size;
45313907Sdyson	int i;
45413907Sdyson	vm_offset_t addr, endaddr, paddr;
45513907Sdyson
45613907Sdyson	size = uio->uio_iov->iov_len;
45713907Sdyson	if (size > wpipe->pipe_buffer.size)
45813907Sdyson		size = wpipe->pipe_buffer.size;
45913907Sdyson
46013907Sdyson	endaddr = round_page(uio->uio_iov->iov_base + size);
46113907Sdyson	for(i = 0, addr = trunc_page(uio->uio_iov->iov_base);
46213907Sdyson		addr < endaddr;
46313907Sdyson		addr += PAGE_SIZE, i+=1) {
46413907Sdyson
46513907Sdyson		vm_page_t m;
46613907Sdyson
46713907Sdyson		vm_fault_quick( addr, VM_PROT_READ);
46813907Sdyson		paddr = pmap_kextract(addr);
46913907Sdyson		if (!paddr) {
47013907Sdyson			int j;
47113907Sdyson			for(j=0;j<i;j++)
47213907Sdyson				vm_page_unwire(wpipe->pipe_map.ms[j]);
47313907Sdyson			return EFAULT;
47413907Sdyson		}
47513907Sdyson
47613907Sdyson		m = PHYS_TO_VM_PAGE(paddr);
47713907Sdyson		vm_page_wire(m);
47813907Sdyson		wpipe->pipe_map.ms[i] = m;
47913907Sdyson	}
48013907Sdyson
48113907Sdyson/*
48213907Sdyson * set up the control block
48313907Sdyson */
48413907Sdyson	wpipe->pipe_map.npages = i;
48513907Sdyson	wpipe->pipe_map.pos = ((vm_offset_t) uio->uio_iov->iov_base) & PAGE_MASK;
48613907Sdyson	wpipe->pipe_map.cnt = size;
48713907Sdyson
48813907Sdyson/*
48913907Sdyson * and map the buffer
49013907Sdyson */
49113907Sdyson	if (wpipe->pipe_map.kva == 0) {
49213907Sdyson		wpipe->pipe_map.kva = kmem_alloc_pageable(kernel_map,
49313907Sdyson			wpipe->pipe_buffer.size);
49413907Sdyson		amountpipekva += wpipe->pipe_buffer.size;
49513907Sdyson	}
49613907Sdyson	pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms,
49713907Sdyson		wpipe->pipe_map.npages);
49813907Sdyson
49913907Sdyson/*
50013907Sdyson * and update the uio data
50113907Sdyson */
50213907Sdyson
50313907Sdyson	uio->uio_iov->iov_len -= size;
50413907Sdyson	uio->uio_iov->iov_base += size;
50513907Sdyson	if (uio->uio_iov->iov_len == 0)
50613907Sdyson		uio->uio_iov++;
50713907Sdyson	uio->uio_resid -= size;
50813907Sdyson	uio->uio_offset += size;
50913907Sdyson	return 0;
51013907Sdyson}
51113907Sdyson
51213907Sdyson/*
51313907Sdyson * unmap and unwire the process buffer
51413907Sdyson */
51513907Sdysonstatic void
51613907Sdysonpipe_destroy_write_buffer(wpipe)
51713907Sdysonstruct pipe *wpipe;
51813907Sdyson{
51913907Sdyson	int i;
52013907Sdyson	pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);
52113907Sdyson
52213907Sdyson	if (wpipe->pipe_map.kva) {
52313907Sdyson		if (amountpipekva > MAXPIPEKVA) {
52413907Sdyson			vm_offset_t kva = wpipe->pipe_map.kva;
52513907Sdyson			wpipe->pipe_map.kva = 0;
52613907Sdyson			kmem_free(kernel_map, kva,
52713907Sdyson				wpipe->pipe_buffer.size);
52813907Sdyson			amountpipekva -= wpipe->pipe_buffer.size;
52913907Sdyson		}
53013907Sdyson	}
53113907Sdyson	for (i=0;i<wpipe->pipe_map.npages;i++)
53213907Sdyson		vm_page_unwire(wpipe->pipe_map.ms[i]);
53313907Sdyson}
53413907Sdyson
53513907Sdyson/*
53613907Sdyson * In the case of a signal, the writing process might go away.  This
53713907Sdyson * code copies the data into the circular buffer so that the source
53813907Sdyson * pages can be freed without loss of data.
53913907Sdyson */
54013907Sdysonstatic void
54113907Sdysonpipe_clone_write_buffer(wpipe)
54213907Sdysonstruct pipe *wpipe;
54313907Sdyson{
54413907Sdyson	int size;
54513907Sdyson	int pos;
54613907Sdyson
54713907Sdyson	size = wpipe->pipe_map.cnt;
54813907Sdyson	pos = wpipe->pipe_map.pos;
54913907Sdyson	bcopy((caddr_t) wpipe->pipe_map.kva+pos,
55013907Sdyson			(caddr_t) wpipe->pipe_buffer.buffer,
55113907Sdyson			size);
55213907Sdyson
55313907Sdyson	wpipe->pipe_buffer.in = size;
55413907Sdyson	wpipe->pipe_buffer.out = 0;
55513907Sdyson	wpipe->pipe_buffer.cnt = size;
55613907Sdyson	wpipe->pipe_state &= ~PIPE_DIRECTW;
55713907Sdyson
55813907Sdyson	pipe_destroy_write_buffer(wpipe);
55913907Sdyson}
56013907Sdyson
56113907Sdyson/*
56213907Sdyson * This implements the pipe buffer write mechanism.  Note that only
56313907Sdyson * a direct write OR a normal pipe write can be pending at any given time.
56413907Sdyson * If there are any characters in the pipe buffer, the direct write will
56513907Sdyson * be deferred until the receiving process grabs all of the bytes from
56613907Sdyson * the pipe buffer.  Then the direct mapping write is set-up.
56713907Sdyson */
56813907Sdysonstatic int
56913907Sdysonpipe_direct_write(wpipe, uio)
57013907Sdyson	struct pipe *wpipe;
57113907Sdyson	struct uio *uio;
57213907Sdyson{
57313907Sdyson	int error;
57413907Sdyson	while (wpipe->pipe_state & PIPE_DIRECTW) {
57513907Sdyson		error = tsleep(wpipe,
57613907Sdyson				PRIBIO|PCATCH, "pipdww", 0);
57713907Sdyson		if (error || (wpipe->pipe_state & PIPE_EOF))
57813907Sdyson			goto error1;
57913907Sdyson	}
58013907Sdyson	wpipe->pipe_map.cnt = 0;	/* transfer not ready yet */
58113907Sdyson	wpipe->pipe_state |= PIPE_DIRECTW;
58213907Sdyson	while (wpipe->pipe_buffer.cnt > 0) {
58313907Sdyson		error = tsleep(wpipe,
58413907Sdyson				PRIBIO|PCATCH, "pipdwc", 0);
58513907Sdyson		if (error || (wpipe->pipe_state & PIPE_EOF)) {
58613907Sdyson			wpipe->pipe_state &= ~PIPE_DIRECTW;
58713907Sdyson			if (error == 0)
58813907Sdyson				error = EPIPE;
58913907Sdyson			goto error1;
59013907Sdyson		}
59113907Sdyson	}
59213907Sdyson
59313907Sdyson	error = pipe_build_write_buffer(wpipe, uio);
59413907Sdyson	if (error) {
59513907Sdyson		wpipe->pipe_state &= ~PIPE_DIRECTW;
59613907Sdyson		goto error1;
59713907Sdyson	}
59813907Sdyson
59913907Sdyson	if (wpipe->pipe_state & PIPE_WANTR) {
60013907Sdyson		wpipe->pipe_state &= ~PIPE_WANTR;
60113907Sdyson		wakeup(wpipe);
60213907Sdyson	}
60313907Sdyson
60413907Sdyson	error = 0;
60513907Sdyson	while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) {
60613907Sdyson		if (wpipe->pipe_state & PIPE_EOF) {
60713907Sdyson			pipelock(wpipe, 0);
60813907Sdyson			pipe_destroy_write_buffer(wpipe);
60913907Sdyson			pipeunlock(wpipe);
61013907Sdyson			wakeup(wpipe);
61113907Sdyson			return EPIPE;
61213907Sdyson		}
61313907Sdyson		error = tsleep(wpipe, PRIBIO|PCATCH, "pipdwt", 0);
61413907Sdyson	}
61513907Sdyson
61613907Sdyson	pipelock(wpipe,0);
61713907Sdyson	if (wpipe->pipe_state & PIPE_DIRECTW) {
61813907Sdyson		/*
61913907Sdyson		 * this bit of trickery substitutes a kernel buffer for
62013907Sdyson		 * the process that might be going away.
62113907Sdyson		 */
62213907Sdyson		pipe_clone_write_buffer(wpipe);
62313907Sdyson	} else {
62413907Sdyson		pipe_destroy_write_buffer(wpipe);
62513907Sdyson	}
62613907Sdyson	pipeunlock(wpipe);
62713907Sdyson	return error;
62813907Sdyson
62913907Sdysonerror1:
63013907Sdyson	wakeup(wpipe);
63113907Sdyson	return error;
63213907Sdyson}
63313907Sdyson
63413907Sdysonstatic __inline int
63513907Sdysonpipewrite(wpipe, uio, nbio)
63613907Sdyson	struct pipe *wpipe;
63713907Sdyson	struct uio *uio;
63813907Sdyson	int nbio;
63913907Sdyson{
64013675Sdyson	int error = 0;
64113675Sdyson
64213675Sdyson	/*
64313675Sdyson	 * detect loss of pipe read side, issue SIGPIPE if lost.
64413675Sdyson	 */
64513675Sdyson	if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF)) {
64613774Sdyson		return EPIPE;
64713675Sdyson	}
64813675Sdyson
64913907Sdyson	if( wpipe->pipe_buffer.buffer == NULL) {
65013907Sdyson		if ((error = pipelock(wpipe,1)) == 0) {
65113907Sdyson			pipespace(wpipe);
65213907Sdyson			pipeunlock(wpipe);
65313907Sdyson		} else {
65413907Sdyson			return error;
65513907Sdyson		}
65613907Sdyson	}
65713907Sdyson
65813675Sdyson	++wpipe->pipe_busy;
65913675Sdyson	while (uio->uio_resid) {
66013907Sdyson		int space;
66113907Sdyson		/*
66213907Sdyson		 * If the transfer is large, we can gain performance if
66313907Sdyson		 * we do process-to-process copies directly.
66413907Sdyson		 */
66513907Sdyson		if ((amountpipekva < LIMITPIPEKVA) &&
66613907Sdyson			(uio->uio_iov->iov_len >= PIPE_MINDIRECT)) {
66713907Sdyson			error = pipe_direct_write( wpipe, uio);
66813907Sdyson			if (error) {
66913907Sdyson				break;
67013907Sdyson			}
67113907Sdyson			continue;
67213907Sdyson		}
67313907Sdyson
67413907Sdyson		/*
67513907Sdyson		 * Pipe buffered writes cannot be coincidental with
67613907Sdyson		 * direct writes.  We wait until the currently executing
67713907Sdyson		 * direct write is completed before we start filling the
67813907Sdyson		 * pipe buffer.
67913907Sdyson		 */
68013907Sdyson	retrywrite:
68113907Sdyson		while (wpipe->pipe_state & PIPE_DIRECTW) {
68213907Sdyson			error = tsleep(wpipe,
68313907Sdyson					PRIBIO|PCATCH, "pipbww", 0);
68413907Sdyson			if (error)
68513907Sdyson				break;
68613907Sdyson		}
68713907Sdyson
68813907Sdyson		space = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
68913907Sdyson
69013907Sdyson		/*
69113907Sdyson		 * We must afford contiguous writes on buffers of size
69213907Sdyson		 * PIPE_BUF or less.
69313907Sdyson		 */
69413907Sdyson		if ((space > 0) &&
69513907Sdyson			((uio->uio_resid > PIPE_BUF) || (uio->uio_resid <= space))) {
69613675Sdyson			int size = wpipe->pipe_buffer.size - wpipe->pipe_buffer.in;
69713675Sdyson			if (size > space)
69813675Sdyson				size = space;
69913675Sdyson			if (size > uio->uio_resid)
70013675Sdyson				size = uio->uio_resid;
70113907Sdyson			if ((error = pipelock(wpipe,1)) == 0) {
70213907Sdyson				/*
70313907Sdyson				 * It is possible for a direct write to
70413907Sdyson				 * slip in on us... handle it here...
70513907Sdyson				 */
70613907Sdyson				if (wpipe->pipe_state & PIPE_DIRECTW) {
70713907Sdyson					pipeunlock(wpipe);
70813907Sdyson					goto retrywrite;
70913907Sdyson				}
71013675Sdyson				error = uiomove( &wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in],
71113675Sdyson					size, uio);
71213675Sdyson				pipeunlock(wpipe);
71313675Sdyson			}
71413675Sdyson			if (error)
71513675Sdyson				break;
71613675Sdyson
71713675Sdyson			wpipe->pipe_buffer.in += size;
71813675Sdyson			if (wpipe->pipe_buffer.in >= wpipe->pipe_buffer.size)
71913675Sdyson				wpipe->pipe_buffer.in = 0;
72013675Sdyson
72113675Sdyson			wpipe->pipe_buffer.cnt += size;
72213675Sdyson			wpipe->pipe_mtime = time;
72313675Sdyson		} else {
72413675Sdyson			/*
72513675Sdyson			 * If the "read-side" has been blocked, wake it up now.
72613675Sdyson			 */
72713675Sdyson			if (wpipe->pipe_state & PIPE_WANTR) {
72813675Sdyson				wpipe->pipe_state &= ~PIPE_WANTR;
72913675Sdyson				wakeup(wpipe);
73013675Sdyson			}
73113675Sdyson			/*
73213675Sdyson			 * don't block on non-blocking I/O
73313675Sdyson			 */
73413907Sdyson			if (nbio) {
73513907Sdyson				error = EAGAIN;
73613675Sdyson				break;
73713675Sdyson			}
73813907Sdyson
73913675Sdyson			wpipe->pipe_state |= PIPE_WANTW;
74013776Sdyson			if (error = tsleep(wpipe, (PRIBIO+1)|PCATCH, "pipewr", 0)) {
74113675Sdyson				break;
74213675Sdyson			}
74313675Sdyson			/*
74413675Sdyson			 * If read side wants to go away, we just issue a signal
74513675Sdyson			 * to ourselves.
74613675Sdyson			 */
74713675Sdyson			if (wpipe->pipe_state & PIPE_EOF) {
74813774Sdyson				error = EPIPE;
74913907Sdyson				break;
75013675Sdyson			}
75113675Sdyson		}
75213675Sdyson	}
75313675Sdyson
75413675Sdyson	if ((wpipe->pipe_busy == 0) &&
75513675Sdyson		(wpipe->pipe_state & PIPE_WANT)) {
75613675Sdyson		wpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTR);
75713675Sdyson		wakeup(wpipe);
75813675Sdyson	} else if (wpipe->pipe_buffer.cnt > 0) {
75913675Sdyson		/*
76013675Sdyson		 * If we have put any characters in the buffer, we wake up
76113675Sdyson		 * the reader.
76213675Sdyson		 */
76313675Sdyson		if (wpipe->pipe_state & PIPE_WANTR) {
76413675Sdyson			wpipe->pipe_state &= ~PIPE_WANTR;
76513675Sdyson			wakeup(wpipe);
76613675Sdyson		}
76713675Sdyson	}
76813907Sdyson	if ((wpipe->pipe_buffer.cnt == 0) &&
76913907Sdyson		(uio->uio_resid == 0) &&
77013907Sdyson		(error == EPIPE))
77113907Sdyson		error = 0;
77213907Sdyson
77313675Sdyson	if (wpipe->pipe_state & PIPE_SEL) {
77413675Sdyson		wpipe->pipe_state &= ~PIPE_SEL;
77513675Sdyson		selwakeup(&wpipe->pipe_sel);
77613675Sdyson	}
77713907Sdyson
77813907Sdyson	--wpipe->pipe_busy;
77913675Sdyson	return error;
78013675Sdyson}
78113675Sdyson
78213907Sdyson/* ARGSUSED */
78313907Sdysonstatic int
78413907Sdysonpipe_write(fp, uio, cred)
78513907Sdyson	struct file *fp;
78613907Sdyson	struct uio *uio;
78713907Sdyson	struct ucred *cred;
78813907Sdyson{
78913907Sdyson	struct pipe *rpipe = (struct pipe *) fp->f_data;
79013907Sdyson	struct pipe *wpipe = rpipe->pipe_peer;
79113907Sdyson	return pipewrite(wpipe, uio, (rpipe->pipe_state & PIPE_NBIO)?1:0);
79213907Sdyson}
79313907Sdyson
79413675Sdyson/*
79513675Sdyson * we implement a very minimal set of ioctls for compatibility with sockets.
79613675Sdyson */
79713675Sdysonint
79813675Sdysonpipe_ioctl(fp, cmd, data, p)
79913675Sdyson	struct file *fp;
80013675Sdyson	int cmd;
80113675Sdyson	register caddr_t data;
80213675Sdyson	struct proc *p;
80313675Sdyson{
80413675Sdyson	register struct pipe *mpipe = (struct pipe *)fp->f_data;
80513675Sdyson
80613675Sdyson	switch (cmd) {
80713675Sdyson
80813675Sdyson	case FIONBIO:
80913675Sdyson		if (*(int *)data)
81013675Sdyson			mpipe->pipe_state |= PIPE_NBIO;
81113675Sdyson		else
81213675Sdyson			mpipe->pipe_state &= ~PIPE_NBIO;
81313675Sdyson		return (0);
81413675Sdyson
81513675Sdyson	case FIOASYNC:
81613675Sdyson		if (*(int *)data) {
81713675Sdyson			mpipe->pipe_state |= PIPE_ASYNC;
81813675Sdyson		} else {
81913675Sdyson			mpipe->pipe_state &= ~PIPE_ASYNC;
82013675Sdyson		}
82113675Sdyson		return (0);
82213675Sdyson
82313675Sdyson	case FIONREAD:
82413675Sdyson		*(int *)data = mpipe->pipe_buffer.cnt;
82513675Sdyson		return (0);
82613675Sdyson
82713675Sdyson	case SIOCSPGRP:
82813675Sdyson		mpipe->pipe_pgid = *(int *)data;
82913675Sdyson		return (0);
83013675Sdyson
83113675Sdyson	case SIOCGPGRP:
83213675Sdyson		*(int *)data = mpipe->pipe_pgid;
83313675Sdyson		return (0);
83413675Sdyson
83513675Sdyson	}
83613675Sdyson	return ENOSYS;
83713675Sdyson}
83813675Sdyson
83913675Sdysonint
84013675Sdysonpipe_select(fp, which, p)
84113675Sdyson	struct file *fp;
84213675Sdyson	int which;
84313675Sdyson	struct proc *p;
84413675Sdyson{
84513675Sdyson	register struct pipe *rpipe = (struct pipe *)fp->f_data;
84613675Sdyson	struct pipe *wpipe;
84713675Sdyson	register int s = splnet();
84813675Sdyson
84913675Sdyson	wpipe = rpipe->pipe_peer;
85013675Sdyson	switch (which) {
85113675Sdyson
85213675Sdyson	case FREAD:
85313907Sdyson		if (rpipe->pipe_buffer.cnt > 0 ||
85413907Sdyson			(rpipe->pipe_state & PIPE_EOF)) {
85513675Sdyson			splx(s);
85613675Sdyson			return (1);
85713675Sdyson		}
85813675Sdyson		selrecord(p, &rpipe->pipe_sel);
85913675Sdyson		rpipe->pipe_state |= PIPE_SEL;
86013675Sdyson		break;
86113675Sdyson
86213675Sdyson	case FWRITE:
86313907Sdyson		if ((wpipe == NULL) ||
86413907Sdyson			(wpipe->pipe_state & PIPE_EOF) ||
86513907Sdyson			((wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF)) {
86613675Sdyson			splx(s);
86713675Sdyson			return (1);
86813675Sdyson		}
86913675Sdyson		selrecord(p, &wpipe->pipe_sel);
87013675Sdyson		wpipe->pipe_state |= PIPE_SEL;
87113675Sdyson		break;
87213675Sdyson
87313675Sdyson	case 0:
87413907Sdyson		if ((rpipe->pipe_state & PIPE_EOF) ||
87513907Sdyson			(wpipe == NULL) ||
87613907Sdyson			(wpipe->pipe_state & PIPE_EOF)) {
87713907Sdyson			splx(s);
87813907Sdyson			return (1);
87913907Sdyson		}
88013907Sdyson
88113675Sdyson		selrecord(p, &rpipe->pipe_sel);
88213675Sdyson		rpipe->pipe_state |= PIPE_SEL;
88313675Sdyson		break;
88413675Sdyson	}
88513675Sdyson	splx(s);
88613675Sdyson	return (0);
88713675Sdyson}
88813675Sdyson
88913675Sdysonint
89013675Sdysonpipe_stat(pipe, ub)
89113675Sdyson	register struct pipe *pipe;
89213675Sdyson	register struct stat *ub;
89313675Sdyson{
89413675Sdyson	bzero((caddr_t)ub, sizeof (*ub));
89513675Sdyson	ub->st_mode = S_IFSOCK;
89613907Sdyson	ub->st_blksize = pipe->pipe_buffer.size;
89713675Sdyson	ub->st_size = pipe->pipe_buffer.cnt;
89813675Sdyson	ub->st_blocks = (ub->st_size + ub->st_blksize - 1) / ub->st_blksize;
89913675Sdyson	TIMEVAL_TO_TIMESPEC(&pipe->pipe_atime, &ub->st_atimespec);
90013675Sdyson	TIMEVAL_TO_TIMESPEC(&pipe->pipe_mtime, &ub->st_mtimespec);
90113675Sdyson	TIMEVAL_TO_TIMESPEC(&pipe->pipe_ctime, &ub->st_ctimespec);
90213675Sdyson	return 0;
90313675Sdyson}
90413675Sdyson
90513675Sdyson/* ARGSUSED */
90613675Sdysonstatic int
90713675Sdysonpipe_close(fp, p)
90813675Sdyson	struct file *fp;
90913675Sdyson	struct proc *p;
91013675Sdyson{
91113675Sdyson	int error = 0;
91213675Sdyson	struct pipe *cpipe = (struct pipe *)fp->f_data;
91313675Sdyson	pipeclose(cpipe);
91413675Sdyson	fp->f_data = NULL;
91513675Sdyson	return 0;
91613675Sdyson}
91713675Sdyson
91813675Sdyson/*
91913675Sdyson * shutdown the pipe
92013675Sdyson */
92113675Sdysonstatic void
92213675Sdysonpipeclose(cpipe)
92313675Sdyson	struct pipe *cpipe;
92413675Sdyson{
92513907Sdyson	struct pipe *ppipe;
92613675Sdyson	if (cpipe) {
92713907Sdyson
92813907Sdyson		if (cpipe->pipe_state & PIPE_SEL) {
92913907Sdyson			cpipe->pipe_state &= ~PIPE_SEL;
93013907Sdyson			selwakeup(&cpipe->pipe_sel);
93113907Sdyson		}
93213907Sdyson
93313675Sdyson		/*
93413675Sdyson		 * If the other side is blocked, wake it up saying that
93513675Sdyson		 * we want to close it down.
93613675Sdyson		 */
93713675Sdyson		while (cpipe->pipe_busy) {
93813675Sdyson			wakeup(cpipe);
93913675Sdyson			cpipe->pipe_state |= PIPE_WANT|PIPE_EOF;
94013675Sdyson			tsleep(cpipe, PRIBIO, "pipecl", 0);
94113675Sdyson		}
94213675Sdyson
94313675Sdyson		/*
94413675Sdyson		 * Disconnect from peer
94513675Sdyson		 */
94613907Sdyson		if (ppipe = cpipe->pipe_peer) {
94713907Sdyson			if (ppipe->pipe_state & PIPE_SEL) {
94813907Sdyson				ppipe->pipe_state &= ~PIPE_SEL;
94913907Sdyson				selwakeup(&ppipe->pipe_sel);
95013907Sdyson			}
95113907Sdyson
95213907Sdyson			ppipe->pipe_state |= PIPE_EOF;
95313907Sdyson			wakeup(ppipe);
95413907Sdyson			ppipe->pipe_peer = NULL;
95513675Sdyson		}
95613675Sdyson
95713675Sdyson		/*
95813675Sdyson		 * free resources
95913675Sdyson		 */
96013907Sdyson		if (cpipe->pipe_buffer.buffer) {
96113907Sdyson			amountpipekva -= cpipe->pipe_buffer.size;
96213907Sdyson			kmem_free(kernel_map,
96313907Sdyson				(vm_offset_t)cpipe->pipe_buffer.buffer,
96413907Sdyson				cpipe->pipe_buffer.size);
96513907Sdyson		}
96613907Sdyson		if (cpipe->pipe_map.kva) {
96713907Sdyson			amountpipekva -= cpipe->pipe_buffer.size;
96813907Sdyson			kmem_free(kernel_map,
96913907Sdyson				cpipe->pipe_map.kva,
97013907Sdyson				cpipe->pipe_buffer.size);
97113907Sdyson		}
97213675Sdyson		free(cpipe, M_TEMP);
97313675Sdyson	}
97413675Sdyson}
97513675Sdyson#endif
976