xref: /onnv-gate/usr/src/uts/common/fs/fifofs/fifosubr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate /*
32*0Sstevel@tonic-gate  * The routines defined in this file are supporting routines for FIFOFS
33*0Sstevel@tonic-gate  * file sytem type.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/param.h>
37*0Sstevel@tonic-gate #include <sys/systm.h>
38*0Sstevel@tonic-gate #include <sys/debug.h>
39*0Sstevel@tonic-gate #include <sys/errno.h>
40*0Sstevel@tonic-gate #include <sys/time.h>
41*0Sstevel@tonic-gate #include <sys/kmem.h>
42*0Sstevel@tonic-gate #include <sys/inline.h>
43*0Sstevel@tonic-gate #include <sys/file.h>
44*0Sstevel@tonic-gate #include <sys/proc.h>
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <sys/sysmacros.h>
47*0Sstevel@tonic-gate #include <sys/var.h>
48*0Sstevel@tonic-gate #include <sys/vfs.h>
49*0Sstevel@tonic-gate #include <sys/vnode.h>
50*0Sstevel@tonic-gate #include <sys/mode.h>
51*0Sstevel@tonic-gate #include <sys/signal.h>
52*0Sstevel@tonic-gate #include <sys/user.h>
53*0Sstevel@tonic-gate #include <sys/uio.h>
54*0Sstevel@tonic-gate #include <sys/flock.h>
55*0Sstevel@tonic-gate #include <sys/stream.h>
56*0Sstevel@tonic-gate #include <sys/fs/fifonode.h>
57*0Sstevel@tonic-gate #include <sys/strsubr.h>
58*0Sstevel@tonic-gate #include <sys/stropts.h>
59*0Sstevel@tonic-gate #include <sys/cmn_err.h>
60*0Sstevel@tonic-gate #include <fs/fs_subr.h>
61*0Sstevel@tonic-gate #include <sys/ddi.h>
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate #if FIFODEBUG
65*0Sstevel@tonic-gate int Fifo_fastmode = 1;		/* pipes/fifos will be opened in fast mode */
66*0Sstevel@tonic-gate int Fifo_verbose = 0;		/* msg when switching out of fast mode */
67*0Sstevel@tonic-gate int Fifohiwat = FIFOHIWAT;	/* Modifiable FIFO high water mark */
68*0Sstevel@tonic-gate #endif
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * This is the loadable module wrapper.
72*0Sstevel@tonic-gate  */
73*0Sstevel@tonic-gate #include <sys/modctl.h>
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate extern struct qinit fifo_strdata;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate struct vfsops *fifo_vfsops;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate static vfsdef_t vfw = {
80*0Sstevel@tonic-gate 	VFSDEF_VERSION,
81*0Sstevel@tonic-gate 	"fifofs",
82*0Sstevel@tonic-gate 	fifoinit,
83*0Sstevel@tonic-gate 	0,
84*0Sstevel@tonic-gate 	NULL
85*0Sstevel@tonic-gate };
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate /*
88*0Sstevel@tonic-gate  * Module linkage information for the kernel.
89*0Sstevel@tonic-gate  */
90*0Sstevel@tonic-gate extern struct mod_ops mod_fsops;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static struct modlfs modlfs = {
93*0Sstevel@tonic-gate 	&mod_fsops, "filesystem for fifo", &vfw
94*0Sstevel@tonic-gate };
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
97*0Sstevel@tonic-gate 	MODREV_1, (void *)&modlfs, NULL
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate int
101*0Sstevel@tonic-gate _init()
102*0Sstevel@tonic-gate {
103*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
104*0Sstevel@tonic-gate }
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate int
107*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * Define data structures within this file.
114*0Sstevel@tonic-gate  * XXX should the hash size be configurable ?
115*0Sstevel@tonic-gate  */
116*0Sstevel@tonic-gate #define	FIFOSHFT	5
117*0Sstevel@tonic-gate #define	FIFO_HASHSZ	63
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate #if ((FIFO_HASHSZ & (FIFO_HASHSZ - 1)) == 0)
120*0Sstevel@tonic-gate #define	FIFOHASH(vp) (((uintptr_t)(vp) >> FIFOSHFT) & (FIFO_HASHSZ - 1))
121*0Sstevel@tonic-gate #else
122*0Sstevel@tonic-gate #define	FIFOHASH(vp) (((uintptr_t)(vp) >> FIFOSHFT) % FIFO_HASHSZ)
123*0Sstevel@tonic-gate #endif
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate fifonode_t	*fifoalloc[FIFO_HASHSZ];
126*0Sstevel@tonic-gate dev_t		fifodev;
127*0Sstevel@tonic-gate struct vfs	*fifovfsp;
128*0Sstevel@tonic-gate int		fifofstype;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate kmutex_t ftable_lock;
131*0Sstevel@tonic-gate static kmutex_t fino_lock;
132*0Sstevel@tonic-gate struct kmem_cache *fnode_cache;
133*0Sstevel@tonic-gate struct kmem_cache *pipe_cache;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static void fifoinsert(fifonode_t *);
136*0Sstevel@tonic-gate static fifonode_t *fifofind(vnode_t *);
137*0Sstevel@tonic-gate static int fifo_connld(struct vnode **, int, cred_t *);
138*0Sstevel@tonic-gate static void fifo_fastturnoff(fifonode_t *);
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate static void fifo_reinit_vp(vnode_t *);
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate /*
143*0Sstevel@tonic-gate  * Constructor/destructor routines for fifos and pipes.
144*0Sstevel@tonic-gate  *
145*0Sstevel@tonic-gate  * In the interest of code sharing, we define a common fifodata structure
146*0Sstevel@tonic-gate  * which consists of a fifolock and one or two fnodes.  A fifo contains
147*0Sstevel@tonic-gate  * one fnode; a pipe contains two.  The fifolock is shared by the fnodes,
148*0Sstevel@tonic-gate  * each of which points to it:
149*0Sstevel@tonic-gate  *
150*0Sstevel@tonic-gate  *	--> -->	---------  --- ---
151*0Sstevel@tonic-gate  *	|   |	| lock	|   |	|
152*0Sstevel@tonic-gate  *	|   |	---------   |	|
153*0Sstevel@tonic-gate  *	|   |	|	|  fifo	|
154*0Sstevel@tonic-gate  *	|   --- | fnode	|   |	|
155*0Sstevel@tonic-gate  *	|	|	|   |  pipe
156*0Sstevel@tonic-gate  *	|	---------  ---	|
157*0Sstevel@tonic-gate  *	|	|	|	|
158*0Sstevel@tonic-gate  *	------- | fnode	|	|
159*0Sstevel@tonic-gate  *		|	|	|
160*0Sstevel@tonic-gate  *		---------      ---
161*0Sstevel@tonic-gate  *
162*0Sstevel@tonic-gate  * Since the fifolock is at the beginning of the fifodata structure,
163*0Sstevel@tonic-gate  * the fifolock address is the same as the fifodata address.  Thus,
164*0Sstevel@tonic-gate  * we can determine the fifodata address from any of its member fnodes.
165*0Sstevel@tonic-gate  * This is essential for fifo_inactive.
166*0Sstevel@tonic-gate  *
167*0Sstevel@tonic-gate  * The fnode constructor is designed to handle any fifodata struture,
168*0Sstevel@tonic-gate  * deducing the number of fnodes from the total size.  Thus, the fnode
169*0Sstevel@tonic-gate  * constructor does most of the work for the pipe constructor.
170*0Sstevel@tonic-gate  */
171*0Sstevel@tonic-gate /*ARGSUSED1*/
172*0Sstevel@tonic-gate static int
173*0Sstevel@tonic-gate fnode_constructor(void *buf, void *cdrarg, int kmflags)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	fifodata_t *fdp = buf;
176*0Sstevel@tonic-gate 	fifolock_t *flp = &fdp->fifo_lock;
177*0Sstevel@tonic-gate 	fifonode_t *fnp = &fdp->fifo_fnode[0];
178*0Sstevel@tonic-gate 	size_t size = (uintptr_t)cdrarg;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	mutex_init(&flp->flk_lock, NULL, MUTEX_DEFAULT, NULL);
181*0Sstevel@tonic-gate 	cv_init(&flp->flk_wait_cv, NULL, CV_DEFAULT, NULL);
182*0Sstevel@tonic-gate 	flp->flk_ocsync = 0;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	while ((char *)fnp < (char *)buf + size) {
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 		vnode_t *vp;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 		vp = vn_alloc(KM_SLEEP);
189*0Sstevel@tonic-gate 		fnp->fn_vnode = vp;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 		fnp->fn_lock = flp;
192*0Sstevel@tonic-gate 		fnp->fn_open = 0;
193*0Sstevel@tonic-gate 		fnp->fn_dest = fnp;
194*0Sstevel@tonic-gate 		fnp->fn_mp = NULL;
195*0Sstevel@tonic-gate 		fnp->fn_count = 0;
196*0Sstevel@tonic-gate 		fnp->fn_rsynccnt = 0;
197*0Sstevel@tonic-gate 		fnp->fn_wsynccnt = 0;
198*0Sstevel@tonic-gate 		fnp->fn_wwaitcnt = 0;
199*0Sstevel@tonic-gate 		fnp->fn_insync = 0;
200*0Sstevel@tonic-gate 		fnp->fn_pcredp = NULL;
201*0Sstevel@tonic-gate 		fnp->fn_cpid = -1;
202*0Sstevel@tonic-gate 		/*
203*0Sstevel@tonic-gate 		 * 32-bit stat(2) may fail if fn_ino isn't initialized
204*0Sstevel@tonic-gate 		 */
205*0Sstevel@tonic-gate 		fnp->fn_ino = 0;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 		cv_init(&fnp->fn_wait_cv, NULL, CV_DEFAULT, NULL);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 		vn_setops(vp, fifo_vnodeops);
210*0Sstevel@tonic-gate 		vp->v_stream = NULL;
211*0Sstevel@tonic-gate 		vp->v_type = VFIFO;
212*0Sstevel@tonic-gate 		vp->v_data = (caddr_t)fnp;
213*0Sstevel@tonic-gate 		vp->v_flag = VNOMAP | VNOSWAP;
214*0Sstevel@tonic-gate 		vn_exists(vp);
215*0Sstevel@tonic-gate 		fnp++;
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 	return (0);
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate static void
221*0Sstevel@tonic-gate fnode_destructor(void *buf, void *cdrarg)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate 	fifodata_t *fdp = buf;
224*0Sstevel@tonic-gate 	fifolock_t *flp = &fdp->fifo_lock;
225*0Sstevel@tonic-gate 	fifonode_t *fnp = &fdp->fifo_fnode[0];
226*0Sstevel@tonic-gate 	size_t size = (uintptr_t)cdrarg;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	mutex_destroy(&flp->flk_lock);
229*0Sstevel@tonic-gate 	cv_destroy(&flp->flk_wait_cv);
230*0Sstevel@tonic-gate 	ASSERT(flp->flk_ocsync == 0);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	while ((char *)fnp < (char *)buf + size) {
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		vnode_t *vp = FTOV(fnp);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 		ASSERT(fnp->fn_mp == NULL);
237*0Sstevel@tonic-gate 		ASSERT(fnp->fn_count == 0);
238*0Sstevel@tonic-gate 		ASSERT(fnp->fn_lock == flp);
239*0Sstevel@tonic-gate 		ASSERT(fnp->fn_open == 0);
240*0Sstevel@tonic-gate 		ASSERT(fnp->fn_insync == 0);
241*0Sstevel@tonic-gate 		ASSERT(fnp->fn_rsynccnt == 0 && fnp->fn_wsynccnt == 0);
242*0Sstevel@tonic-gate 		ASSERT(fnp->fn_wwaitcnt == 0);
243*0Sstevel@tonic-gate 		ASSERT(fnp->fn_pcredp == NULL);
244*0Sstevel@tonic-gate 		ASSERT(vn_matchops(vp, fifo_vnodeops));
245*0Sstevel@tonic-gate 		ASSERT(vp->v_stream == NULL);
246*0Sstevel@tonic-gate 		ASSERT(vp->v_type == VFIFO);
247*0Sstevel@tonic-gate 		ASSERT(vp->v_data == (caddr_t)fnp);
248*0Sstevel@tonic-gate 		ASSERT((vp->v_flag & (VNOMAP|VNOSWAP)) == (VNOMAP|VNOSWAP));
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		cv_destroy(&fnp->fn_wait_cv);
251*0Sstevel@tonic-gate 		vn_invalid(vp);
252*0Sstevel@tonic-gate 		vn_free(vp);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 		fnp++;
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate }
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate static int
259*0Sstevel@tonic-gate pipe_constructor(void *buf, void *cdrarg, int kmflags)
260*0Sstevel@tonic-gate {
261*0Sstevel@tonic-gate 	fifodata_t *fdp = buf;
262*0Sstevel@tonic-gate 	fifonode_t *fnp1 = &fdp->fifo_fnode[0];
263*0Sstevel@tonic-gate 	fifonode_t *fnp2 = &fdp->fifo_fnode[1];
264*0Sstevel@tonic-gate 	vnode_t *vp1;
265*0Sstevel@tonic-gate 	vnode_t *vp2;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	(void) fnode_constructor(buf, cdrarg, kmflags);
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	vp1 = FTOV(fnp1);
270*0Sstevel@tonic-gate 	vp2 = FTOV(fnp2);
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	vp1->v_vfsp	= vp2->v_vfsp		= fifovfsp;
273*0Sstevel@tonic-gate 	vp1->v_rdev	= vp2->v_rdev		= fifodev;
274*0Sstevel@tonic-gate 	fnp1->fn_realvp	= fnp2->fn_realvp	= NULL;
275*0Sstevel@tonic-gate 	fnp1->fn_dest	= fnp2;
276*0Sstevel@tonic-gate 	fnp2->fn_dest	= fnp1;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	return (0);
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate static void
282*0Sstevel@tonic-gate pipe_destructor(void *buf, void *cdrarg)
283*0Sstevel@tonic-gate {
284*0Sstevel@tonic-gate #ifdef DEBUG
285*0Sstevel@tonic-gate 	fifodata_t *fdp = buf;
286*0Sstevel@tonic-gate 	fifonode_t *fnp1 = &fdp->fifo_fnode[0];
287*0Sstevel@tonic-gate 	fifonode_t *fnp2 = &fdp->fifo_fnode[1];
288*0Sstevel@tonic-gate 	vnode_t *vp1 = FTOV(fnp1);
289*0Sstevel@tonic-gate 	vnode_t *vp2 = FTOV(fnp2);
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	ASSERT(vp1->v_vfsp == fifovfsp);
292*0Sstevel@tonic-gate 	ASSERT(vp2->v_vfsp == fifovfsp);
293*0Sstevel@tonic-gate 	ASSERT(vp1->v_rdev == fifodev);
294*0Sstevel@tonic-gate 	ASSERT(vp2->v_rdev == fifodev);
295*0Sstevel@tonic-gate #endif
296*0Sstevel@tonic-gate 	fnode_destructor(buf, cdrarg);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate /*
300*0Sstevel@tonic-gate  * Reinitialize a FIFO vnode (uses normal vnode reinit, but ensures that
301*0Sstevel@tonic-gate  * vnode type and flags are reset).
302*0Sstevel@tonic-gate  */
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate static void fifo_reinit_vp(vnode_t *vp)
305*0Sstevel@tonic-gate {
306*0Sstevel@tonic-gate 	vn_reinit(vp);
307*0Sstevel@tonic-gate 	vp->v_type = VFIFO;
308*0Sstevel@tonic-gate 	vp->v_flag = VNOMAP | VNOSWAP;
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * Save file system type/index, initialize vfs operations vector, get
313*0Sstevel@tonic-gate  * unique device number for FIFOFS and initialize the FIFOFS hash.
314*0Sstevel@tonic-gate  * Create and initialize a "generic" vfs pointer that will be placed
315*0Sstevel@tonic-gate  * in the v_vfsp field of each pipe's vnode.
316*0Sstevel@tonic-gate  */
317*0Sstevel@tonic-gate int
318*0Sstevel@tonic-gate fifoinit(int fstype, char *name)
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate 	static const fs_operation_def_t fifo_vfsops_template[] = {
321*0Sstevel@tonic-gate 		NULL, NULL
322*0Sstevel@tonic-gate 	};
323*0Sstevel@tonic-gate 	int error;
324*0Sstevel@tonic-gate 	major_t dev;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	fifofstype = fstype;
327*0Sstevel@tonic-gate 	error = vfs_setfsops(fstype, fifo_vfsops_template, &fifo_vfsops);
328*0Sstevel@tonic-gate 	if (error != 0) {
329*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "fifoinit: bad vfs ops template");
330*0Sstevel@tonic-gate 		return (error);
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	error = vn_make_ops(name, fifo_vnodeops_template, &fifo_vnodeops);
334*0Sstevel@tonic-gate 	if (error != 0) {
335*0Sstevel@tonic-gate 		(void) vfs_freevfsops_by_type(fstype);
336*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "fifoinit: bad vnode ops template");
337*0Sstevel@tonic-gate 		return (error);
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if ((dev = getudev()) == (major_t)-1) {
341*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "fifoinit: can't get unique device number");
342*0Sstevel@tonic-gate 		dev = 0;
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate 	fifodev = makedevice(dev, 0);
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	fifovfsp = kmem_zalloc(sizeof (struct vfs), KM_SLEEP);
347*0Sstevel@tonic-gate 	fifovfsp->vfs_next = NULL;
348*0Sstevel@tonic-gate 	vfs_setops(fifovfsp, fifo_vfsops);
349*0Sstevel@tonic-gate 	fifovfsp->vfs_vnodecovered = NULL;
350*0Sstevel@tonic-gate 	fifovfsp->vfs_flag = 0;
351*0Sstevel@tonic-gate 	fifovfsp->vfs_bsize = 1024;
352*0Sstevel@tonic-gate 	fifovfsp->vfs_fstype = fifofstype;
353*0Sstevel@tonic-gate 	vfs_make_fsid(&fifovfsp->vfs_fsid, fifodev, fifofstype);
354*0Sstevel@tonic-gate 	fifovfsp->vfs_data = NULL;
355*0Sstevel@tonic-gate 	fifovfsp->vfs_dev = fifodev;
356*0Sstevel@tonic-gate 	fifovfsp->vfs_bcount = 0;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	mutex_init(&ftable_lock, NULL, MUTEX_DEFAULT, NULL);
359*0Sstevel@tonic-gate 	mutex_init(&fino_lock, NULL, MUTEX_DEFAULT, NULL);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	/*
362*0Sstevel@tonic-gate 	 * vnodes are cached aligned
363*0Sstevel@tonic-gate 	 */
364*0Sstevel@tonic-gate 	fnode_cache = kmem_cache_create("fnode_cache",
365*0Sstevel@tonic-gate 		sizeof (fifodata_t) - sizeof (fifonode_t), 32,
366*0Sstevel@tonic-gate 		fnode_constructor, fnode_destructor, NULL,
367*0Sstevel@tonic-gate 		(void *)(sizeof (fifodata_t) - sizeof (fifonode_t)), NULL, 0);
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	pipe_cache = kmem_cache_create("pipe_cache", sizeof (fifodata_t), 32,
370*0Sstevel@tonic-gate 		pipe_constructor, pipe_destructor, NULL,
371*0Sstevel@tonic-gate 		(void *)(sizeof (fifodata_t)), NULL, 0);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate #if FIFODEBUG
374*0Sstevel@tonic-gate 	if (Fifohiwat < FIFOHIWAT)
375*0Sstevel@tonic-gate 		Fifohiwat = FIFOHIWAT;
376*0Sstevel@tonic-gate #endif /* FIFODEBUG */
377*0Sstevel@tonic-gate 	fifo_strdata.qi_minfo->mi_hiwat = Fifohiwat;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	return (0);
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate /*
383*0Sstevel@tonic-gate  * Provide a shadow for a vnode. If vp already has a shadow in the hash list,
384*0Sstevel@tonic-gate  * return its shadow.  Otherwise, create a vnode to shadow vp, hash the
385*0Sstevel@tonic-gate  * new vnode and return its pointer to the caller.
386*0Sstevel@tonic-gate  */
387*0Sstevel@tonic-gate vnode_t *
388*0Sstevel@tonic-gate fifovp(vnode_t *vp, cred_t *crp)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	fifonode_t *fnp;
391*0Sstevel@tonic-gate 	fifodata_t *fdp;
392*0Sstevel@tonic-gate 	vnode_t *newvp;
393*0Sstevel@tonic-gate 	struct vattr va;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	ASSERT(vp != NULL);
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	fdp = kmem_cache_alloc(fnode_cache, KM_SLEEP);
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	mutex_enter(&ftable_lock);
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	if ((fnp = fifofind(vp)) != NULL) {
402*0Sstevel@tonic-gate 		mutex_exit(&ftable_lock);
403*0Sstevel@tonic-gate #if DEBUG
404*0Sstevel@tonic-gate 		fdp->fifo_fnode[0].fn_wcnt = 0;
405*0Sstevel@tonic-gate 		fdp->fifo_fnode[0].fn_rcnt = 0;
406*0Sstevel@tonic-gate #endif
407*0Sstevel@tonic-gate 		kmem_cache_free(fnode_cache, fdp);
408*0Sstevel@tonic-gate 		return (FTOV(fnp));
409*0Sstevel@tonic-gate 	}
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	fdp->fifo_lock.flk_ref = 1;
412*0Sstevel@tonic-gate 	fnp = &fdp->fifo_fnode[0];
413*0Sstevel@tonic-gate 	fnp->fn_realvp	= vp;
414*0Sstevel@tonic-gate 	fnp->fn_wcnt	= 0;
415*0Sstevel@tonic-gate 	fnp->fn_rcnt	= 0;
416*0Sstevel@tonic-gate #if FIFODEBUG
417*0Sstevel@tonic-gate 	if (! Fifo_fastmode) {
418*0Sstevel@tonic-gate 		fnp->fn_flag	= 0;
419*0Sstevel@tonic-gate 	} else {
420*0Sstevel@tonic-gate 		fnp->fn_flag	= FIFOFAST;
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate #else /* FIFODEBUG */
423*0Sstevel@tonic-gate 	fnp->fn_flag	= FIFOFAST;
424*0Sstevel@tonic-gate #endif /* FIFODEBUG */
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	/*
427*0Sstevel@tonic-gate 	 * initialize the times from vp.
428*0Sstevel@tonic-gate 	 */
429*0Sstevel@tonic-gate 	va.va_mask = AT_TIMES;
430*0Sstevel@tonic-gate 	if (VOP_GETATTR(vp, &va, 0, crp) == 0) {
431*0Sstevel@tonic-gate 		fnp->fn_atime = va.va_atime.tv_sec;
432*0Sstevel@tonic-gate 		fnp->fn_mtime = va.va_mtime.tv_sec;
433*0Sstevel@tonic-gate 		fnp->fn_ctime = va.va_ctime.tv_sec;
434*0Sstevel@tonic-gate 	} else {
435*0Sstevel@tonic-gate 		fnp->fn_atime = 0;
436*0Sstevel@tonic-gate 		fnp->fn_mtime = 0;
437*0Sstevel@tonic-gate 		fnp->fn_ctime = 0;
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	VN_HOLD(vp);
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	newvp = FTOV(fnp);
443*0Sstevel@tonic-gate 	fifo_reinit_vp(newvp);
444*0Sstevel@tonic-gate 	newvp->v_vfsp = vp->v_vfsp;
445*0Sstevel@tonic-gate 	newvp->v_rdev = vp->v_rdev;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	fifoinsert(fnp);
448*0Sstevel@tonic-gate 	mutex_exit(&ftable_lock);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	return (newvp);
451*0Sstevel@tonic-gate }
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate  * Create a pipe end by...
455*0Sstevel@tonic-gate  * allocating a vnode-fifonode pair and initializing the fifonode.
456*0Sstevel@tonic-gate  */
457*0Sstevel@tonic-gate void
458*0Sstevel@tonic-gate makepipe(vnode_t **vpp1, vnode_t **vpp2)
459*0Sstevel@tonic-gate {
460*0Sstevel@tonic-gate 	fifonode_t *fnp1;
461*0Sstevel@tonic-gate 	fifonode_t *fnp2;
462*0Sstevel@tonic-gate 	vnode_t *nvp1;
463*0Sstevel@tonic-gate 	vnode_t *nvp2;
464*0Sstevel@tonic-gate 	fifodata_t *fdp;
465*0Sstevel@tonic-gate 	time_t now;
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	fdp = kmem_cache_alloc(pipe_cache, KM_SLEEP);
468*0Sstevel@tonic-gate 	fdp->fifo_lock.flk_ref = 2;
469*0Sstevel@tonic-gate 	fnp1 = &fdp->fifo_fnode[0];
470*0Sstevel@tonic-gate 	fnp2 = &fdp->fifo_fnode[1];
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	fnp1->fn_wcnt	= fnp2->fn_wcnt		= 1;
473*0Sstevel@tonic-gate 	fnp1->fn_rcnt	= fnp2->fn_rcnt		= 1;
474*0Sstevel@tonic-gate #if FIFODEBUG
475*0Sstevel@tonic-gate 	if (! Fifo_fastmode) {
476*0Sstevel@tonic-gate 		fnp1->fn_flag	= fnp2->fn_flag		= ISPIPE;
477*0Sstevel@tonic-gate 	} else {
478*0Sstevel@tonic-gate 		fnp1->fn_flag	= fnp2->fn_flag		= ISPIPE | FIFOFAST;
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate #else /* FIFODEBUG */
481*0Sstevel@tonic-gate 	fnp1->fn_flag	= fnp2->fn_flag		= ISPIPE | FIFOFAST;
482*0Sstevel@tonic-gate #endif /* FIFODEBUG */
483*0Sstevel@tonic-gate 	now = gethrestime_sec();
484*0Sstevel@tonic-gate 	fnp1->fn_atime	= fnp2->fn_atime	= now;
485*0Sstevel@tonic-gate 	fnp1->fn_mtime	= fnp2->fn_mtime	= now;
486*0Sstevel@tonic-gate 	fnp1->fn_ctime	= fnp2->fn_ctime	= now;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	*vpp1 = nvp1 = FTOV(fnp1);
489*0Sstevel@tonic-gate 	*vpp2 = nvp2 = FTOV(fnp2);
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	fifo_reinit_vp(nvp1);		/* Reinitialize vnodes for reuse... */
492*0Sstevel@tonic-gate 	fifo_reinit_vp(nvp2);
493*0Sstevel@tonic-gate 	nvp1->v_vfsp = fifovfsp; 	/* Need to re-establish VFS & device */
494*0Sstevel@tonic-gate 	nvp2->v_vfsp = fifovfsp; 	/* before we can reuse this vnode. */
495*0Sstevel@tonic-gate 	nvp1->v_rdev = fifodev;
496*0Sstevel@tonic-gate 	nvp2->v_rdev = fifodev;
497*0Sstevel@tonic-gate }
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate /*
500*0Sstevel@tonic-gate  * Attempt to establish a unique pipe id.  Only un-named pipes use this
501*0Sstevel@tonic-gate  * routine.
502*0Sstevel@tonic-gate  */
503*0Sstevel@tonic-gate ino_t
504*0Sstevel@tonic-gate fifogetid(void)
505*0Sstevel@tonic-gate {
506*0Sstevel@tonic-gate 	static ino_t fifo_ino = 0;
507*0Sstevel@tonic-gate 	ino_t fino;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	mutex_enter(&fino_lock);
510*0Sstevel@tonic-gate 	fino = fifo_ino++;
511*0Sstevel@tonic-gate 	mutex_exit(&fino_lock);
512*0Sstevel@tonic-gate 	return (fino);
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate /*
517*0Sstevel@tonic-gate  * Stream a pipe/FIFO.
518*0Sstevel@tonic-gate  * The FIFOCONNLD flag is used when CONNLD has been pushed on the stream.
519*0Sstevel@tonic-gate  * If the flag is set, a new vnode is created by calling fifo_connld().
520*0Sstevel@tonic-gate  * Connld logic was moved to fifo_connld() to speed up the open
521*0Sstevel@tonic-gate  * operation, simplify the connld/fifo interaction, and remove inherent
522*0Sstevel@tonic-gate  * race conditions between the connld module and fifos.
523*0Sstevel@tonic-gate  * This routine is single threaded for two reasons.
524*0Sstevel@tonic-gate  * 1) connld requests are synchronous; that is, they must block
525*0Sstevel@tonic-gate  *    until the server does an I_RECVFD (oh, well).  Single threading is
526*0Sstevel@tonic-gate  *    the simplest way to accomplish this.
527*0Sstevel@tonic-gate  * 2) fifo_close() must not send M_HANGUP or M_ERROR while we are
528*0Sstevel@tonic-gate  *    in stropen. Stropen() has a tendency to reset things and
529*0Sstevel@tonic-gate  *    we would like streams to remember that a hangup occurred.
530*0Sstevel@tonic-gate  */
531*0Sstevel@tonic-gate int
532*0Sstevel@tonic-gate fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
533*0Sstevel@tonic-gate {
534*0Sstevel@tonic-gate 	int error = 0;
535*0Sstevel@tonic-gate 	vnode_t *oldvp = *vpp;
536*0Sstevel@tonic-gate 	fifonode_t *fnp = VTOF(*vpp);
537*0Sstevel@tonic-gate 	dev_t pdev = 0;
538*0Sstevel@tonic-gate 	int firstopen = 0;
539*0Sstevel@tonic-gate 	fifolock_t *fn_lock;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	fn_lock = fnp->fn_lock;
542*0Sstevel@tonic-gate 	if (!lockheld)
543*0Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
544*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	/*
547*0Sstevel@tonic-gate 	 * FIFO is in the process of opening. Wait for it
548*0Sstevel@tonic-gate 	 * to complete before starting another open on it
549*0Sstevel@tonic-gate 	 * This prevents races associated with connld open
550*0Sstevel@tonic-gate 	 */
551*0Sstevel@tonic-gate 	while (fnp->fn_flag & FIFOOPEN) {
552*0Sstevel@tonic-gate 		if (!cv_wait_sig(&fnp->fn_wait_cv, &fn_lock->flk_lock)) {
553*0Sstevel@tonic-gate 			fifo_cleanup(oldvp, flag);
554*0Sstevel@tonic-gate 			if (!lockheld)
555*0Sstevel@tonic-gate 				mutex_exit(&fn_lock->flk_lock);
556*0Sstevel@tonic-gate 			return (EINTR);
557*0Sstevel@tonic-gate 		}
558*0Sstevel@tonic-gate 	}
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	/*
561*0Sstevel@tonic-gate 	 * The other end of the pipe is almost closed so
562*0Sstevel@tonic-gate 	 * reject any other open on this end of the pipe
563*0Sstevel@tonic-gate 	 * This only happens with a pipe mounted under namefs
564*0Sstevel@tonic-gate 	 */
565*0Sstevel@tonic-gate 	if ((fnp->fn_flag & (FIFOCLOSE|ISPIPE)) == (FIFOCLOSE|ISPIPE)) {
566*0Sstevel@tonic-gate 		fifo_cleanup(oldvp, flag);
567*0Sstevel@tonic-gate 		cv_broadcast(&fnp->fn_wait_cv);
568*0Sstevel@tonic-gate 		if (!lockheld)
569*0Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
570*0Sstevel@tonic-gate 		return (ENXIO);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	fnp->fn_flag |= FIFOOPEN;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	/*
576*0Sstevel@tonic-gate 	 * can't allow close to happen while we are
577*0Sstevel@tonic-gate 	 * in the middle of stropen().
578*0Sstevel@tonic-gate 	 * M_HANGUP and M_ERROR could leave the stream in a strange state
579*0Sstevel@tonic-gate 	 */
580*0Sstevel@tonic-gate 	while (fn_lock->flk_ocsync)
581*0Sstevel@tonic-gate 		cv_wait(&fn_lock->flk_wait_cv, &fn_lock->flk_lock);
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	fn_lock->flk_ocsync = 1;
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	if (fnp->fn_flag & FIFOCONNLD) {
586*0Sstevel@tonic-gate 		/*
587*0Sstevel@tonic-gate 		 * This is a reopen, so we should release the fifo lock
588*0Sstevel@tonic-gate 		 * just in case some strange module pushed on connld
589*0Sstevel@tonic-gate 		 * has some odd side effect.
590*0Sstevel@tonic-gate 		 * Note: this stropen is on the oldvp.  It will
591*0Sstevel@tonic-gate 		 * have no impact on the connld vp returned and
592*0Sstevel@tonic-gate 		 * strclose() will only be called when we release
593*0Sstevel@tonic-gate 		 * flk_ocsync
594*0Sstevel@tonic-gate 		 */
595*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
596*0Sstevel@tonic-gate 		if ((error = stropen(oldvp, &pdev, flag, crp)) != 0) {
597*0Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
598*0Sstevel@tonic-gate 			fifo_cleanup(oldvp, flag);
599*0Sstevel@tonic-gate 			fn_lock->flk_ocsync = 0;
600*0Sstevel@tonic-gate 			cv_broadcast(&fn_lock->flk_wait_cv);
601*0Sstevel@tonic-gate 			goto out;
602*0Sstevel@tonic-gate 		}
603*0Sstevel@tonic-gate 		/*
604*0Sstevel@tonic-gate 		 * streams open done, allow close on other end if
605*0Sstevel@tonic-gate 		 * required.  Do this now.. it could
606*0Sstevel@tonic-gate 		 * be a very long time before fifo_connld returns.
607*0Sstevel@tonic-gate 		 */
608*0Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
609*0Sstevel@tonic-gate 		/*
610*0Sstevel@tonic-gate 		 * we need to fake an open here so that if this
611*0Sstevel@tonic-gate 		 * end of the pipe closes, we don't loose the
612*0Sstevel@tonic-gate 		 * stream head (kind of like single threading
613*0Sstevel@tonic-gate 		 * open and close for this end of the pipe)
614*0Sstevel@tonic-gate 		 * We'll need to call fifo_close() to do clean
615*0Sstevel@tonic-gate 		 * up in case this end of the pipe was closed
616*0Sstevel@tonic-gate 		 * down while we were in fifo_connld()
617*0Sstevel@tonic-gate 		 */
618*0Sstevel@tonic-gate 		ASSERT(fnp->fn_open > 0);
619*0Sstevel@tonic-gate 		fnp->fn_open++;
620*0Sstevel@tonic-gate 		fn_lock->flk_ocsync = 0;
621*0Sstevel@tonic-gate 		cv_broadcast(&fn_lock->flk_wait_cv);
622*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
623*0Sstevel@tonic-gate 		/*
624*0Sstevel@tonic-gate 		 * Connld has been pushed onto the pipe
625*0Sstevel@tonic-gate 		 * Create new pipe on behalf of connld
626*0Sstevel@tonic-gate 		 */
627*0Sstevel@tonic-gate 		if (error = fifo_connld(vpp, flag, crp)) {
628*0Sstevel@tonic-gate 			(void) fifo_close(oldvp, flag, 1, 0, crp);
629*0Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
630*0Sstevel@tonic-gate 			goto out;
631*0Sstevel@tonic-gate 		}
632*0Sstevel@tonic-gate 		/*
633*0Sstevel@tonic-gate 		 * undo fake open.  We need to call fifo_close
634*0Sstevel@tonic-gate 		 * because some other thread could have done
635*0Sstevel@tonic-gate 		 * a close and detach of the named pipe while
636*0Sstevel@tonic-gate 		 * we were in fifo_connld(), so
637*0Sstevel@tonic-gate 		 * we want to make sure the close completes (yuk)
638*0Sstevel@tonic-gate 		 */
639*0Sstevel@tonic-gate 		(void) fifo_close(oldvp, flag, 1, 0, crp);
640*0Sstevel@tonic-gate 		/*
641*0Sstevel@tonic-gate 		 * fifo_connld has changed the vp, so we
642*0Sstevel@tonic-gate 		 * need to re-initialize locals
643*0Sstevel@tonic-gate 		 */
644*0Sstevel@tonic-gate 		fnp = VTOF(*vpp);
645*0Sstevel@tonic-gate 		fn_lock = fnp->fn_lock;
646*0Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
647*0Sstevel@tonic-gate 	} else {
648*0Sstevel@tonic-gate 		/*
649*0Sstevel@tonic-gate 		 * release lock in case there are modules pushed that
650*0Sstevel@tonic-gate 		 * could have some strange side effect
651*0Sstevel@tonic-gate 		 */
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 		/*
656*0Sstevel@tonic-gate 		 * If this is the first open of a fifo (dotwist
657*0Sstevel@tonic-gate 		 * will be non-zero) we will need to twist the queues.
658*0Sstevel@tonic-gate 		 */
659*0Sstevel@tonic-gate 		if (oldvp->v_stream == NULL)
660*0Sstevel@tonic-gate 			firstopen = 1;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 		/*
664*0Sstevel@tonic-gate 		 * normal open of pipe/fifo
665*0Sstevel@tonic-gate 		 */
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 		if ((error = stropen(oldvp, &pdev, flag, crp)) != 0) {
668*0Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
669*0Sstevel@tonic-gate 			fifo_cleanup(oldvp, flag);
670*0Sstevel@tonic-gate 			ASSERT(fnp->fn_open != 0 || oldvp->v_stream == NULL);
671*0Sstevel@tonic-gate 			fn_lock->flk_ocsync = 0;
672*0Sstevel@tonic-gate 			cv_broadcast(&fn_lock->flk_wait_cv);
673*0Sstevel@tonic-gate 			goto out;
674*0Sstevel@tonic-gate 		}
675*0Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 		/*
678*0Sstevel@tonic-gate 		 * twist the ends of the fifo together
679*0Sstevel@tonic-gate 		 */
680*0Sstevel@tonic-gate 		if (dotwist && firstopen)
681*0Sstevel@tonic-gate 			strmate(*vpp, *vpp);
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 		/*
684*0Sstevel@tonic-gate 		 * Show that this open has succeeded
685*0Sstevel@tonic-gate 		 * and allow closes or other opens to proceed
686*0Sstevel@tonic-gate 		 */
687*0Sstevel@tonic-gate 		fnp->fn_open++;
688*0Sstevel@tonic-gate 		fn_lock->flk_ocsync = 0;
689*0Sstevel@tonic-gate 		cv_broadcast(&fn_lock->flk_wait_cv);
690*0Sstevel@tonic-gate 	}
691*0Sstevel@tonic-gate out:
692*0Sstevel@tonic-gate 	fnp->fn_flag &= ~FIFOOPEN;
693*0Sstevel@tonic-gate 	if (error == 0) {
694*0Sstevel@tonic-gate 		fnp->fn_flag |= FIFOISOPEN;
695*0Sstevel@tonic-gate 		/*
696*0Sstevel@tonic-gate 		 * If this is a FIFO and has the close flag set
697*0Sstevel@tonic-gate 		 * and there are now writers, clear the close flag
698*0Sstevel@tonic-gate 		 * Note: close flag only gets set when last writer
699*0Sstevel@tonic-gate 		 * on a FIFO goes away.
700*0Sstevel@tonic-gate 		 */
701*0Sstevel@tonic-gate 		if (((fnp->fn_flag & (ISPIPE|FIFOCLOSE)) == FIFOCLOSE) &&
702*0Sstevel@tonic-gate 		    fnp->fn_wcnt > 0)
703*0Sstevel@tonic-gate 			fnp->fn_flag &= ~FIFOCLOSE;
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 	cv_broadcast(&fnp->fn_wait_cv);
706*0Sstevel@tonic-gate 	if (!lockheld)
707*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
708*0Sstevel@tonic-gate 	return (error);
709*0Sstevel@tonic-gate }
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate /*
712*0Sstevel@tonic-gate  * Clean up the state of a FIFO and/or mounted pipe in the
713*0Sstevel@tonic-gate  * event that a fifo_open() was interrupted while the
714*0Sstevel@tonic-gate  * process was blocked.
715*0Sstevel@tonic-gate  */
716*0Sstevel@tonic-gate void
717*0Sstevel@tonic-gate fifo_cleanup(vnode_t *vp, int flag)
718*0Sstevel@tonic-gate {
719*0Sstevel@tonic-gate 	fifonode_t *fnp = VTOF(vp);
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	cleanlocks(vp, curproc->p_pid, 0);
724*0Sstevel@tonic-gate 	cleanshares(vp, curproc->p_pid);
725*0Sstevel@tonic-gate 	if (flag & FREAD) {
726*0Sstevel@tonic-gate 		fnp->fn_rcnt--;
727*0Sstevel@tonic-gate 	}
728*0Sstevel@tonic-gate 	if (flag & FWRITE) {
729*0Sstevel@tonic-gate 		fnp->fn_wcnt--;
730*0Sstevel@tonic-gate 	}
731*0Sstevel@tonic-gate 	cv_broadcast(&fnp->fn_wait_cv);
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate  * Insert a fifonode-vnode pair onto the fifoalloc hash list.
737*0Sstevel@tonic-gate  */
738*0Sstevel@tonic-gate static void
739*0Sstevel@tonic-gate fifoinsert(fifonode_t *fnp)
740*0Sstevel@tonic-gate {
741*0Sstevel@tonic-gate 	int idx = FIFOHASH(fnp->fn_realvp);
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	/*
744*0Sstevel@tonic-gate 	 * We don't need to hold fn_lock since we're holding ftable_lock and
745*0Sstevel@tonic-gate 	 * this routine is only called right after we've allocated an fnode.
746*0Sstevel@tonic-gate 	 * FIFO is inserted at head of NULL terminated doubly linked list.
747*0Sstevel@tonic-gate 	 */
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftable_lock));
750*0Sstevel@tonic-gate 	fnp->fn_backp = NULL;
751*0Sstevel@tonic-gate 	fnp->fn_nextp = fifoalloc[idx];
752*0Sstevel@tonic-gate 	fifoalloc[idx] = fnp;
753*0Sstevel@tonic-gate 	if (fnp->fn_nextp)
754*0Sstevel@tonic-gate 		fnp->fn_nextp->fn_backp = fnp;
755*0Sstevel@tonic-gate }
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate /*
758*0Sstevel@tonic-gate  * Find a fifonode-vnode pair on the fifoalloc hash list.
759*0Sstevel@tonic-gate  * vp is a vnode to be shadowed. If it's on the hash list,
760*0Sstevel@tonic-gate  * it already has a shadow, therefore return its corresponding
761*0Sstevel@tonic-gate  * fifonode.
762*0Sstevel@tonic-gate  */
763*0Sstevel@tonic-gate static fifonode_t *
764*0Sstevel@tonic-gate fifofind(vnode_t *vp)
765*0Sstevel@tonic-gate {
766*0Sstevel@tonic-gate 	fifonode_t *fnode;
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftable_lock));
769*0Sstevel@tonic-gate 	for (fnode = fifoalloc[FIFOHASH(vp)]; fnode; fnode = fnode->fn_nextp) {
770*0Sstevel@tonic-gate 		if (fnode->fn_realvp == vp) {
771*0Sstevel@tonic-gate 			VN_HOLD(FTOV(fnode));
772*0Sstevel@tonic-gate 			return (fnode);
773*0Sstevel@tonic-gate 		}
774*0Sstevel@tonic-gate 	}
775*0Sstevel@tonic-gate 	return (NULL);
776*0Sstevel@tonic-gate }
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate /*
779*0Sstevel@tonic-gate  * Remove a fifonode-vnode pair from the fifoalloc hash list.
780*0Sstevel@tonic-gate  * This routine is called from the fifo_inactive() routine when a
781*0Sstevel@tonic-gate  * FIFO is being released.
782*0Sstevel@tonic-gate  * If the link to be removed is the only link, set fifoalloc to NULL.
783*0Sstevel@tonic-gate  */
784*0Sstevel@tonic-gate void
785*0Sstevel@tonic-gate fiforemove(fifonode_t *fnp)
786*0Sstevel@tonic-gate {
787*0Sstevel@tonic-gate 	int idx = FIFOHASH(fnp->fn_realvp);
788*0Sstevel@tonic-gate 	fifonode_t *fnode;
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftable_lock));
791*0Sstevel@tonic-gate 	fnode = fifoalloc[idx];
792*0Sstevel@tonic-gate 	/*
793*0Sstevel@tonic-gate 	 * fast path... only 1 FIFO in this list entry
794*0Sstevel@tonic-gate 	 */
795*0Sstevel@tonic-gate 	if (fnode != NULL && fnode == fnp &&
796*0Sstevel@tonic-gate 		!fnode->fn_nextp && !fnode->fn_backp) {
797*0Sstevel@tonic-gate 			fifoalloc[idx] = NULL;
798*0Sstevel@tonic-gate 	} else {
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 		for (;  fnode;  fnode = fnode->fn_nextp) {
801*0Sstevel@tonic-gate 			if (fnode == fnp) {
802*0Sstevel@tonic-gate 				/*
803*0Sstevel@tonic-gate 				 * if we are first entry
804*0Sstevel@tonic-gate 				 */
805*0Sstevel@tonic-gate 				if (fnp == fifoalloc[idx])
806*0Sstevel@tonic-gate 					fifoalloc[idx] = fnp->fn_nextp;
807*0Sstevel@tonic-gate 				if (fnode->fn_nextp)
808*0Sstevel@tonic-gate 					fnode->fn_nextp->fn_backp =
809*0Sstevel@tonic-gate 						fnode->fn_backp;
810*0Sstevel@tonic-gate 				if (fnode->fn_backp)
811*0Sstevel@tonic-gate 					fnode->fn_backp->fn_nextp =
812*0Sstevel@tonic-gate 						fnode->fn_nextp;
813*0Sstevel@tonic-gate 				break;
814*0Sstevel@tonic-gate 			}
815*0Sstevel@tonic-gate 		}
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate }
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate /*
820*0Sstevel@tonic-gate  * Flush all data from a fifo's message queue
821*0Sstevel@tonic-gate  */
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate void
824*0Sstevel@tonic-gate fifo_fastflush(fifonode_t *fnp)
825*0Sstevel@tonic-gate {
826*0Sstevel@tonic-gate 	mblk_t *bp;
827*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	if ((bp = fnp->fn_mp) != NULL) {
830*0Sstevel@tonic-gate 		fnp->fn_mp = NULL;
831*0Sstevel@tonic-gate 		fnp->fn_count = 0;
832*0Sstevel@tonic-gate 		freemsg(bp);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 	fifo_wakewriter(fnp->fn_dest, fnp->fn_lock);
835*0Sstevel@tonic-gate }
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate /*
838*0Sstevel@tonic-gate  * Note:  This routine is single threaded
839*0Sstevel@tonic-gate  *  Protected by FIFOOPEN flag (i.e. flk_lock is not held)
840*0Sstevel@tonic-gate  *  Upon successful completion, the original fifo is unlocked
841*0Sstevel@tonic-gate  *  and FIFOOPEN is cleared for the original vpp.
842*0Sstevel@tonic-gate  *  The new fifo returned has FIFOOPEN set.
843*0Sstevel@tonic-gate  */
844*0Sstevel@tonic-gate static int
845*0Sstevel@tonic-gate fifo_connld(struct vnode **vpp, int flag, cred_t *crp)
846*0Sstevel@tonic-gate {
847*0Sstevel@tonic-gate 	struct vnode *vp1;
848*0Sstevel@tonic-gate 	struct vnode *vp2;
849*0Sstevel@tonic-gate 	struct fifonode *oldfnp;
850*0Sstevel@tonic-gate 	struct fifonode *fn_dest;
851*0Sstevel@tonic-gate 	int error;
852*0Sstevel@tonic-gate 	struct file *filep;
853*0Sstevel@tonic-gate 	struct fifolock *fn_lock;
854*0Sstevel@tonic-gate 	cred_t *c;
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	/*
857*0Sstevel@tonic-gate 	 * Get two vnodes that will represent the pipe ends for the new pipe.
858*0Sstevel@tonic-gate 	 */
859*0Sstevel@tonic-gate 	makepipe(&vp1, &vp2);
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 	/*
862*0Sstevel@tonic-gate 	 * Allocate a file descriptor and file pointer for one of the pipe
863*0Sstevel@tonic-gate 	 * ends. The file descriptor will be used to send that pipe end to
864*0Sstevel@tonic-gate 	 * the process on the other end of this stream. Note that we get
865*0Sstevel@tonic-gate 	 * the file structure only, there is no file list entry allocated.
866*0Sstevel@tonic-gate 	 */
867*0Sstevel@tonic-gate 	if (error = falloc(vp1, FWRITE|FREAD, &filep, NULL)) {
868*0Sstevel@tonic-gate 		VN_RELE(vp1);
869*0Sstevel@tonic-gate 		VN_RELE(vp2);
870*0Sstevel@tonic-gate 		return (error);
871*0Sstevel@tonic-gate 	}
872*0Sstevel@tonic-gate 	mutex_exit(&filep->f_tlock);
873*0Sstevel@tonic-gate 	oldfnp = VTOF(*vpp);
874*0Sstevel@tonic-gate 	fn_lock = oldfnp->fn_lock;
875*0Sstevel@tonic-gate 	fn_dest = oldfnp->fn_dest;
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 	/*
878*0Sstevel@tonic-gate 	 * Create two new stream heads and attach them to the two vnodes for
879*0Sstevel@tonic-gate 	 * the new pipe.
880*0Sstevel@tonic-gate 	 */
881*0Sstevel@tonic-gate 	if ((error = fifo_stropen(&vp1, FREAD|FWRITE, filep->f_cred, 0, 0)) !=
882*0Sstevel@tonic-gate 	    0 ||
883*0Sstevel@tonic-gate 	    (error = fifo_stropen(&vp2, flag, filep->f_cred, 0, 0)) != 0) {
884*0Sstevel@tonic-gate #if DEBUG
885*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "fifo stropen failed error 0x%x",
886*0Sstevel@tonic-gate 			error);
887*0Sstevel@tonic-gate #endif
888*0Sstevel@tonic-gate 		/*
889*0Sstevel@tonic-gate 		 * this will call fifo_close and VN_RELE on vp1
890*0Sstevel@tonic-gate 		 */
891*0Sstevel@tonic-gate 		(void) closef(filep);
892*0Sstevel@tonic-gate 		VN_RELE(vp2);
893*0Sstevel@tonic-gate 		return (error);
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	/*
897*0Sstevel@tonic-gate 	 * twist the ends of the pipe together
898*0Sstevel@tonic-gate 	 */
899*0Sstevel@tonic-gate 	strmate(vp1, vp2);
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	/*
902*0Sstevel@tonic-gate 	 * Set our end to busy in open
903*0Sstevel@tonic-gate 	 * Note: Don't need lock around this because we're the only
904*0Sstevel@tonic-gate 	 * one who knows about it
905*0Sstevel@tonic-gate 	 */
906*0Sstevel@tonic-gate 	VTOF(vp2)->fn_flag |= FIFOOPEN;
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	fn_dest->fn_flag |= FIFOSEND;
911*0Sstevel@tonic-gate 	/*
912*0Sstevel@tonic-gate 	 * check to make sure neither end of pipe has gone away
913*0Sstevel@tonic-gate 	 */
914*0Sstevel@tonic-gate 	if (!(fn_dest->fn_flag & FIFOISOPEN)) {
915*0Sstevel@tonic-gate 		error = ENXIO;
916*0Sstevel@tonic-gate 		fn_dest->fn_flag &= ~FIFOSEND;
917*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
918*0Sstevel@tonic-gate 		/*
919*0Sstevel@tonic-gate 		 * this will call fifo_close and VN_RELE on vp1
920*0Sstevel@tonic-gate 		 */
921*0Sstevel@tonic-gate 		goto out;
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 	/*
926*0Sstevel@tonic-gate 	 * Tag the sender's credential on the pipe descriptor.
927*0Sstevel@tonic-gate 	 */
928*0Sstevel@tonic-gate 	crhold(VTOF(vp1)->fn_pcredp = crp);
929*0Sstevel@tonic-gate 	VTOF(vp1)->fn_cpid = curproc->p_pid;
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	/*
932*0Sstevel@tonic-gate 	 * send the file descriptor to other end of pipe
933*0Sstevel@tonic-gate 	 */
934*0Sstevel@tonic-gate 	if (error = do_sendfp((*vpp)->v_stream, filep, crp)) {
935*0Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
936*0Sstevel@tonic-gate 		fn_dest->fn_flag &= ~FIFOSEND;
937*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
938*0Sstevel@tonic-gate 		/*
939*0Sstevel@tonic-gate 		 * this will call fifo_close and VN_RELE on vp1
940*0Sstevel@tonic-gate 		 */
941*0Sstevel@tonic-gate 		goto out;
942*0Sstevel@tonic-gate 	}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
945*0Sstevel@tonic-gate 	/*
946*0Sstevel@tonic-gate 	 * Wait for other end to receive file descriptor
947*0Sstevel@tonic-gate 	 * FIFOCLOSE indicates that one or both sides of the pipe
948*0Sstevel@tonic-gate 	 * have gone away.
949*0Sstevel@tonic-gate 	 */
950*0Sstevel@tonic-gate 	while ((fn_dest->fn_flag & (FIFOCLOSE | FIFOSEND)) == FIFOSEND) {
951*0Sstevel@tonic-gate 		if (!cv_wait_sig(&oldfnp->fn_wait_cv, &fn_lock->flk_lock)) {
952*0Sstevel@tonic-gate 			error = EINTR;
953*0Sstevel@tonic-gate 			fn_dest->fn_flag &= ~FIFOSEND;
954*0Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
955*0Sstevel@tonic-gate 			goto out;
956*0Sstevel@tonic-gate 		}
957*0Sstevel@tonic-gate 	}
958*0Sstevel@tonic-gate 	/*
959*0Sstevel@tonic-gate 	 * If either end of pipe has gone away and the other end did not
960*0Sstevel@tonic-gate 	 * receive pipe, reject the connld open
961*0Sstevel@tonic-gate 	 */
962*0Sstevel@tonic-gate 	if ((fn_dest->fn_flag & FIFOSEND)) {
963*0Sstevel@tonic-gate 		error = ENXIO;
964*0Sstevel@tonic-gate 		fn_dest->fn_flag &= ~FIFOSEND;
965*0Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
966*0Sstevel@tonic-gate 		goto out;
967*0Sstevel@tonic-gate 	}
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	oldfnp->fn_flag &= ~FIFOOPEN;
970*0Sstevel@tonic-gate 	cv_broadcast(&oldfnp->fn_wait_cv);
971*0Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	VN_RELE(*vpp);
974*0Sstevel@tonic-gate 	*vpp = vp2;
975*0Sstevel@tonic-gate 	(void) closef(filep);
976*0Sstevel@tonic-gate 	return (0);
977*0Sstevel@tonic-gate out:
978*0Sstevel@tonic-gate 	c = filep->f_cred;
979*0Sstevel@tonic-gate 	crhold(c);
980*0Sstevel@tonic-gate 	(void) closef(filep);
981*0Sstevel@tonic-gate 	VTOF(vp2)->fn_flag &= ~FIFOOPEN;
982*0Sstevel@tonic-gate 	(void) fifo_close(vp2, flag, 1, (offset_t)0, c);
983*0Sstevel@tonic-gate 	crfree(c);
984*0Sstevel@tonic-gate 	VN_RELE(vp2);
985*0Sstevel@tonic-gate 	return (error);
986*0Sstevel@tonic-gate }
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate /*
989*0Sstevel@tonic-gate  * Disable fastpath mode.
990*0Sstevel@tonic-gate  */
991*0Sstevel@tonic-gate void
992*0Sstevel@tonic-gate fifo_fastoff(fifonode_t *fnp)
993*0Sstevel@tonic-gate {
994*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
995*0Sstevel@tonic-gate 	ASSERT(FTOV(fnp)->v_stream);
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	if (!(fnp->fn_flag & FIFOFAST))
999*0Sstevel@tonic-gate 		return;
1000*0Sstevel@tonic-gate #if FIFODEBUG
1001*0Sstevel@tonic-gate 	if (Fifo_verbose)
1002*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "Fifo reverting to streams mode\n");
1003*0Sstevel@tonic-gate #endif
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	fifo_fastturnoff(fnp);
1006*0Sstevel@tonic-gate 	if (fnp->fn_flag & ISPIPE) {
1007*0Sstevel@tonic-gate 		fifo_fastturnoff(fnp->fn_dest);
1008*0Sstevel@tonic-gate 	}
1009*0Sstevel@tonic-gate }
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate /*
1013*0Sstevel@tonic-gate  * flk_lock must be held while calling fifo_fastturnoff() to
1014*0Sstevel@tonic-gate  * preserve data ordering (no reads or writes allowed)
1015*0Sstevel@tonic-gate  */
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate static void
1018*0Sstevel@tonic-gate fifo_fastturnoff(fifonode_t *fnp)
1019*0Sstevel@tonic-gate {
1020*0Sstevel@tonic-gate 	fifonode_t *fn_dest = fnp->fn_dest;
1021*0Sstevel@tonic-gate 	mblk_t	*fn_mp;
1022*0Sstevel@tonic-gate 	int	fn_flag;
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
1025*0Sstevel@tonic-gate 	/*
1026*0Sstevel@tonic-gate 	 * Note: This end can't be closed if there
1027*0Sstevel@tonic-gate 	 * is stuff in fn_mp
1028*0Sstevel@tonic-gate 	 */
1029*0Sstevel@tonic-gate 	if ((fn_mp = fnp->fn_mp) != NULL) {
1030*0Sstevel@tonic-gate 		ASSERT(fnp->fn_flag & FIFOISOPEN);
1031*0Sstevel@tonic-gate 		ASSERT(FTOV(fnp)->v_stream != NULL);
1032*0Sstevel@tonic-gate 		ASSERT(FTOV(fnp)->v_stream->sd_wrq != NULL);
1033*0Sstevel@tonic-gate 		ASSERT(RD(FTOV(fnp)->v_stream->sd_wrq) != NULL);
1034*0Sstevel@tonic-gate 		ASSERT(strvp2wq(FTOV(fnp)) != NULL);
1035*0Sstevel@tonic-gate 		fnp->fn_mp = NULL;
1036*0Sstevel@tonic-gate 		fnp->fn_count = 0;
1037*0Sstevel@tonic-gate 		/*
1038*0Sstevel@tonic-gate 		 * Don't need to drop flk_lock across the put()
1039*0Sstevel@tonic-gate 		 * since we're just moving the message from the fifo
1040*0Sstevel@tonic-gate 		 * node to the STREAM head...
1041*0Sstevel@tonic-gate 		 */
1042*0Sstevel@tonic-gate 		put(RD(strvp2wq(FTOV(fnp))), fn_mp);
1043*0Sstevel@tonic-gate 	}
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	/*
1046*0Sstevel@tonic-gate 	 * Need to re-issue any pending poll requests
1047*0Sstevel@tonic-gate 	 * so that the STREAMS framework sees them
1048*0Sstevel@tonic-gate 	 * Writers would be waiting on fnp and readers on fn_dest
1049*0Sstevel@tonic-gate 	 */
1050*0Sstevel@tonic-gate 	if ((fnp->fn_flag & (FIFOISOPEN | FIFOPOLLW)) ==
1051*0Sstevel@tonic-gate 	    (FIFOISOPEN | FIFOPOLLW)) {
1052*0Sstevel@tonic-gate 		strpollwakeup(FTOV(fnp), POLLWRNORM);
1053*0Sstevel@tonic-gate 	}
1054*0Sstevel@tonic-gate 	fn_flag = fn_dest->fn_flag;
1055*0Sstevel@tonic-gate 	if ((fn_flag & FIFOISOPEN) == FIFOISOPEN) {
1056*0Sstevel@tonic-gate 		if ((fn_flag & (FIFOPOLLR | FIFOPOLLRBAND))) {
1057*0Sstevel@tonic-gate 			strpollwakeup(FTOV(fn_dest), POLLIN|POLLRDNORM);
1058*0Sstevel@tonic-gate 		}
1059*0Sstevel@tonic-gate 	}
1060*0Sstevel@tonic-gate 	/*
1061*0Sstevel@tonic-gate 	 * wake up any sleeping processes so they can notice we went
1062*0Sstevel@tonic-gate 	 * to streams mode
1063*0Sstevel@tonic-gate 	 */
1064*0Sstevel@tonic-gate 	fnp->fn_flag &= ~(FIFOFAST|FIFOWANTW|FIFOWANTR);
1065*0Sstevel@tonic-gate 	cv_broadcast(&fnp->fn_wait_cv);
1066*0Sstevel@tonic-gate }
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate /*
1069*0Sstevel@tonic-gate  * Alternative version of fifo_fastoff()
1070*0Sstevel@tonic-gate  * optimized for putmsg/getmsg.
1071*0Sstevel@tonic-gate  */
1072*0Sstevel@tonic-gate void
1073*0Sstevel@tonic-gate fifo_vfastoff(vnode_t *vp)
1074*0Sstevel@tonic-gate {
1075*0Sstevel@tonic-gate 	fifonode_t	*fnp = VTOF(vp);
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	mutex_enter(&fnp->fn_lock->flk_lock);
1078*0Sstevel@tonic-gate 	if (!(fnp->fn_flag & FIFOFAST)) {
1079*0Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock->flk_lock);
1080*0Sstevel@tonic-gate 		return;
1081*0Sstevel@tonic-gate 	}
1082*0Sstevel@tonic-gate 	fifo_fastoff(fnp);
1083*0Sstevel@tonic-gate 	mutex_exit(&fnp->fn_lock->flk_lock);
1084*0Sstevel@tonic-gate }
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate /*
1087*0Sstevel@tonic-gate  * Wake any sleeping writers, poll and send signals if necessary
1088*0Sstevel@tonic-gate  * This module is only called when we drop below the hi water mark
1089*0Sstevel@tonic-gate  * FIFOWANTW indicates that a process is sleeping in fifo_write()
1090*0Sstevel@tonic-gate  * FIFOHIWATW indicates that we have either attempted a poll or
1091*0Sstevel@tonic-gate  * non-blocking write and were over the high water mark
1092*0Sstevel@tonic-gate  * This routine assumes a low water mark of 0.
1093*0Sstevel@tonic-gate  */
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate void
1096*0Sstevel@tonic-gate fifo_wakewriter(fifonode_t *fn_dest, fifolock_t *fn_lock)
1097*0Sstevel@tonic-gate {
1098*0Sstevel@tonic-gate 	int fn_dflag = fn_dest->fn_flag;
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
1101*0Sstevel@tonic-gate 	ASSERT(fn_dest->fn_dest->fn_count < Fifohiwat);
1102*0Sstevel@tonic-gate 	if ((fn_dflag & FIFOWANTW)) {
1103*0Sstevel@tonic-gate 		cv_broadcast(&fn_dest->fn_wait_cv);
1104*0Sstevel@tonic-gate 	}
1105*0Sstevel@tonic-gate 	if ((fn_dflag & (FIFOHIWATW | FIFOISOPEN)) ==
1106*0Sstevel@tonic-gate 	    (FIFOHIWATW | FIFOISOPEN)) {
1107*0Sstevel@tonic-gate 		if (fn_dflag & FIFOPOLLW)
1108*0Sstevel@tonic-gate 			strpollwakeup(FTOV(fn_dest), POLLWRNORM);
1109*0Sstevel@tonic-gate 		if (fn_dflag & FIFOSETSIG)
1110*0Sstevel@tonic-gate 			str_sendsig(FTOV(fn_dest), S_WRNORM, 0, 0);
1111*0Sstevel@tonic-gate 	}
1112*0Sstevel@tonic-gate 	/*
1113*0Sstevel@tonic-gate 	 * FIFOPOLLW can't be set without setting FIFOHIWAT
1114*0Sstevel@tonic-gate 	 * This allows us to clear both here.
1115*0Sstevel@tonic-gate 	 */
1116*0Sstevel@tonic-gate 	fn_dest->fn_flag = fn_dflag & ~(FIFOWANTW | FIFOHIWATW | FIFOPOLLW);
1117*0Sstevel@tonic-gate }
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate /*
1120*0Sstevel@tonic-gate  * wake up any sleeping readers, poll or send signal if needed
1121*0Sstevel@tonic-gate  * FIFOWANTR indicates that a process is waiting in fifo_read() for data
1122*0Sstevel@tonic-gate  * FIFOSETSIG indicates that SIGPOLL should be sent to process
1123*0Sstevel@tonic-gate  * FIFOPOLLR indicates that a poll request for reading on the fifo was made
1124*0Sstevel@tonic-gate  */
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate void
1127*0Sstevel@tonic-gate fifo_wakereader(fifonode_t *fn_dest, fifolock_t *fn_lock)
1128*0Sstevel@tonic-gate {
1129*0Sstevel@tonic-gate 	int fn_dflag = fn_dest->fn_flag;
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
1132*0Sstevel@tonic-gate 	if (fn_dflag & FIFOWANTR) {
1133*0Sstevel@tonic-gate 		cv_broadcast(&fn_dest->fn_wait_cv);
1134*0Sstevel@tonic-gate 	}
1135*0Sstevel@tonic-gate 	if (fn_dflag & FIFOISOPEN) {
1136*0Sstevel@tonic-gate 		if (fn_dflag & FIFOPOLLR)
1137*0Sstevel@tonic-gate 			strpollwakeup(FTOV(fn_dest), POLLIN | POLLRDNORM);
1138*0Sstevel@tonic-gate 		if (fn_dflag & FIFOSETSIG)
1139*0Sstevel@tonic-gate 			str_sendsig(FTOV(fn_dest), S_INPUT | S_RDNORM, 0, 0);
1140*0Sstevel@tonic-gate 	}
1141*0Sstevel@tonic-gate 	fn_dest->fn_flag = fn_dflag & ~(FIFOWANTR | FIFOPOLLR);
1142*0Sstevel@tonic-gate }
1143