xref: /titanic_52/usr/src/uts/common/fs/fifofs/fifovnops.c (revision f3bb54f387fc03cf651e19bbee54cc88ee51bb29)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56fc927dcSgfaden  * Common Development and Distribution License (the "License").
66fc927dcSgfaden  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All rights reserved.  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26132c40dcSbpramod  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30a5eb7107SBryan Cantrill /*
31*f3bb54f3SPatrick Mooney  * Copyright 2015, Joyent, Inc.
32a5eb7107SBryan Cantrill  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * FIFOFS file system vnode operations.  This file system
367c478bd9Sstevel@tonic-gate  * type supports STREAMS-based pipes and FIFOs.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/param.h>
407c478bd9Sstevel@tonic-gate #include <sys/systm.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/cred.h>
437c478bd9Sstevel@tonic-gate #include <sys/errno.h>
447c478bd9Sstevel@tonic-gate #include <sys/time.h>
457c478bd9Sstevel@tonic-gate #include <sys/file.h>
467c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
477c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
487c478bd9Sstevel@tonic-gate #include <sys/uio.h>
497c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
507c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
51aa59c4cbSrsb #include <sys/vfs_opreg.h>
526fc927dcSgfaden #include <sys/pathname.h>
537c478bd9Sstevel@tonic-gate #include <sys/signal.h>
547c478bd9Sstevel@tonic-gate #include <sys/user.h>
557c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
567c478bd9Sstevel@tonic-gate #include <sys/stream.h>
577c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
587c478bd9Sstevel@tonic-gate #include <sys/strredir.h>
597c478bd9Sstevel@tonic-gate #include <sys/fs/fifonode.h>
607c478bd9Sstevel@tonic-gate #include <sys/fs/namenode.h>
617c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
627c478bd9Sstevel@tonic-gate #include <sys/proc.h>
637c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
647c478bd9Sstevel@tonic-gate #include <sys/debug.h>
657c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
667c478bd9Sstevel@tonic-gate #include <sys/filio.h>
677c478bd9Sstevel@tonic-gate #include <sys/termio.h>
687c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
697c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
707c478bd9Sstevel@tonic-gate #include <sys/policy.h>
716fc927dcSgfaden #include <sys/tsol/label.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Define the routines/data structures used in this file.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate static int fifo_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
777c478bd9Sstevel@tonic-gate static int fifo_write(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
78da6c28aaSamw static int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *,
79da6c28aaSamw 	caller_context_t *);
807c478bd9Sstevel@tonic-gate static int fifo_setattr(vnode_t *, vattr_t *, int, cred_t *,
817c478bd9Sstevel@tonic-gate 	caller_context_t *);
82da6c28aaSamw static int fifo_realvp(vnode_t *, vnode_t **, caller_context_t *);
83da6c28aaSamw static int fifo_access(vnode_t *, int, int, cred_t *, caller_context_t *);
849acbbeafSnn35248 static int fifo_create(struct vnode *, char *, vattr_t *, enum vcexcl,
85da6c28aaSamw     int, struct vnode **, struct cred *, int, caller_context_t *,
86da6c28aaSamw     vsecattr_t *);
87da6c28aaSamw static int fifo_fid(vnode_t *, fid_t *, caller_context_t *);
88da6c28aaSamw static int fifo_fsync(vnode_t *, int, cred_t *, caller_context_t *);
89da6c28aaSamw static int fifo_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
90da6c28aaSamw static int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
91da6c28aaSamw 	caller_context_t *);
927c478bd9Sstevel@tonic-gate static int fifo_fastioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
937c478bd9Sstevel@tonic-gate static int fifo_strioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
94da6c28aaSamw static int fifo_poll(vnode_t *, short, int, short *, pollhead_t **,
95da6c28aaSamw 	caller_context_t *);
96da6c28aaSamw static int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *,
97da6c28aaSamw 	caller_context_t *);
98da6c28aaSamw static void fifo_inactive(vnode_t *, cred_t *, caller_context_t *);
997c478bd9Sstevel@tonic-gate static int fifo_rwlock(vnode_t *, int, caller_context_t *);
1007c478bd9Sstevel@tonic-gate static void fifo_rwunlock(vnode_t *, int, caller_context_t *);
101da6c28aaSamw static int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
102da6c28aaSamw 	caller_context_t *);
103da6c28aaSamw static int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
104da6c28aaSamw 	caller_context_t *);
1057c478bd9Sstevel@tonic-gate 
10639cba716Swroche /* functions local to this file */
10739cba716Swroche static boolean_t fifo_stayfast_enter(fifonode_t *);
10839cba716Swroche static void fifo_stayfast_exit(fifonode_t *);
10939cba716Swroche 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * Define the data structures external to this file.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate extern	dev_t	fifodev;
1147c478bd9Sstevel@tonic-gate extern struct qinit fifo_stwdata;
1157c478bd9Sstevel@tonic-gate extern struct qinit fifo_strdata;
1167c478bd9Sstevel@tonic-gate extern kmutex_t ftable_lock;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate struct  streamtab fifoinfo = { &fifo_strdata, &fifo_stwdata, NULL, NULL };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate struct vnodeops *fifo_vnodeops;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate const fs_operation_def_t fifo_vnodeops_template[] = {
123aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = fifo_open },
124aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = fifo_close },
125aa59c4cbSrsb 	VOPNAME_READ,		{ .vop_read = fifo_read },
126aa59c4cbSrsb 	VOPNAME_WRITE,		{ .vop_write = fifo_write },
127aa59c4cbSrsb 	VOPNAME_IOCTL,		{ .vop_ioctl = fifo_ioctl },
128aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = fifo_getattr },
129aa59c4cbSrsb 	VOPNAME_SETATTR,	{ .vop_setattr = fifo_setattr },
130aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = fifo_access },
131aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = fifo_create },
132aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = fifo_fsync },
133aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = fifo_inactive },
134aa59c4cbSrsb 	VOPNAME_FID,		{ .vop_fid = fifo_fid },
135aa59c4cbSrsb 	VOPNAME_RWLOCK,		{ .vop_rwlock = fifo_rwlock },
136aa59c4cbSrsb 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = fifo_rwunlock },
137aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = fifo_seek },
138aa59c4cbSrsb 	VOPNAME_REALVP,		{ .vop_realvp = fifo_realvp },
139aa59c4cbSrsb 	VOPNAME_POLL,		{ .vop_poll = fifo_poll },
140aa59c4cbSrsb 	VOPNAME_PATHCONF,	{ .vop_pathconf = fifo_pathconf },
141aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
142aa59c4cbSrsb 	VOPNAME_SETSECATTR,	{ .vop_setsecattr = fifo_setsecattr },
143aa59c4cbSrsb 	VOPNAME_GETSECATTR,	{ .vop_getsecattr = fifo_getsecattr },
1447c478bd9Sstevel@tonic-gate 	NULL,			NULL
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Return the fifoinfo structure.
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate struct streamtab *
1517c478bd9Sstevel@tonic-gate fifo_getinfo()
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	return (&fifoinfo);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1576fc927dcSgfaden  * Trusted Extensions enforces a restrictive policy for
1586fc927dcSgfaden  * writing via cross-zone named pipes. A privileged global
1596fc927dcSgfaden  * zone process may expose a named pipe by loopback mounting
1606fc927dcSgfaden  * it from a lower-level zone to a higher-level zone. The
1616fc927dcSgfaden  * kernel-enforced mount policy for lofs mounts ensures
1626fc927dcSgfaden  * that such mounts are read-only in the higher-level
1636fc927dcSgfaden  * zone. But this is not sufficient to prevent writing
1646fc927dcSgfaden  * down via fifos.  This function prevents writing down
1656fc927dcSgfaden  * by comparing the zone of the process which is requesting
1666fc927dcSgfaden  * write access with the zone owning the named pipe rendezvous.
1676fc927dcSgfaden  * For write access the zone of the named pipe must equal the
1686fc927dcSgfaden  * zone of the writing process. Writing up is possible since
1696fc927dcSgfaden  * the named pipe can be opened for read by a process in a
1706fc927dcSgfaden  * higher level zone.
1716fc927dcSgfaden  *
1726fc927dcSgfaden  * An exception is made for the global zone to support trusted
1736fc927dcSgfaden  * processes which enforce their own data flow policies.
1746fc927dcSgfaden  */
1756fc927dcSgfaden static boolean_t
1766fc927dcSgfaden tsol_fifo_access(vnode_t *vp, int flag, cred_t *crp)
1776fc927dcSgfaden {
1786fc927dcSgfaden 	fifonode_t	*fnp = VTOF(vp);
1796fc927dcSgfaden 
1806fc927dcSgfaden 	if (is_system_labeled() &&
1816fc927dcSgfaden 	    (flag & FWRITE) &&
1826fc927dcSgfaden 	    (!(fnp->fn_flag & ISPIPE))) {
1836fc927dcSgfaden 		zone_t	*proc_zone;
1846fc927dcSgfaden 
1856fc927dcSgfaden 		proc_zone = crgetzone(crp);
1866fc927dcSgfaden 		if (proc_zone != global_zone) {
1876fc927dcSgfaden 			char		vpath[MAXPATHLEN];
1886fc927dcSgfaden 			zone_t		*fifo_zone;
1896fc927dcSgfaden 
1906fc927dcSgfaden 			/*
1916fc927dcSgfaden 			 * Get the pathname and use it to find
1926fc927dcSgfaden 			 * the zone of the fifo.
1936fc927dcSgfaden 			 */
1946fc927dcSgfaden 			if (vnodetopath(rootdir, vp, vpath, sizeof (vpath),
1956fc927dcSgfaden 			    kcred) == 0) {
1966fc927dcSgfaden 				fifo_zone = zone_find_by_path(vpath);
1976fc927dcSgfaden 				zone_rele(fifo_zone);
1986fc927dcSgfaden 
1996fc927dcSgfaden 				if (fifo_zone != global_zone &&
2006fc927dcSgfaden 				    fifo_zone != proc_zone) {
2016fc927dcSgfaden 					return (B_FALSE);
2026fc927dcSgfaden 				}
2036fc927dcSgfaden 			} else {
2046fc927dcSgfaden 				return (B_FALSE);
2056fc927dcSgfaden 			}
2066fc927dcSgfaden 		}
2076fc927dcSgfaden 	}
2086fc927dcSgfaden 	return (B_TRUE);
2096fc927dcSgfaden }
2106fc927dcSgfaden 
2116fc927dcSgfaden /*
2127c478bd9Sstevel@tonic-gate  * Open and stream a FIFO.
2137c478bd9Sstevel@tonic-gate  * If this is the first open of the file (FIFO is not streaming),
2147c478bd9Sstevel@tonic-gate  * initialize the fifonode and attach a stream to the vnode.
2157c478bd9Sstevel@tonic-gate  *
2167c478bd9Sstevel@tonic-gate  * Each end of a fifo must be synchronized with the other end.
2177c478bd9Sstevel@tonic-gate  * If not, the mated end may complete an open, I/O, close sequence
2187c478bd9Sstevel@tonic-gate  * before the end waiting in open ever wakes up.
2197c478bd9Sstevel@tonic-gate  * Note: namefs pipes come through this routine too.
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate int
222da6c28aaSamw fifo_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	vnode_t		*vp		= *vpp;
2257c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp		= VTOF(vp);
2267c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock	= fnp->fn_lock;
2277c478bd9Sstevel@tonic-gate 	int		error;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VFIFO);
2307c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(vp, fifo_vnodeops));
2317c478bd9Sstevel@tonic-gate 
2326fc927dcSgfaden 	if (!tsol_fifo_access(vp, flag, crp))
2336fc927dcSgfaden 		return (EACCES);
2346fc927dcSgfaden 
2357c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
2367c478bd9Sstevel@tonic-gate 	/*
2377c478bd9Sstevel@tonic-gate 	 * If we are the first reader, wake up any writers that
2387c478bd9Sstevel@tonic-gate 	 * may be waiting around.  wait for all of them to
2397c478bd9Sstevel@tonic-gate 	 * wake up before proceeding (i.e. fn_wsynccnt == 0)
2407c478bd9Sstevel@tonic-gate 	 */
2417c478bd9Sstevel@tonic-gate 	if (flag & FREAD) {
2427c478bd9Sstevel@tonic-gate 		fnp->fn_rcnt++;		/* record reader present */
2437c478bd9Sstevel@tonic-gate 		if (! (fnp->fn_flag & ISPIPE))
2447c478bd9Sstevel@tonic-gate 			fnp->fn_rsynccnt++;	/* record reader in open */
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/*
2487c478bd9Sstevel@tonic-gate 	 * If we are the first writer, wake up any readers that
2497c478bd9Sstevel@tonic-gate 	 * may be waiting around.  wait for all of them to
2507c478bd9Sstevel@tonic-gate 	 * wake up before proceeding (i.e. fn_rsynccnt == 0)
2517c478bd9Sstevel@tonic-gate 	 */
2527c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
2537c478bd9Sstevel@tonic-gate 		fnp->fn_wcnt++;		/* record writer present */
2547c478bd9Sstevel@tonic-gate 		if (! (fnp->fn_flag & ISPIPE))
2557c478bd9Sstevel@tonic-gate 			fnp->fn_wsynccnt++;	/* record writer in open */
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * fifo_stropen will take care of twisting the queues on the first
2597c478bd9Sstevel@tonic-gate 	 * open.  The 1 being passed in means twist the queues on the first
2607c478bd9Sstevel@tonic-gate 	 * open.
2617c478bd9Sstevel@tonic-gate 	 */
2627c478bd9Sstevel@tonic-gate 	error = fifo_stropen(vpp, flag, crp, 1, 1);
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * fifo_stropen() could have replaced vpp
2657c478bd9Sstevel@tonic-gate 	 * since fifo's are the only thing we need to sync up,
2667c478bd9Sstevel@tonic-gate 	 * everything else just returns;
2677c478bd9Sstevel@tonic-gate 	 * Note: don't need to hold lock since ISPIPE can't change
2687c478bd9Sstevel@tonic-gate 	 * and both old and new vp need to be pipes
2697c478bd9Sstevel@tonic-gate 	 */
2707c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&VTOF(*vpp)->fn_lock->flk_lock));
2717c478bd9Sstevel@tonic-gate 	if (fnp->fn_flag & ISPIPE) {
2727c478bd9Sstevel@tonic-gate 		ASSERT(VTOF(*vpp)->fn_flag & ISPIPE);
2737c478bd9Sstevel@tonic-gate 		ASSERT(VTOF(*vpp)->fn_rsynccnt == 0);
2747c478bd9Sstevel@tonic-gate 		ASSERT(VTOF(*vpp)->fn_rsynccnt == 0);
2757c478bd9Sstevel@tonic-gate 		/*
2767c478bd9Sstevel@tonic-gate 		 * XXX note: should probably hold locks, but
2777c478bd9Sstevel@tonic-gate 		 * These values should not be changing
2787c478bd9Sstevel@tonic-gate 		 */
2797c478bd9Sstevel@tonic-gate 		ASSERT(fnp->fn_rsynccnt == 0);
2807c478bd9Sstevel@tonic-gate 		ASSERT(fnp->fn_wsynccnt == 0);
2817c478bd9Sstevel@tonic-gate 		mutex_exit(&VTOF(*vpp)->fn_lock->flk_lock);
2827c478bd9Sstevel@tonic-gate 		return (error);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * vp can't change for FIFOS
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	ASSERT(vp == *vpp);
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * If we are opening for read (or writer)
2907c478bd9Sstevel@tonic-gate 	 *   indicate that the reader (or writer) is done with open
2917c478bd9Sstevel@tonic-gate 	 *   if there is a writer (or reader) waiting for us, wake them up
292da6c28aaSamw 	 *	and indicate that at least 1 read (or write) open has occurred
2937c478bd9Sstevel@tonic-gate 	 *	this is need in the event the read (or write) side closes
2947c478bd9Sstevel@tonic-gate 	 *	before the writer (or reader) has a chance to wake up
2957c478bd9Sstevel@tonic-gate 	 *	i.e. it sees that a reader (or writer) was once there
2967c478bd9Sstevel@tonic-gate 	 */
2977c478bd9Sstevel@tonic-gate 	if (flag & FREAD) {
2987c478bd9Sstevel@tonic-gate 		fnp->fn_rsynccnt--;	/* reader done with open */
2997c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & FIFOSYNC) {
3007c478bd9Sstevel@tonic-gate 			/*
301da6c28aaSamw 			 * This indicates that a read open has occurred
3027c478bd9Sstevel@tonic-gate 			 * Only need to set if writer is actually asleep
3037c478bd9Sstevel@tonic-gate 			 * Flag will be consumed by writer.
3047c478bd9Sstevel@tonic-gate 			 */
3057c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOROCR;
3067c478bd9Sstevel@tonic-gate 			cv_broadcast(&fnp->fn_wait_cv);
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
3107c478bd9Sstevel@tonic-gate 		fnp->fn_wsynccnt--;	/* writer done with open */
3117c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & FIFOSYNC) {
3127c478bd9Sstevel@tonic-gate 			/*
313da6c28aaSamw 			 * This indicates that a write open has occurred
3147c478bd9Sstevel@tonic-gate 			 * Only need to set if reader is actually asleep
3157c478bd9Sstevel@tonic-gate 			 * Flag will be consumed by reader.
3167c478bd9Sstevel@tonic-gate 			 */
3177c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOWOCR;
3187c478bd9Sstevel@tonic-gate 			cv_broadcast(&fnp->fn_wait_cv);
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	fnp->fn_flag &= ~FIFOSYNC;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/*
3257c478bd9Sstevel@tonic-gate 	 * errors don't wait around.. just return
3267c478bd9Sstevel@tonic-gate 	 * Note: XXX other end will wake up and continue despite error.
3277c478bd9Sstevel@tonic-gate 	 * There is no defined semantic on the correct course of option
3287c478bd9Sstevel@tonic-gate 	 * so we do what we've done in the past
3297c478bd9Sstevel@tonic-gate 	 */
3307c478bd9Sstevel@tonic-gate 	if (error != 0) {
3317c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock->flk_lock);
3327c478bd9Sstevel@tonic-gate 		goto done;
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 	ASSERT(fnp->fn_rsynccnt <= fnp->fn_rcnt);
3357c478bd9Sstevel@tonic-gate 	ASSERT(fnp->fn_wsynccnt <= fnp->fn_wcnt);
3367c478bd9Sstevel@tonic-gate 	/*
3377c478bd9Sstevel@tonic-gate 	 * FIFOWOCR (or FIFOROCR) indicates that the writer (or reader)
3387c478bd9Sstevel@tonic-gate 	 * has woken us up and is done with open (this way, if the other
3397c478bd9Sstevel@tonic-gate 	 * end has made it to close, we don't block forever in open)
3407c478bd9Sstevel@tonic-gate 	 * fn_wnct == fn_wsynccnt (or fn_rcnt == fn_rsynccnt) indicates
3417c478bd9Sstevel@tonic-gate 	 * that no writer (or reader) has yet made it through open
342bc20329dSjk115741 	 * This has the side benefit of that the first
3437c478bd9Sstevel@tonic-gate 	 * reader (or writer) will wait until the other end finishes open
3447c478bd9Sstevel@tonic-gate 	 */
3457c478bd9Sstevel@tonic-gate 	if (flag & FREAD) {
3467c478bd9Sstevel@tonic-gate 		while ((fnp->fn_flag & FIFOWOCR) == 0 &&
3477c478bd9Sstevel@tonic-gate 		    fnp->fn_wcnt == fnp->fn_wsynccnt) {
3487c478bd9Sstevel@tonic-gate 			if (flag & (FNDELAY|FNONBLOCK)) {
3497c478bd9Sstevel@tonic-gate 				mutex_exit(&fnp->fn_lock->flk_lock);
3507c478bd9Sstevel@tonic-gate 				goto done;
3517c478bd9Sstevel@tonic-gate 			}
3527c478bd9Sstevel@tonic-gate 			fnp->fn_insync++;
3537c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOSYNC;
3547c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
3557c478bd9Sstevel@tonic-gate 			    &fnp->fn_lock->flk_lock)) {
3567c478bd9Sstevel@tonic-gate 				/*
3577c478bd9Sstevel@tonic-gate 				 * Last reader to wakeup clear writer
3587c478bd9Sstevel@tonic-gate 				 * Clear both writer and reader open
359da6c28aaSamw 				 * occurred flag incase other end is O_RDWR
3607c478bd9Sstevel@tonic-gate 				 */
3617c478bd9Sstevel@tonic-gate 				if (--fnp->fn_insync == 0 &&
3627c478bd9Sstevel@tonic-gate 				    fnp->fn_flag & FIFOWOCR) {
3637c478bd9Sstevel@tonic-gate 					fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
3647c478bd9Sstevel@tonic-gate 				}
3657c478bd9Sstevel@tonic-gate 				mutex_exit(&fnp->fn_lock->flk_lock);
366da6c28aaSamw 				(void) fifo_close(*vpp, flag, 1, 0, crp, ct);
3677c478bd9Sstevel@tonic-gate 				error = EINTR;
3687c478bd9Sstevel@tonic-gate 				goto done;
3697c478bd9Sstevel@tonic-gate 			}
3707c478bd9Sstevel@tonic-gate 			/*
371da6c28aaSamw 			 * Last reader to wakeup clear writer open occurred flag
372da6c28aaSamw 			 * Clear both writer and reader open occurred flag
3737c478bd9Sstevel@tonic-gate 			 * incase other end is O_RDWR
3747c478bd9Sstevel@tonic-gate 			 */
3757c478bd9Sstevel@tonic-gate 			if (--fnp->fn_insync == 0 &&
3767c478bd9Sstevel@tonic-gate 			    fnp->fn_flag & FIFOWOCR) {
3777c478bd9Sstevel@tonic-gate 				fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
3787c478bd9Sstevel@tonic-gate 				break;
3797c478bd9Sstevel@tonic-gate 			}
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 	} else if (flag & FWRITE) {
3827c478bd9Sstevel@tonic-gate 		while ((fnp->fn_flag & FIFOROCR) == 0 &&
3837c478bd9Sstevel@tonic-gate 		    fnp->fn_rcnt == fnp->fn_rsynccnt) {
3847c478bd9Sstevel@tonic-gate 			if ((flag & (FNDELAY|FNONBLOCK)) && fnp->fn_rcnt == 0) {
3857c478bd9Sstevel@tonic-gate 				mutex_exit(&fnp->fn_lock->flk_lock);
386da6c28aaSamw 				(void) fifo_close(*vpp, flag, 1, 0, crp, ct);
3877c478bd9Sstevel@tonic-gate 				error = ENXIO;
3887c478bd9Sstevel@tonic-gate 				goto done;
3897c478bd9Sstevel@tonic-gate 			}
3907c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOSYNC;
3917c478bd9Sstevel@tonic-gate 			fnp->fn_insync++;
3927c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
3937c478bd9Sstevel@tonic-gate 			    &fnp->fn_lock->flk_lock)) {
3947c478bd9Sstevel@tonic-gate 				/*
3957c478bd9Sstevel@tonic-gate 				 * Last writer to wakeup clear
3967c478bd9Sstevel@tonic-gate 				 * Clear both writer and reader open
397da6c28aaSamw 				 * occurred flag in case other end is O_RDWR
3987c478bd9Sstevel@tonic-gate 				 */
3997c478bd9Sstevel@tonic-gate 				if (--fnp->fn_insync == 0 &&
4007c478bd9Sstevel@tonic-gate 				    (fnp->fn_flag & FIFOROCR) != 0) {
4017c478bd9Sstevel@tonic-gate 					fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
4027c478bd9Sstevel@tonic-gate 				}
4037c478bd9Sstevel@tonic-gate 				mutex_exit(&fnp->fn_lock->flk_lock);
404da6c28aaSamw 				(void) fifo_close(*vpp, flag, 1, 0, crp, ct);
4057c478bd9Sstevel@tonic-gate 				error = EINTR;
4067c478bd9Sstevel@tonic-gate 				goto done;
4077c478bd9Sstevel@tonic-gate 			}
4087c478bd9Sstevel@tonic-gate 			/*
409da6c28aaSamw 			 * Last writer to wakeup clear reader open occurred flag
4107c478bd9Sstevel@tonic-gate 			 * Clear both writer and reader open
411da6c28aaSamw 			 * occurred flag in case other end is O_RDWR
4127c478bd9Sstevel@tonic-gate 			 */
4137c478bd9Sstevel@tonic-gate 			if (--fnp->fn_insync == 0 &&
4147c478bd9Sstevel@tonic-gate 			    (fnp->fn_flag & FIFOROCR) != 0) {
4157c478bd9Sstevel@tonic-gate 				fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
4167c478bd9Sstevel@tonic-gate 				break;
4177c478bd9Sstevel@tonic-gate 			}
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
4217c478bd9Sstevel@tonic-gate done:
4227c478bd9Sstevel@tonic-gate 	return (error);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * Close down a stream.
4277c478bd9Sstevel@tonic-gate  * Call cleanlocks() and strclean() on every close.
4287c478bd9Sstevel@tonic-gate  * For last close send hangup message and force
4297c478bd9Sstevel@tonic-gate  * the other end of a named pipe to be unmounted.
4307c478bd9Sstevel@tonic-gate  * Mount guarantees that the mounted end will only call fifo_close()
4317c478bd9Sstevel@tonic-gate  * with a count of 1 when the unmount occurs.
4327c478bd9Sstevel@tonic-gate  * This routine will close down one end of a pipe or FIFO
4337c478bd9Sstevel@tonic-gate  * and free the stream head via strclose()
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4367c478bd9Sstevel@tonic-gate int
437da6c28aaSamw fifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
438da6c28aaSamw 	caller_context_t *ct)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp		= VTOF(vp);
4417c478bd9Sstevel@tonic-gate 	fifonode_t	*fn_dest	= fnp->fn_dest;
4427c478bd9Sstevel@tonic-gate 	int		error		= 0;
4437c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock	= fnp->fn_lock;
4447c478bd9Sstevel@tonic-gate 	queue_t		*sd_wrq;
4457c478bd9Sstevel@tonic-gate 	vnode_t		*fn_dest_vp;
4467c478bd9Sstevel@tonic-gate 	int		senthang = 0;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
4497c478bd9Sstevel@tonic-gate 	/*
4507c478bd9Sstevel@tonic-gate 	 * clean locks and clear events.
4517c478bd9Sstevel@tonic-gate 	 */
4527c478bd9Sstevel@tonic-gate 	(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
4537c478bd9Sstevel@tonic-gate 	cleanshares(vp, ttoproc(curthread)->p_pid);
4547c478bd9Sstevel@tonic-gate 	strclean(vp);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * If a file still has the pipe/FIFO open, return.
4587c478bd9Sstevel@tonic-gate 	 */
4597c478bd9Sstevel@tonic-gate 	if (count > 1)
4607c478bd9Sstevel@tonic-gate 		return (0);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	sd_wrq = strvp2wq(vp);
4647c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/*
4677c478bd9Sstevel@tonic-gate 	 * wait for pending opens to finish up
4687c478bd9Sstevel@tonic-gate 	 * note: this also has the side effect of single threading closes
4697c478bd9Sstevel@tonic-gate 	 */
4707c478bd9Sstevel@tonic-gate 	while (fn_lock->flk_ocsync)
4717c478bd9Sstevel@tonic-gate 		cv_wait(&fn_lock->flk_wait_cv, &fn_lock->flk_lock);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	fn_lock->flk_ocsync = 1;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (flag & FREAD) {
4767c478bd9Sstevel@tonic-gate 		fnp->fn_rcnt--;
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	/*
4797c478bd9Sstevel@tonic-gate 	 * If we are last writer wake up sleeping readers
4807c478bd9Sstevel@tonic-gate 	 * (They'll figure out that there are no more writers
4817c478bd9Sstevel@tonic-gate 	 * and do the right thing)
4827c478bd9Sstevel@tonic-gate 	 * send hangup down stream so that stream head will do the
4837c478bd9Sstevel@tonic-gate 	 * right thing.
4847c478bd9Sstevel@tonic-gate 	 */
4857c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
4867c478bd9Sstevel@tonic-gate 		if (--fnp->fn_wcnt == 0 && fn_dest->fn_rcnt > 0) {
4877c478bd9Sstevel@tonic-gate 			if ((fn_dest->fn_flag & (FIFOFAST | FIFOWANTR)) ==
4887c478bd9Sstevel@tonic-gate 			    (FIFOFAST | FIFOWANTR)) {
4897c478bd9Sstevel@tonic-gate 				/*
4907c478bd9Sstevel@tonic-gate 				 * While we're at it, clear FIFOWANTW too
4917c478bd9Sstevel@tonic-gate 				 * Wake up any sleeping readers or
4927c478bd9Sstevel@tonic-gate 				 * writers.
4937c478bd9Sstevel@tonic-gate 				 */
4947c478bd9Sstevel@tonic-gate 				fn_dest->fn_flag &= ~(FIFOWANTR | FIFOWANTW);
4957c478bd9Sstevel@tonic-gate 				cv_broadcast(&fn_dest->fn_wait_cv);
4967c478bd9Sstevel@tonic-gate 			}
4977c478bd9Sstevel@tonic-gate 			/*
4987c478bd9Sstevel@tonic-gate 			 * This is needed incase the other side
4997c478bd9Sstevel@tonic-gate 			 * was opened non-blocking.  It is the
5007c478bd9Sstevel@tonic-gate 			 * only way we can tell that wcnt is 0 because
5017c478bd9Sstevel@tonic-gate 			 * of close instead of never having a writer
5027c478bd9Sstevel@tonic-gate 			 */
5037c478bd9Sstevel@tonic-gate 			if (!(fnp->fn_flag & ISPIPE))
5047c478bd9Sstevel@tonic-gate 				fnp->fn_flag |= FIFOCLOSE;
5057c478bd9Sstevel@tonic-gate 			/*
5067c478bd9Sstevel@tonic-gate 			 * Note: sending hangup effectively shuts down
5077c478bd9Sstevel@tonic-gate 			 * both reader and writer at other end.
5087c478bd9Sstevel@tonic-gate 			 */
5097c478bd9Sstevel@tonic-gate 			(void) putnextctl_wait(sd_wrq, M_HANGUP);
5107c478bd9Sstevel@tonic-gate 			senthang = 1;
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	/*
5157c478bd9Sstevel@tonic-gate 	 * For FIFOs we need to indicate to stream head that last reader
5167c478bd9Sstevel@tonic-gate 	 * has gone away so that an error is generated
5177c478bd9Sstevel@tonic-gate 	 * Pipes just need to wake up the other end so that it can
5187c478bd9Sstevel@tonic-gate 	 * notice this end has gone away.
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (fnp->fn_rcnt == 0 && fn_dest->fn_wcnt > 0) {
5227c478bd9Sstevel@tonic-gate 		if ((fn_dest->fn_flag & (FIFOFAST | FIFOWANTW)) ==
5237c478bd9Sstevel@tonic-gate 		    (FIFOFAST | FIFOWANTW)) {
5247c478bd9Sstevel@tonic-gate 			/*
5257c478bd9Sstevel@tonic-gate 			 * wake up any sleeping writers
5267c478bd9Sstevel@tonic-gate 			 */
5277c478bd9Sstevel@tonic-gate 			fn_dest->fn_flag &= ~FIFOWANTW;
5287c478bd9Sstevel@tonic-gate 			cv_broadcast(&fn_dest->fn_wait_cv);
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * if there are still processes with this FIFO open
5347c478bd9Sstevel@tonic-gate 	 *	clear open/close sync flag
5357c478bd9Sstevel@tonic-gate 	 *	and just return;
5367c478bd9Sstevel@tonic-gate 	 */
5377c478bd9Sstevel@tonic-gate 	if (--fnp->fn_open > 0) {
5387c478bd9Sstevel@tonic-gate 		ASSERT((fnp->fn_rcnt + fnp->fn_wcnt) != 0);
5397c478bd9Sstevel@tonic-gate 		fn_lock->flk_ocsync = 0;
5407c478bd9Sstevel@tonic-gate 		cv_broadcast(&fn_lock->flk_wait_cv);
5417c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
5427c478bd9Sstevel@tonic-gate 		return (0);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/*
5467c478bd9Sstevel@tonic-gate 	 * Need to send HANGUP if other side is still open
5477c478bd9Sstevel@tonic-gate 	 * (fnp->fn_rcnt or fnp->fn_wcnt may not be zero (some thread
5487c478bd9Sstevel@tonic-gate 	 * on this end of the pipe may still be in fifo_open())
5497c478bd9Sstevel@tonic-gate 	 *
5507c478bd9Sstevel@tonic-gate 	 * Note: we can get here with fn_rcnt and fn_wcnt != 0 if some
5517c478bd9Sstevel@tonic-gate 	 * thread is blocked somewhere in the fifo_open() path prior to
5527c478bd9Sstevel@tonic-gate 	 * fifo_stropen() incrementing fn_open.  This can occur for
5537c478bd9Sstevel@tonic-gate 	 * normal FIFOs as well as named pipes.  fn_rcnt and
5547c478bd9Sstevel@tonic-gate 	 * fn_wcnt only indicate attempts to open. fn_open indicates
5557c478bd9Sstevel@tonic-gate 	 * successful opens. Partially opened FIFOs should proceed
5567c478bd9Sstevel@tonic-gate 	 * normally; i.e. they will appear to be new opens.  Partially
5577c478bd9Sstevel@tonic-gate 	 * opened pipes will probably fail.
5587c478bd9Sstevel@tonic-gate 	 */
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	if (fn_dest->fn_open && senthang == 0)
5617c478bd9Sstevel@tonic-gate 		(void) putnextctl_wait(sd_wrq, M_HANGUP);
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/*
5657c478bd9Sstevel@tonic-gate 	 * If this a pipe and this is the first end to close,
5667c478bd9Sstevel@tonic-gate 	 * then we have a bit of cleanup work to do.
5677c478bd9Sstevel@tonic-gate 	 * 	Mark both ends of pipe as closed.
5687c478bd9Sstevel@tonic-gate 	 * 	Wake up anybody blocked at the other end and for named pipes,
5697c478bd9Sstevel@tonic-gate 	 *	Close down this end of the stream
5707c478bd9Sstevel@tonic-gate 	 *	Allow other opens/closes to continue
5717c478bd9Sstevel@tonic-gate 	 * 	force an unmount of other end.
5727c478bd9Sstevel@tonic-gate 	 * Otherwise if this is last close,
5737c478bd9Sstevel@tonic-gate 	 *	flush messages,
5747c478bd9Sstevel@tonic-gate 	 *	close down the stream
5757c478bd9Sstevel@tonic-gate 	 *	allow other opens/closes to continue
5767c478bd9Sstevel@tonic-gate 	 */
5777c478bd9Sstevel@tonic-gate 	fnp->fn_flag &= ~FIFOISOPEN;
5787c478bd9Sstevel@tonic-gate 	if ((fnp->fn_flag & ISPIPE) && !(fnp->fn_flag & FIFOCLOSE)) {
5797c478bd9Sstevel@tonic-gate 		fnp->fn_flag |= FIFOCLOSE;
5807c478bd9Sstevel@tonic-gate 		fn_dest->fn_flag |= FIFOCLOSE;
5817c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & FIFOFAST)
5827c478bd9Sstevel@tonic-gate 			fifo_fastflush(fnp);
5837c478bd9Sstevel@tonic-gate 		if (vp->v_stream != NULL) {
5847c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
5857c478bd9Sstevel@tonic-gate 			(void) strclose(vp, flag, crp);
5867c478bd9Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		cv_broadcast(&fn_dest->fn_wait_cv);
5897c478bd9Sstevel@tonic-gate 		/*
5907c478bd9Sstevel@tonic-gate 		 * allow opens and closes to proceed
5917c478bd9Sstevel@tonic-gate 		 * Since this end is now closed down, any attempt
5927c478bd9Sstevel@tonic-gate 		 * to do anything with this end will fail
5937c478bd9Sstevel@tonic-gate 		 */
5947c478bd9Sstevel@tonic-gate 		fn_lock->flk_ocsync = 0;
5957c478bd9Sstevel@tonic-gate 		cv_broadcast(&fn_lock->flk_wait_cv);
5967c478bd9Sstevel@tonic-gate 		fn_dest_vp = FTOV(fn_dest);
5977c478bd9Sstevel@tonic-gate 		/*
5987c478bd9Sstevel@tonic-gate 		 * if other end of pipe has been opened and it's
5997c478bd9Sstevel@tonic-gate 		 * a named pipe, unmount it
6007c478bd9Sstevel@tonic-gate 		 */
6017c478bd9Sstevel@tonic-gate 		if (fn_dest_vp->v_stream &&
6027c478bd9Sstevel@tonic-gate 		    (fn_dest_vp->v_stream->sd_flag & STRMOUNT)) {
6037c478bd9Sstevel@tonic-gate 			/*
6047c478bd9Sstevel@tonic-gate 			 * We must hold the destination vnode because
6057c478bd9Sstevel@tonic-gate 			 * nm_unmountall() causes close to be called
6067c478bd9Sstevel@tonic-gate 			 * for the other end of named pipe.  This
6077c478bd9Sstevel@tonic-gate 			 * could free the vnode before we are ready.
6087c478bd9Sstevel@tonic-gate 			 */
6097c478bd9Sstevel@tonic-gate 			VN_HOLD(fn_dest_vp);
6107c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
6117c478bd9Sstevel@tonic-gate 			error = nm_unmountall(fn_dest_vp, crp);
6127c478bd9Sstevel@tonic-gate 			ASSERT(error == 0);
6137c478bd9Sstevel@tonic-gate 			VN_RELE(fn_dest_vp);
6147c478bd9Sstevel@tonic-gate 		} else {
6157c478bd9Sstevel@tonic-gate 			ASSERT(vp->v_count >= 1);
6167c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
6177c478bd9Sstevel@tonic-gate 		}
6187c478bd9Sstevel@tonic-gate 	} else {
6197c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & FIFOFAST)
6207c478bd9Sstevel@tonic-gate 			fifo_fastflush(fnp);
6217c478bd9Sstevel@tonic-gate #if DEBUG
6227c478bd9Sstevel@tonic-gate 		fn_dest_vp = FTOV(fn_dest);
6237c478bd9Sstevel@tonic-gate 		if (fn_dest_vp->v_stream)
6247c478bd9Sstevel@tonic-gate 			ASSERT((fn_dest_vp->v_stream->sd_flag & STRMOUNT) == 0);
6257c478bd9Sstevel@tonic-gate #endif
6267c478bd9Sstevel@tonic-gate 		if (vp->v_stream != NULL) {
6277c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
6287c478bd9Sstevel@tonic-gate 			(void) strclose(vp, flag, crp);
6297c478bd9Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
6307c478bd9Sstevel@tonic-gate 		}
6317c478bd9Sstevel@tonic-gate 		fn_lock->flk_ocsync = 0;
6327c478bd9Sstevel@tonic-gate 		cv_broadcast(&fn_lock->flk_wait_cv);
6337c478bd9Sstevel@tonic-gate 		cv_broadcast(&fn_dest->fn_wait_cv);
6347c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 	return (error);
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate /*
6407c478bd9Sstevel@tonic-gate  * Read from a pipe or FIFO.
6417c478bd9Sstevel@tonic-gate  * return 0 if....
6427c478bd9Sstevel@tonic-gate  *    (1) user read request is 0 or no stream
6437c478bd9Sstevel@tonic-gate  *    (2) broken pipe with no data
6447c478bd9Sstevel@tonic-gate  *    (3) write-only FIFO with no data
6457c478bd9Sstevel@tonic-gate  *    (4) no data and FNDELAY flag is set.
6467c478bd9Sstevel@tonic-gate  * Otherwise return
6477c478bd9Sstevel@tonic-gate  *	EAGAIN if FNONBLOCK is set and no data to read
648bc20329dSjk115741  *	EINTR if signal received while waiting for data
6497c478bd9Sstevel@tonic-gate  *
6507c478bd9Sstevel@tonic-gate  * While there is no data to read....
6517c478bd9Sstevel@tonic-gate  *   -  if the NDELAY/NONBLOCK flag is set, return 0/EAGAIN.
6527c478bd9Sstevel@tonic-gate  *   -  wait for a write.
6537c478bd9Sstevel@tonic-gate  *
6547c478bd9Sstevel@tonic-gate  */
6557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate static int
6587c478bd9Sstevel@tonic-gate fifo_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *crp,
6597c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp		= VTOF(vp);
6627c478bd9Sstevel@tonic-gate 	fifonode_t	*fn_dest;
6637c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock	= fnp->fn_lock;
6647c478bd9Sstevel@tonic-gate 	int		error		= 0;
6657c478bd9Sstevel@tonic-gate 	mblk_t		*bp;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
6687c478bd9Sstevel@tonic-gate 	if (uiop->uio_resid == 0)
6697c478bd9Sstevel@tonic-gate 		return (0);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
6727c478bd9Sstevel@tonic-gate 
673bc20329dSjk115741 	TRACE_2(TR_FAC_FIFO, TR_FIFOREAD_IN, "fifo_read in:%p fnp %p", vp, fnp);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if (! (fnp->fn_flag & FIFOFAST))
6767c478bd9Sstevel@tonic-gate 		goto stream_mode;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	fn_dest	= fnp->fn_dest;
6797c478bd9Sstevel@tonic-gate 	/*
6807c478bd9Sstevel@tonic-gate 	 * Check for data on our input queue
6817c478bd9Sstevel@tonic-gate 	 */
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	while (fnp->fn_count == 0) {
6847c478bd9Sstevel@tonic-gate 		/*
6857c478bd9Sstevel@tonic-gate 		 * No data on first attempt and no writer, then EOF
6867c478bd9Sstevel@tonic-gate 		 */
6877c478bd9Sstevel@tonic-gate 		if (fn_dest->fn_wcnt == 0 || fn_dest->fn_rcnt == 0) {
6887c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
6897c478bd9Sstevel@tonic-gate 			return (0);
6907c478bd9Sstevel@tonic-gate 		}
6917c478bd9Sstevel@tonic-gate 		/*
6927c478bd9Sstevel@tonic-gate 		 * no data found.. if non-blocking, return EAGAIN
6937c478bd9Sstevel@tonic-gate 		 * otherwise 0.
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 		if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) {
6967c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
6977c478bd9Sstevel@tonic-gate 			if (uiop->uio_fmode & FNONBLOCK)
6987c478bd9Sstevel@tonic-gate 				return (EAGAIN);
6997c478bd9Sstevel@tonic-gate 			return (0);
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		/*
7037c478bd9Sstevel@tonic-gate 		 * Note: FIFOs can get here with FIFOCLOSE set if
7047c478bd9Sstevel@tonic-gate 		 * write side is in the middle of opeining after
7057c478bd9Sstevel@tonic-gate 		 * it once closed. Pipes better not have FIFOCLOSE set
7067c478bd9Sstevel@tonic-gate 		 */
7077c478bd9Sstevel@tonic-gate 		ASSERT((fnp->fn_flag & (ISPIPE|FIFOCLOSE)) !=
7087c478bd9Sstevel@tonic-gate 		    (ISPIPE|FIFOCLOSE));
7097c478bd9Sstevel@tonic-gate 		/*
7107c478bd9Sstevel@tonic-gate 		 * wait for data
7117c478bd9Sstevel@tonic-gate 		 */
7127c478bd9Sstevel@tonic-gate 		fnp->fn_flag |= FIFOWANTR;
7137c478bd9Sstevel@tonic-gate 
714bc20329dSjk115741 		TRACE_1(TR_FAC_FIFO, TR_FIFOREAD_WAIT, "fiforead wait: %p", vp);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
7177c478bd9Sstevel@tonic-gate 		    &fn_lock->flk_lock)) {
7187c478bd9Sstevel@tonic-gate 			error = EINTR;
7197c478bd9Sstevel@tonic-gate 			goto done;
7207c478bd9Sstevel@tonic-gate 		}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_FIFO, TR_FIFOREAD_WAKE,
7237c478bd9Sstevel@tonic-gate 		    "fiforead awake: %p", vp);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 		/*
7267c478bd9Sstevel@tonic-gate 		 * check to make sure we are still in fast mode
7277c478bd9Sstevel@tonic-gate 		 */
7287c478bd9Sstevel@tonic-gate 		if (!(fnp->fn_flag & FIFOFAST))
7297c478bd9Sstevel@tonic-gate 			goto stream_mode;
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	ASSERT(fnp->fn_mp != NULL);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	/* For pipes copy should not bypass cache */
7357c478bd9Sstevel@tonic-gate 	uiop->uio_extflg |= UIO_COPY_CACHED;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	do {
7387c478bd9Sstevel@tonic-gate 		int bpsize = MBLKL(fnp->fn_mp);
7397c478bd9Sstevel@tonic-gate 		int uiosize = MIN(bpsize, uiop->uio_resid);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 		error = uiomove(fnp->fn_mp->b_rptr, uiosize, UIO_READ, uiop);
7427c478bd9Sstevel@tonic-gate 		if (error != 0)
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		fnp->fn_count -= uiosize;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (bpsize <= uiosize) {
7487c478bd9Sstevel@tonic-gate 			bp = fnp->fn_mp;
7497c478bd9Sstevel@tonic-gate 			fnp->fn_mp = fnp->fn_mp->b_cont;
7507c478bd9Sstevel@tonic-gate 			freeb(bp);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 			if (uiop->uio_resid == 0)
7537c478bd9Sstevel@tonic-gate 				break;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 			while (fnp->fn_mp == NULL && fn_dest->fn_wwaitcnt > 0) {
7567c478bd9Sstevel@tonic-gate 				ASSERT(fnp->fn_count == 0);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 				if (uiop->uio_fmode & (FNDELAY|FNONBLOCK))
7597c478bd9Sstevel@tonic-gate 					goto trywake;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 				/*
7627c478bd9Sstevel@tonic-gate 				 * We've consumed all available data but there
7637c478bd9Sstevel@tonic-gate 				 * are threads waiting to write more, let them
7647c478bd9Sstevel@tonic-gate 				 * proceed before bailing.
7657c478bd9Sstevel@tonic-gate 				 */
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 				fnp->fn_flag |= FIFOWANTR;
7687c478bd9Sstevel@tonic-gate 				fifo_wakewriter(fn_dest, fn_lock);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 				if (!cv_wait_sig(&fnp->fn_wait_cv,
7717c478bd9Sstevel@tonic-gate 				    &fn_lock->flk_lock))
7727c478bd9Sstevel@tonic-gate 					goto trywake;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 				if (!(fnp->fn_flag & FIFOFAST))
7757c478bd9Sstevel@tonic-gate 					goto stream_mode;
7767c478bd9Sstevel@tonic-gate 			}
7777c478bd9Sstevel@tonic-gate 		} else {
7787c478bd9Sstevel@tonic-gate 			fnp->fn_mp->b_rptr += uiosize;
7797c478bd9Sstevel@tonic-gate 			ASSERT(uiop->uio_resid == 0);
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 	} while (uiop->uio_resid != 0 && fnp->fn_mp != NULL);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate trywake:
7847c478bd9Sstevel@tonic-gate 	ASSERT(msgdsize(fnp->fn_mp) == fnp->fn_count);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/*
7877c478bd9Sstevel@tonic-gate 	 * wake up any blocked writers, processes
7887c478bd9Sstevel@tonic-gate 	 * sleeping on POLLWRNORM, or processes waiting for SIGPOLL
7897c478bd9Sstevel@tonic-gate 	 * Note: checking for fn_count < Fifohiwat emulates
7907c478bd9Sstevel@tonic-gate 	 * STREAMS functionality when low water mark is 0
7917c478bd9Sstevel@tonic-gate 	 */
7927c478bd9Sstevel@tonic-gate 	if (fn_dest->fn_flag & (FIFOWANTW | FIFOHIWATW) &&
7937c478bd9Sstevel@tonic-gate 	    fnp->fn_count < Fifohiwat) {
7947c478bd9Sstevel@tonic-gate 		fifo_wakewriter(fn_dest, fn_lock);
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 	goto done;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	/*
7997c478bd9Sstevel@tonic-gate 	 * FIFO is in streams mode.. let the stream head handle it
8007c478bd9Sstevel@tonic-gate 	 */
8017c478bd9Sstevel@tonic-gate stream_mode:
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
8047c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_FIFO,
8057c478bd9Sstevel@tonic-gate 	    TR_FIFOREAD_STREAM, "fifo_read stream_mode:%p", vp);
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	error = strread(vp, uiop, crp);
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate done:
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * vnode update access time
8147c478bd9Sstevel@tonic-gate 	 */
8157c478bd9Sstevel@tonic-gate 	if (error == 0) {
8167c478bd9Sstevel@tonic-gate 		time_t now = gethrestime_sec();
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & ISPIPE)
8197c478bd9Sstevel@tonic-gate 			fnp->fn_dest->fn_atime = now;
8207c478bd9Sstevel@tonic-gate 		fnp->fn_atime = now;
8217c478bd9Sstevel@tonic-gate 	}
822bc20329dSjk115741 	TRACE_2(TR_FAC_FIFO, TR_FIFOREAD_OUT,
823bc20329dSjk115741 	    "fifo_read out:%p error %d", vp, error);
8247c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
8257c478bd9Sstevel@tonic-gate 	return (error);
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate /*
8297c478bd9Sstevel@tonic-gate  * send SIGPIPE and return EPIPE if ...
8307c478bd9Sstevel@tonic-gate  *   (1) broken pipe (essentially, reader is gone)
8317c478bd9Sstevel@tonic-gate  *   (2) FIFO is not open for reading
8327c478bd9Sstevel@tonic-gate  * return 0 if...
8337c478bd9Sstevel@tonic-gate  *   (1) no stream
8347c478bd9Sstevel@tonic-gate  *   (2) user write request is for 0 bytes and SW_SNDZERO is not set
8357c478bd9Sstevel@tonic-gate  *	Note: SW_SNDZERO can't be set in fast mode
8367c478bd9Sstevel@tonic-gate  * While the stream is flow controlled....
8377c478bd9Sstevel@tonic-gate  *   -  if the NDELAY/NONBLOCK flag is set, return 0/EAGAIN.
8387c478bd9Sstevel@tonic-gate  *   -  unlock the fifonode and sleep waiting for a reader.
8397c478bd9Sstevel@tonic-gate  *   -  if a pipe and it has a mate, sleep waiting for its mate
8407c478bd9Sstevel@tonic-gate  *	to read.
8417c478bd9Sstevel@tonic-gate  */
8427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8437c478bd9Sstevel@tonic-gate static int
8447c478bd9Sstevel@tonic-gate fifo_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *crp,
8457c478bd9Sstevel@tonic-gate 	caller_context_t *ct)
8467c478bd9Sstevel@tonic-gate {
8477c478bd9Sstevel@tonic-gate 	struct fifonode	*fnp, *fn_dest;
8487c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock;
8497c478bd9Sstevel@tonic-gate 	struct stdata	*stp;
8507c478bd9Sstevel@tonic-gate 	int		error	= 0;
8517c478bd9Sstevel@tonic-gate 	int		write_size;
8527c478bd9Sstevel@tonic-gate 	int		size;
8537c478bd9Sstevel@tonic-gate 	int		fmode;
8547c478bd9Sstevel@tonic-gate 	mblk_t		*bp;
8557c478bd9Sstevel@tonic-gate 	boolean_t	hotread;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream);
8587c478bd9Sstevel@tonic-gate 	uiop->uio_loffset = 0;
8597c478bd9Sstevel@tonic-gate 	stp	= vp->v_stream;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/*
8627c478bd9Sstevel@tonic-gate 	 * remember original number of bytes requested. Used to determine if
8637c478bd9Sstevel@tonic-gate 	 * we actually have written anything at all
8647c478bd9Sstevel@tonic-gate 	 */
8657c478bd9Sstevel@tonic-gate 	write_size = uiop->uio_resid;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	/*
8687c478bd9Sstevel@tonic-gate 	 * only send zero-length messages if SW_SNDZERO is set
8697c478bd9Sstevel@tonic-gate 	 * Note: we will be in streams mode if SW_SNDZERO is set
8707c478bd9Sstevel@tonic-gate 	 * XXX this streams interface should not be exposed
8717c478bd9Sstevel@tonic-gate 	 */
8727c478bd9Sstevel@tonic-gate 	if ((write_size == 0) && !(stp->sd_wput_opt & SW_SNDZERO))
8737c478bd9Sstevel@tonic-gate 		return (0);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	fnp = VTOF(vp);
8767c478bd9Sstevel@tonic-gate 	fn_lock = fnp->fn_lock;
8777c478bd9Sstevel@tonic-gate 	fn_dest = fnp->fn_dest;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
8807c478bd9Sstevel@tonic-gate 
881bc20329dSjk115741 	TRACE_3(TR_FAC_FIFO, TR_FIFOWRITE_IN,
882bc20329dSjk115741 	    "fifo_write in:%p fnp %p size %d", vp, fnp, write_size);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 * oops, no readers, error
8867c478bd9Sstevel@tonic-gate 	 */
8877c478bd9Sstevel@tonic-gate 	if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
8887c478bd9Sstevel@tonic-gate 		goto epipe;
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	/*
8927c478bd9Sstevel@tonic-gate 	 * if we are not in fast mode, let streams handle it
8937c478bd9Sstevel@tonic-gate 	 */
8947c478bd9Sstevel@tonic-gate 	if (!(fnp->fn_flag & FIFOFAST))
8957c478bd9Sstevel@tonic-gate 		goto stream_mode;
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	fmode = uiop->uio_fmode & (FNDELAY|FNONBLOCK);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	/* For pipes copy should not bypass cache */
9007c478bd9Sstevel@tonic-gate 	uiop->uio_extflg |= UIO_COPY_CACHED;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	do  {
9037c478bd9Sstevel@tonic-gate 		/*
9047c478bd9Sstevel@tonic-gate 		 * check to make sure we are not over high water mark
9057c478bd9Sstevel@tonic-gate 		 */
9067c478bd9Sstevel@tonic-gate 		while (fn_dest->fn_count >= Fifohiwat) {
9077c478bd9Sstevel@tonic-gate 			/*
9087c478bd9Sstevel@tonic-gate 			 * Indicate that we have gone over high
9097c478bd9Sstevel@tonic-gate 			 * water mark
9107c478bd9Sstevel@tonic-gate 			 */
9117c478bd9Sstevel@tonic-gate 			/*
9127c478bd9Sstevel@tonic-gate 			 * if non-blocking, return
9137c478bd9Sstevel@tonic-gate 			 * only happens first time through loop
9147c478bd9Sstevel@tonic-gate 			 */
9157c478bd9Sstevel@tonic-gate 			if (fmode) {
9167c478bd9Sstevel@tonic-gate 				fnp->fn_flag |= FIFOHIWATW;
9177c478bd9Sstevel@tonic-gate 				if (uiop->uio_resid == write_size) {
9187c478bd9Sstevel@tonic-gate 					mutex_exit(&fn_lock->flk_lock);
9197c478bd9Sstevel@tonic-gate 					if (fmode & FNDELAY)
9207c478bd9Sstevel@tonic-gate 						return (0);
9217c478bd9Sstevel@tonic-gate 					else
9227c478bd9Sstevel@tonic-gate 						return (EAGAIN);
9237c478bd9Sstevel@tonic-gate 				}
9247c478bd9Sstevel@tonic-gate 				goto done;
9257c478bd9Sstevel@tonic-gate 			}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 			/*
9287c478bd9Sstevel@tonic-gate 			 * wait for things to drain
9297c478bd9Sstevel@tonic-gate 			 */
9307c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOWANTW;
9317c478bd9Sstevel@tonic-gate 			fnp->fn_wwaitcnt++;
9327c478bd9Sstevel@tonic-gate 			TRACE_1(TR_FAC_FIFO, TR_FIFOWRITE_WAIT,
9337c478bd9Sstevel@tonic-gate 			    "fifo_write wait: %p", vp);
9347c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
9357c478bd9Sstevel@tonic-gate 			    &fn_lock->flk_lock)) {
9367c478bd9Sstevel@tonic-gate 				error = EINTR;
9377c478bd9Sstevel@tonic-gate 				fnp->fn_wwaitcnt--;
9387c478bd9Sstevel@tonic-gate 				fifo_wakereader(fn_dest, fn_lock);
9397c478bd9Sstevel@tonic-gate 				goto done;
9407c478bd9Sstevel@tonic-gate 			}
9417c478bd9Sstevel@tonic-gate 			fnp->fn_wwaitcnt--;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 			TRACE_1(TR_FAC_FIFO, TR_FIFOWRITE_WAKE,
9447c478bd9Sstevel@tonic-gate 			    "fifo_write wake: %p", vp);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 			/*
9477c478bd9Sstevel@tonic-gate 			 * check to make sure we're still in fast mode
9487c478bd9Sstevel@tonic-gate 			 */
9497c478bd9Sstevel@tonic-gate 			if (!(fnp->fn_flag & FIFOFAST))
9507c478bd9Sstevel@tonic-gate 				goto stream_mode;
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 			/*
9537c478bd9Sstevel@tonic-gate 			 * make sure readers didn't go away
9547c478bd9Sstevel@tonic-gate 			 */
9557c478bd9Sstevel@tonic-gate 			if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
9567c478bd9Sstevel@tonic-gate 				goto epipe;
9577c478bd9Sstevel@tonic-gate 			}
9587c478bd9Sstevel@tonic-gate 		}
9597c478bd9Sstevel@tonic-gate 		/*
9607c478bd9Sstevel@tonic-gate 		 * If the write will put us over the high water mark,
9617c478bd9Sstevel@tonic-gate 		 * then we must break the message up into PIPE_BUF
9627c478bd9Sstevel@tonic-gate 		 * chunks to stay compliant with STREAMS
9637c478bd9Sstevel@tonic-gate 		 */
9647c478bd9Sstevel@tonic-gate 		if (uiop->uio_resid + fn_dest->fn_count > Fifohiwat)
9657c478bd9Sstevel@tonic-gate 			size = MIN(uiop->uio_resid, PIPE_BUF);
9667c478bd9Sstevel@tonic-gate 		else
9677c478bd9Sstevel@tonic-gate 			size = uiop->uio_resid;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 		/*
9707c478bd9Sstevel@tonic-gate 		 * We don't need to hold flk_lock across the allocb() and
9717c478bd9Sstevel@tonic-gate 		 * uiomove().  However, on a multiprocessor machine where both
9727c478bd9Sstevel@tonic-gate 		 * the reader and writer thread are on cpu's, we must be
9737c478bd9Sstevel@tonic-gate 		 * careful to only drop the lock if there's data to be read.
9747c478bd9Sstevel@tonic-gate 		 * This forces threads entering fifo_read() to spin or block
9757c478bd9Sstevel@tonic-gate 		 * on flk_lock, rather than acquiring flk_lock only to
9767c478bd9Sstevel@tonic-gate 		 * discover there's no data to read and being forced to go
9777c478bd9Sstevel@tonic-gate 		 * back to sleep, only to be woken up microseconds later by
9787c478bd9Sstevel@tonic-gate 		 * this writer thread.
9797c478bd9Sstevel@tonic-gate 		 */
9807c478bd9Sstevel@tonic-gate 		hotread = fn_dest->fn_count > 0;
98139cba716Swroche 		if (hotread) {
98239cba716Swroche 			if (!fifo_stayfast_enter(fnp))
98339cba716Swroche 				goto stream_mode;
9847c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
98539cba716Swroche 		}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 		ASSERT(size != 0);
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * Align the mblk with the user data so that
9907c478bd9Sstevel@tonic-gate 		 * copying in the data can take advantage of
9917c478bd9Sstevel@tonic-gate 		 * the double word alignment
9927c478bd9Sstevel@tonic-gate 		 */
9937c478bd9Sstevel@tonic-gate 		if ((bp = allocb(size + 8, BPRI_MED)) == NULL) {
9947c478bd9Sstevel@tonic-gate 			if (!hotread)
9957c478bd9Sstevel@tonic-gate 				mutex_exit(&fn_lock->flk_lock);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 			error = strwaitbuf(size, BPRI_MED);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
100039cba716Swroche 
100139cba716Swroche 			if (hotread) {
100239cba716Swroche 				/*
100339cba716Swroche 				 * As we dropped the mutex for a moment, we
100439cba716Swroche 				 * need to wake up any thread waiting to be
100539cba716Swroche 				 * allowed to go from fast mode to stream mode.
100639cba716Swroche 				 */
100739cba716Swroche 				fifo_stayfast_exit(fnp);
100839cba716Swroche 			}
10097c478bd9Sstevel@tonic-gate 			if (error != 0) {
10107c478bd9Sstevel@tonic-gate 				goto done;
10117c478bd9Sstevel@tonic-gate 			}
10127c478bd9Sstevel@tonic-gate 			/*
10137c478bd9Sstevel@tonic-gate 			 * check to make sure we're still in fast mode
10147c478bd9Sstevel@tonic-gate 			 */
10157c478bd9Sstevel@tonic-gate 			if (!(fnp->fn_flag & FIFOFAST))
10167c478bd9Sstevel@tonic-gate 				goto stream_mode;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 			/*
10197c478bd9Sstevel@tonic-gate 			 * make sure readers didn't go away
10207c478bd9Sstevel@tonic-gate 			 */
10217c478bd9Sstevel@tonic-gate 			if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
10227c478bd9Sstevel@tonic-gate 				goto epipe;
10237c478bd9Sstevel@tonic-gate 			}
10247c478bd9Sstevel@tonic-gate 			/*
10257c478bd9Sstevel@tonic-gate 			 * some other thread could have gotten in
10267c478bd9Sstevel@tonic-gate 			 * need to go back and check hi water mark
10277c478bd9Sstevel@tonic-gate 			 */
10287c478bd9Sstevel@tonic-gate 			continue;
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 		bp->b_rptr += ((uintptr_t)uiop->uio_iov->iov_base & 0x7);
10317c478bd9Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + size;
10327c478bd9Sstevel@tonic-gate 		error = uiomove((caddr_t)bp->b_rptr, size, UIO_WRITE, uiop);
103339cba716Swroche 		if (hotread) {
10347c478bd9Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
103539cba716Swroche 			/*
103639cba716Swroche 			 * As we dropped the mutex for a moment, we need to:
103739cba716Swroche 			 * - wake up any thread waiting to be allowed to go
103839cba716Swroche 			 *   from fast mode to stream mode,
103939cba716Swroche 			 * - make sure readers didn't go away.
104039cba716Swroche 			 */
104139cba716Swroche 			fifo_stayfast_exit(fnp);
104239cba716Swroche 			if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
104339cba716Swroche 				freeb(bp);
104439cba716Swroche 				goto epipe;
104539cba716Swroche 			}
104639cba716Swroche 		}
104739cba716Swroche 
10487c478bd9Sstevel@tonic-gate 		if (error != 0) {
10497c478bd9Sstevel@tonic-gate 			freeb(bp);
10507c478bd9Sstevel@tonic-gate 			goto done;
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 		fn_dest->fn_count += size;
10547c478bd9Sstevel@tonic-gate 		if (fn_dest->fn_mp != NULL) {
10557c478bd9Sstevel@tonic-gate 			fn_dest->fn_tail->b_cont = bp;
10567c478bd9Sstevel@tonic-gate 			fn_dest->fn_tail = bp;
10577c478bd9Sstevel@tonic-gate 		} else {
10587c478bd9Sstevel@tonic-gate 			fn_dest->fn_mp = fn_dest->fn_tail = bp;
10597c478bd9Sstevel@tonic-gate 			/*
10607c478bd9Sstevel@tonic-gate 			 * This is the first bit of data; wake up any sleeping
10617c478bd9Sstevel@tonic-gate 			 * readers, processes blocked in poll, and those
10627c478bd9Sstevel@tonic-gate 			 * expecting a SIGPOLL.
10637c478bd9Sstevel@tonic-gate 			 */
10647c478bd9Sstevel@tonic-gate 			fifo_wakereader(fn_dest, fn_lock);
10657c478bd9Sstevel@tonic-gate 		}
10667c478bd9Sstevel@tonic-gate 	} while (uiop->uio_resid != 0);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	goto done;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate stream_mode:
10717c478bd9Sstevel@tonic-gate 	/*
10727c478bd9Sstevel@tonic-gate 	 * streams mode
10737c478bd9Sstevel@tonic-gate 	 *  let the stream head handle the write
10747c478bd9Sstevel@tonic-gate 	 */
10757c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
10787c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_FIFO,
10797c478bd9Sstevel@tonic-gate 	    TR_FIFOWRITE_STREAM, "fifo_write stream_mode:%p", vp);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	error = strwrite(vp, uiop, crp);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate done:
10867c478bd9Sstevel@tonic-gate 	/*
10877c478bd9Sstevel@tonic-gate 	 * update vnode modification and change times
1088da6c28aaSamw 	 * make sure there were no errors and some data was transferred
10897c478bd9Sstevel@tonic-gate 	 */
10907c478bd9Sstevel@tonic-gate 	if (error == 0 && write_size != uiop->uio_resid) {
10917c478bd9Sstevel@tonic-gate 		time_t now = gethrestime_sec();
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & ISPIPE) {
10947c478bd9Sstevel@tonic-gate 			fn_dest->fn_mtime = fn_dest->fn_ctime = now;
10957c478bd9Sstevel@tonic-gate 		}
10967c478bd9Sstevel@tonic-gate 		fnp->fn_mtime = fnp->fn_ctime = now;
10977c478bd9Sstevel@tonic-gate 	} else if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
10987c478bd9Sstevel@tonic-gate 		goto epipe;
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_FIFO, TR_FIFOWRITE_OUT,
11017c478bd9Sstevel@tonic-gate 	    "fifo_write out: vp %p error %d fnp %p", vp, error, fnp);
11027c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
11037c478bd9Sstevel@tonic-gate 	return (error);
11047c478bd9Sstevel@tonic-gate epipe:
11057c478bd9Sstevel@tonic-gate 	error = EPIPE;
11067c478bd9Sstevel@tonic-gate 	TRACE_3(TR_FAC_FIFO, TR_FIFOWRITE_OUT,
1107bc20329dSjk115741 	    "fifo_write out: vp %p error %d fnp %p", vp, error, fnp);
11087c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
11097c478bd9Sstevel@tonic-gate 	tsignal(curthread, SIGPIPE);
11107c478bd9Sstevel@tonic-gate 	return (error);
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate 
1113da6c28aaSamw /*ARGSUSED6*/
11147c478bd9Sstevel@tonic-gate static int
11157c478bd9Sstevel@tonic-gate fifo_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
1116da6c28aaSamw 	cred_t *cr, int *rvalp, caller_context_t *ct)
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate 	/*
11197c478bd9Sstevel@tonic-gate 	 * Just a quick check
11207c478bd9Sstevel@tonic-gate 	 * Once we go to streams mode we don't ever revert back
11217c478bd9Sstevel@tonic-gate 	 * So we do this quick check so as not to incur the overhead
11227c478bd9Sstevel@tonic-gate 	 * associated with acquiring the lock
11237c478bd9Sstevel@tonic-gate 	 */
11247c478bd9Sstevel@tonic-gate 	return ((VTOF(vp)->fn_flag & FIFOFAST) ?
11257c478bd9Sstevel@tonic-gate 	    fifo_fastioctl(vp, cmd, arg, mode, cr, rvalp) :
11267c478bd9Sstevel@tonic-gate 	    fifo_strioctl(vp, cmd, arg, mode, cr, rvalp));
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate static int
11307c478bd9Sstevel@tonic-gate fifo_fastioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
11317c478bd9Sstevel@tonic-gate 	cred_t *cr, int *rvalp)
11327c478bd9Sstevel@tonic-gate {
11337c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp		= VTOF(vp);
11347c478bd9Sstevel@tonic-gate 	fifonode_t	*fn_dest;
11357c478bd9Sstevel@tonic-gate 	int		error		= 0;
11367c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock	= fnp->fn_lock;
11377c478bd9Sstevel@tonic-gate 	int		cnt;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/*
11407c478bd9Sstevel@tonic-gate 	 * tty operations not allowed
11417c478bd9Sstevel@tonic-gate 	 */
11427c478bd9Sstevel@tonic-gate 	if (((cmd & IOCTYPE) == LDIOC) ||
11437c478bd9Sstevel@tonic-gate 	    ((cmd & IOCTYPE) == tIOC) ||
11447c478bd9Sstevel@tonic-gate 	    ((cmd & IOCTYPE) == TIOC)) {
11457c478bd9Sstevel@tonic-gate 		return (EINVAL);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (!(fnp->fn_flag & FIFOFAST)) {
11517c478bd9Sstevel@tonic-gate 		goto stream_mode;
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	switch (cmd) {
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	/*
11577c478bd9Sstevel@tonic-gate 	 * Things we can't handle
11587c478bd9Sstevel@tonic-gate 	 * These will switch us to streams mode.
11597c478bd9Sstevel@tonic-gate 	 */
11607c478bd9Sstevel@tonic-gate 	default:
11617c478bd9Sstevel@tonic-gate 	case I_STR:
11627c478bd9Sstevel@tonic-gate 	case I_SRDOPT:
11637c478bd9Sstevel@tonic-gate 	case I_PUSH:
11647c478bd9Sstevel@tonic-gate 	case I_FDINSERT:
11657c478bd9Sstevel@tonic-gate 	case I_SENDFD:
11667c478bd9Sstevel@tonic-gate 	case I_RECVFD:
11677c478bd9Sstevel@tonic-gate 	case I_E_RECVFD:
11687c478bd9Sstevel@tonic-gate 	case I_ATMARK:
11697c478bd9Sstevel@tonic-gate 	case I_CKBAND:
11707c478bd9Sstevel@tonic-gate 	case I_GETBAND:
11717c478bd9Sstevel@tonic-gate 	case I_SWROPT:
11727c478bd9Sstevel@tonic-gate 		goto turn_fastoff;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	/*
11757c478bd9Sstevel@tonic-gate 	 * Things that don't do damage
11767c478bd9Sstevel@tonic-gate 	 * These things don't adjust the state of the
11777c478bd9Sstevel@tonic-gate 	 * stream head (i_setcltime does, but we don't care)
11787c478bd9Sstevel@tonic-gate 	 */
11797c478bd9Sstevel@tonic-gate 	case I_FIND:
11807c478bd9Sstevel@tonic-gate 	case I_GETSIG:
11817c478bd9Sstevel@tonic-gate 	case FIONBIO:
11827c478bd9Sstevel@tonic-gate 	case FIOASYNC:
11837c478bd9Sstevel@tonic-gate 	case I_GRDOPT:	/* probably should not get this, but no harm */
11847c478bd9Sstevel@tonic-gate 	case I_GWROPT:
11857c478bd9Sstevel@tonic-gate 	case I_LIST:
11867c478bd9Sstevel@tonic-gate 	case I_SETCLTIME:
11877c478bd9Sstevel@tonic-gate 	case I_GETCLTIME:
11887c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
11897c478bd9Sstevel@tonic-gate 		return (strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp));
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	case I_CANPUT:
11927c478bd9Sstevel@tonic-gate 		/*
11937c478bd9Sstevel@tonic-gate 		 * We can only handle normal band canputs.
11947c478bd9Sstevel@tonic-gate 		 * XXX : We could just always go to stream mode; after all
11957c478bd9Sstevel@tonic-gate 		 * canput is a streams semantics type thing
11967c478bd9Sstevel@tonic-gate 		 */
11977c478bd9Sstevel@tonic-gate 		if (arg != 0) {
11987c478bd9Sstevel@tonic-gate 			goto turn_fastoff;
11997c478bd9Sstevel@tonic-gate 		}
12007c478bd9Sstevel@tonic-gate 		*rvalp = (fnp->fn_dest->fn_count < Fifohiwat) ? 1 : 0;
12017c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
12027c478bd9Sstevel@tonic-gate 		return (0);
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	case I_NREAD:
12057c478bd9Sstevel@tonic-gate 		/*
12067c478bd9Sstevel@tonic-gate 		 * This may seem a bit silly for non-streams semantics,
12077c478bd9Sstevel@tonic-gate 		 * (After all, if they really want a message, they'll
12087c478bd9Sstevel@tonic-gate 		 * probably use getmsg() anyway). but it doesn't hurt
12097c478bd9Sstevel@tonic-gate 		 */
12107c478bd9Sstevel@tonic-gate 		error = copyout((caddr_t)&fnp->fn_count, (caddr_t)arg,
12117c478bd9Sstevel@tonic-gate 		    sizeof (cnt));
12127c478bd9Sstevel@tonic-gate 		if (error == 0) {
12137c478bd9Sstevel@tonic-gate 			*rvalp = (fnp->fn_count == 0) ? 0 : 1;
12147c478bd9Sstevel@tonic-gate 		}
12157c478bd9Sstevel@tonic-gate 		break;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	case FIORDCHK:
12187c478bd9Sstevel@tonic-gate 		*rvalp = fnp->fn_count;
12197c478bd9Sstevel@tonic-gate 		break;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	case I_PEEK:
12227c478bd9Sstevel@tonic-gate 	{
12237c478bd9Sstevel@tonic-gate 		STRUCT_DECL(strpeek, strpeek);
12247c478bd9Sstevel@tonic-gate 		struct uio	uio;
12257c478bd9Sstevel@tonic-gate 		struct iovec	iov;
12267c478bd9Sstevel@tonic-gate 		int		count;
12277c478bd9Sstevel@tonic-gate 		mblk_t		*bp;
1228bc20329dSjk115741 		int		len;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 		STRUCT_INIT(strpeek, mode);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 		if (fnp->fn_count == 0) {
12337c478bd9Sstevel@tonic-gate 			*rvalp = 0;
12347c478bd9Sstevel@tonic-gate 			break;
12357c478bd9Sstevel@tonic-gate 		}
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 		error = copyin((caddr_t)arg, STRUCT_BUF(strpeek),
12387c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek));
12397c478bd9Sstevel@tonic-gate 		if (error)
12407c478bd9Sstevel@tonic-gate 			break;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 		/*
12437c478bd9Sstevel@tonic-gate 		 * can't have any high priority message when in fast mode
12447c478bd9Sstevel@tonic-gate 		 */
12457c478bd9Sstevel@tonic-gate 		if (STRUCT_FGET(strpeek, flags) & RS_HIPRI) {
12467c478bd9Sstevel@tonic-gate 			*rvalp = 0;
12477c478bd9Sstevel@tonic-gate 			break;
12487c478bd9Sstevel@tonic-gate 		}
12497c478bd9Sstevel@tonic-gate 
1250bc20329dSjk115741 		len = STRUCT_FGET(strpeek, databuf.maxlen);
1251bc20329dSjk115741 		if (len <= 0) {
1252bc20329dSjk115741 			STRUCT_FSET(strpeek, databuf.len, len);
1253bc20329dSjk115741 		} else {
12547c478bd9Sstevel@tonic-gate 			iov.iov_base = STRUCT_FGETP(strpeek, databuf.buf);
1255bc20329dSjk115741 			iov.iov_len = len;
12567c478bd9Sstevel@tonic-gate 			uio.uio_iov = &iov;
12577c478bd9Sstevel@tonic-gate 			uio.uio_iovcnt = 1;
12587c478bd9Sstevel@tonic-gate 			uio.uio_loffset = 0;
12597c478bd9Sstevel@tonic-gate 			uio.uio_segflg = UIO_USERSPACE;
12607c478bd9Sstevel@tonic-gate 			uio.uio_fmode = 0;
12617c478bd9Sstevel@tonic-gate 			/* For pipes copy should not bypass cache */
12627c478bd9Sstevel@tonic-gate 			uio.uio_extflg = UIO_COPY_CACHED;
12637c478bd9Sstevel@tonic-gate 			uio.uio_resid = iov.iov_len;
12647c478bd9Sstevel@tonic-gate 			count = fnp->fn_count;
12657c478bd9Sstevel@tonic-gate 			bp = fnp->fn_mp;
12667c478bd9Sstevel@tonic-gate 			while (count > 0 && uio.uio_resid) {
1267bc20329dSjk115741 				cnt = MIN(uio.uio_resid, MBLKL(bp));
12687c478bd9Sstevel@tonic-gate 				if ((error = uiomove((char *)bp->b_rptr, cnt,
12697c478bd9Sstevel@tonic-gate 				    UIO_READ, &uio)) != 0) {
12707c478bd9Sstevel@tonic-gate 					break;
12717c478bd9Sstevel@tonic-gate 				}
12727c478bd9Sstevel@tonic-gate 				count -= cnt;
12737c478bd9Sstevel@tonic-gate 				bp = bp->b_cont;
12747c478bd9Sstevel@tonic-gate 			}
1275bc20329dSjk115741 			STRUCT_FSET(strpeek, databuf.len, len - uio.uio_resid);
1276bc20329dSjk115741 		}
12777c478bd9Sstevel@tonic-gate 		STRUCT_FSET(strpeek, flags, 0);
1278bc20329dSjk115741 		STRUCT_FSET(strpeek, ctlbuf.len, -1);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		error = copyout(STRUCT_BUF(strpeek), (caddr_t)arg,
12817c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(strpeek));
1282bc20329dSjk115741 		if (error == 0 && len >= 0)
12837c478bd9Sstevel@tonic-gate 			*rvalp = 1;
12847c478bd9Sstevel@tonic-gate 		break;
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	case FIONREAD:
12887c478bd9Sstevel@tonic-gate 		/*
12897c478bd9Sstevel@tonic-gate 		 * let user know total number of bytes in message queue
12907c478bd9Sstevel@tonic-gate 		 */
12917c478bd9Sstevel@tonic-gate 		error = copyout((caddr_t)&fnp->fn_count, (caddr_t)arg,
12927c478bd9Sstevel@tonic-gate 		    sizeof (fnp->fn_count));
12937c478bd9Sstevel@tonic-gate 		if (error == 0)
12947c478bd9Sstevel@tonic-gate 			*rvalp = 0;
12957c478bd9Sstevel@tonic-gate 		break;
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	case I_SETSIG:
12987c478bd9Sstevel@tonic-gate 		/*
12997c478bd9Sstevel@tonic-gate 		 * let streams set up the signal masking for us
13007c478bd9Sstevel@tonic-gate 		 * we just check to see if it's set
13017c478bd9Sstevel@tonic-gate 		 * XXX : this interface should not be visible
13027c478bd9Sstevel@tonic-gate 		 *  i.e. STREAM's framework is exposed.
13037c478bd9Sstevel@tonic-gate 		 */
13047c478bd9Sstevel@tonic-gate 		error = strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp);
13057c478bd9Sstevel@tonic-gate 		if (vp->v_stream->sd_sigflags & (S_INPUT|S_RDNORM|S_WRNORM))
13067c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOSETSIG;
13077c478bd9Sstevel@tonic-gate 		else
13087c478bd9Sstevel@tonic-gate 			fnp->fn_flag &= ~FIFOSETSIG;
13097c478bd9Sstevel@tonic-gate 		break;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	case I_FLUSH:
13127c478bd9Sstevel@tonic-gate 		/*
13137c478bd9Sstevel@tonic-gate 		 * flush them message queues
13147c478bd9Sstevel@tonic-gate 		 */
13157c478bd9Sstevel@tonic-gate 		if (arg & ~FLUSHRW) {
13167c478bd9Sstevel@tonic-gate 			error = EINVAL;
13177c478bd9Sstevel@tonic-gate 			break;
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 		if (arg & FLUSHR) {
13207c478bd9Sstevel@tonic-gate 			fifo_fastflush(fnp);
13217c478bd9Sstevel@tonic-gate 		}
13227c478bd9Sstevel@tonic-gate 		fn_dest = fnp->fn_dest;
13237c478bd9Sstevel@tonic-gate 		if ((arg & FLUSHW)) {
13247c478bd9Sstevel@tonic-gate 			fifo_fastflush(fn_dest);
13257c478bd9Sstevel@tonic-gate 		}
13267c478bd9Sstevel@tonic-gate 		/*
13277c478bd9Sstevel@tonic-gate 		 * wake up any sleeping readers or writers
13287c478bd9Sstevel@tonic-gate 		 * (waking readers probably doesn't make sense, but it
13297c478bd9Sstevel@tonic-gate 		 *  doesn't hurt; i.e. we just got rid of all the data
13307c478bd9Sstevel@tonic-gate 		 *  what's to read ?)
13317c478bd9Sstevel@tonic-gate 		 */
13327c478bd9Sstevel@tonic-gate 		if (fn_dest->fn_flag & (FIFOWANTW | FIFOWANTR)) {
13337c478bd9Sstevel@tonic-gate 			fn_dest->fn_flag &= ~(FIFOWANTW | FIFOWANTR);
13347c478bd9Sstevel@tonic-gate 			cv_broadcast(&fn_dest->fn_wait_cv);
13357c478bd9Sstevel@tonic-gate 		}
13367c478bd9Sstevel@tonic-gate 		*rvalp = 0;
13377c478bd9Sstevel@tonic-gate 		break;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/*
13407c478bd9Sstevel@tonic-gate 	 * Since no band data can ever get on a fifo in fast mode
13417c478bd9Sstevel@tonic-gate 	 * just return 0.
13427c478bd9Sstevel@tonic-gate 	 */
13437c478bd9Sstevel@tonic-gate 	case I_FLUSHBAND:
13447c478bd9Sstevel@tonic-gate 		error = 0;
13457c478bd9Sstevel@tonic-gate 		*rvalp = 0;
13467c478bd9Sstevel@tonic-gate 		break;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * invalid calls for stream head or fifos
13507c478bd9Sstevel@tonic-gate 	 */
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	case I_POP:		/* shouldn't happen */
13537c478bd9Sstevel@tonic-gate 	case I_LOOK:
13547c478bd9Sstevel@tonic-gate 	case I_LINK:
13557c478bd9Sstevel@tonic-gate 	case I_PLINK:
13567c478bd9Sstevel@tonic-gate 	case I_UNLINK:
13577c478bd9Sstevel@tonic-gate 	case I_PUNLINK:
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	/*
13607c478bd9Sstevel@tonic-gate 	 * more invalid tty type of ioctls
13617c478bd9Sstevel@tonic-gate 	 */
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	case SRIOCSREDIR:
13647c478bd9Sstevel@tonic-gate 	case SRIOCISREDIR:
13657c478bd9Sstevel@tonic-gate 		error = EINVAL;
13667c478bd9Sstevel@tonic-gate 		break;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	}
13697c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
13707c478bd9Sstevel@tonic-gate 	return (error);
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate turn_fastoff:
13737c478bd9Sstevel@tonic-gate 	fifo_fastoff(fnp);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate stream_mode:
13767c478bd9Sstevel@tonic-gate 	/*
13777c478bd9Sstevel@tonic-gate 	 * streams mode
13787c478bd9Sstevel@tonic-gate 	 */
13797c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
13807c478bd9Sstevel@tonic-gate 	return (fifo_strioctl(vp, cmd, arg, mode, cr, rvalp));
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate /*
13857c478bd9Sstevel@tonic-gate  * FIFO is in STREAMS mode; STREAMS framework does most of the work.
13867c478bd9Sstevel@tonic-gate  */
13877c478bd9Sstevel@tonic-gate static int
13887c478bd9Sstevel@tonic-gate fifo_strioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
13897c478bd9Sstevel@tonic-gate 	cred_t *cr, int *rvalp)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp = VTOF(vp);
13927c478bd9Sstevel@tonic-gate 	int		error;
13937c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock;
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 	if (cmd == _I_GETPEERCRED) {
13967c478bd9Sstevel@tonic-gate 		if (mode == FKIOCTL && fnp->fn_pcredp != NULL) {
13977c478bd9Sstevel@tonic-gate 			k_peercred_t *kp = (k_peercred_t *)arg;
13987c478bd9Sstevel@tonic-gate 			crhold(fnp->fn_pcredp);
13997c478bd9Sstevel@tonic-gate 			kp->pc_cr = fnp->fn_pcredp;
14007c478bd9Sstevel@tonic-gate 			kp->pc_cpid = fnp->fn_cpid;
14017c478bd9Sstevel@tonic-gate 			return (0);
14027c478bd9Sstevel@tonic-gate 		} else {
14037c478bd9Sstevel@tonic-gate 			return (ENOTSUP);
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	error = strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	switch (cmd) {
14107c478bd9Sstevel@tonic-gate 	/*
14117c478bd9Sstevel@tonic-gate 	 * The FIFOSEND flag is set to inform other processes that a file
14127c478bd9Sstevel@tonic-gate 	 * descriptor is pending at the stream head of this pipe.
14137c478bd9Sstevel@tonic-gate 	 * The flag is cleared and the sending process is awoken when
1414bc20329dSjk115741 	 * this process has completed receiving the file descriptor.
14157c478bd9Sstevel@tonic-gate 	 * XXX This could become out of sync if the process does I_SENDFDs
14167c478bd9Sstevel@tonic-gate 	 * and opens on connld attached to the same pipe.
14177c478bd9Sstevel@tonic-gate 	 */
14187c478bd9Sstevel@tonic-gate 	case I_RECVFD:
14197c478bd9Sstevel@tonic-gate 	case I_E_RECVFD:
14207c478bd9Sstevel@tonic-gate 		if (error == 0) {
14217c478bd9Sstevel@tonic-gate 			fn_lock = fnp->fn_lock;
14227c478bd9Sstevel@tonic-gate 			mutex_enter(&fn_lock->flk_lock);
14237c478bd9Sstevel@tonic-gate 			if (fnp->fn_flag & FIFOSEND) {
14247c478bd9Sstevel@tonic-gate 				fnp->fn_flag &= ~FIFOSEND;
14257c478bd9Sstevel@tonic-gate 				cv_broadcast(&fnp->fn_dest->fn_wait_cv);
14267c478bd9Sstevel@tonic-gate 			}
14277c478bd9Sstevel@tonic-gate 			mutex_exit(&fn_lock->flk_lock);
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 		break;
14307c478bd9Sstevel@tonic-gate 	default:
14317c478bd9Sstevel@tonic-gate 		break;
14327c478bd9Sstevel@tonic-gate 	}
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	return (error);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate /*
14387c478bd9Sstevel@tonic-gate  * If shadowing a vnode (FIFOs), apply the VOP_GETATTR to the shadowed
14397c478bd9Sstevel@tonic-gate  * vnode to Obtain the node information. If not shadowing (pipes), obtain
14407c478bd9Sstevel@tonic-gate  * the node information from the credentials structure.
14417c478bd9Sstevel@tonic-gate  */
14427c478bd9Sstevel@tonic-gate int
1443da6c28aaSamw fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
1444da6c28aaSamw 	caller_context_t *ct)
14457c478bd9Sstevel@tonic-gate {
14467c478bd9Sstevel@tonic-gate 	int		error		= 0;
14477c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp		= VTOF(vp);
14487c478bd9Sstevel@tonic-gate 	queue_t		*qp;
14497c478bd9Sstevel@tonic-gate 	qband_t		*bandp;
14507c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock	= fnp->fn_lock;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	if (fnp->fn_realvp) {
14537c478bd9Sstevel@tonic-gate 		/*
14547c478bd9Sstevel@tonic-gate 		 * for FIFOs or mounted pipes
14557c478bd9Sstevel@tonic-gate 		 */
1456da6c28aaSamw 		if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp, ct))
14577c478bd9Sstevel@tonic-gate 			return (error);
14587c478bd9Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
14597c478bd9Sstevel@tonic-gate 		/* set current times from fnode, even if older than vnode */
14607c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = fnp->fn_atime;
14617c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = 0;
14627c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_sec = fnp->fn_mtime;
14637c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = 0;
14647c478bd9Sstevel@tonic-gate 		vap->va_ctime.tv_sec = fnp->fn_ctime;
14657c478bd9Sstevel@tonic-gate 		vap->va_ctime.tv_nsec = 0;
14667c478bd9Sstevel@tonic-gate 	} else {
14677c478bd9Sstevel@tonic-gate 		/*
14687c478bd9Sstevel@tonic-gate 		 * for non-attached/ordinary pipes
14697c478bd9Sstevel@tonic-gate 		 */
14707c478bd9Sstevel@tonic-gate 		vap->va_mode = 0;
14717c478bd9Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
14727c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = fnp->fn_atime;
14737c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = 0;
14747c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_sec = fnp->fn_mtime;
14757c478bd9Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = 0;
14767c478bd9Sstevel@tonic-gate 		vap->va_ctime.tv_sec = fnp->fn_ctime;
14777c478bd9Sstevel@tonic-gate 		vap->va_ctime.tv_nsec = 0;
14787c478bd9Sstevel@tonic-gate 		vap->va_uid = crgetuid(crp);
14797c478bd9Sstevel@tonic-gate 		vap->va_gid = crgetgid(crp);
14807c478bd9Sstevel@tonic-gate 		vap->va_nlink = 0;
14817c478bd9Sstevel@tonic-gate 		vap->va_fsid = fifodev;
14827c478bd9Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)fnp->fn_ino;
14837c478bd9Sstevel@tonic-gate 		vap->va_rdev = 0;
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate 	vap->va_type = VFIFO;
14867c478bd9Sstevel@tonic-gate 	vap->va_blksize = PIPE_BUF;
14877c478bd9Sstevel@tonic-gate 	/*
14887c478bd9Sstevel@tonic-gate 	 * Size is number of un-read bytes at the stream head and
14897c478bd9Sstevel@tonic-gate 	 * nblocks is the unread bytes expressed in blocks.
14907c478bd9Sstevel@tonic-gate 	 */
14917c478bd9Sstevel@tonic-gate 	if (vp->v_stream && (fnp->fn_flag & FIFOISOPEN)) {
14927c478bd9Sstevel@tonic-gate 		if ((fnp->fn_flag & FIFOFAST)) {
14937c478bd9Sstevel@tonic-gate 			vap->va_size = (u_offset_t)fnp->fn_count;
14947c478bd9Sstevel@tonic-gate 		} else {
14957c478bd9Sstevel@tonic-gate 			qp = RD((strvp2wq(vp)));
14967c478bd9Sstevel@tonic-gate 			vap->va_size = (u_offset_t)qp->q_count;
14977c478bd9Sstevel@tonic-gate 			if (qp->q_nband != 0) {
14987c478bd9Sstevel@tonic-gate 				mutex_enter(QLOCK(qp));
14997c478bd9Sstevel@tonic-gate 				for (bandp = qp->q_bandp; bandp;
15007c478bd9Sstevel@tonic-gate 				    bandp = bandp->qb_next)
15017c478bd9Sstevel@tonic-gate 					vap->va_size += bandp->qb_count;
15027c478bd9Sstevel@tonic-gate 				mutex_exit(QLOCK(qp));
15037c478bd9Sstevel@tonic-gate 			}
15047c478bd9Sstevel@tonic-gate 		}
15057c478bd9Sstevel@tonic-gate 		vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
15067c478bd9Sstevel@tonic-gate 	} else {
15077c478bd9Sstevel@tonic-gate 		vap->va_size = (u_offset_t)0;
15087c478bd9Sstevel@tonic-gate 		vap->va_nblocks = (fsblkcnt64_t)0;
15097c478bd9Sstevel@tonic-gate 	}
15107c478bd9Sstevel@tonic-gate 	mutex_exit(&fn_lock->flk_lock);
15117c478bd9Sstevel@tonic-gate 	vap->va_seq = 0;
15127c478bd9Sstevel@tonic-gate 	return (0);
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate /*
15167c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply the VOP_SETATTR to it, and to the fnode.
15177c478bd9Sstevel@tonic-gate  * Otherwise, set the time and return 0.
15187c478bd9Sstevel@tonic-gate  */
15197c478bd9Sstevel@tonic-gate int
15207c478bd9Sstevel@tonic-gate fifo_setattr(
15217c478bd9Sstevel@tonic-gate 	vnode_t			*vp,
15227c478bd9Sstevel@tonic-gate 	vattr_t			*vap,
15237c478bd9Sstevel@tonic-gate 	int			flags,
15247c478bd9Sstevel@tonic-gate 	cred_t			*crp,
15257c478bd9Sstevel@tonic-gate 	caller_context_t	*ctp)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp	= VTOF(vp);
15287c478bd9Sstevel@tonic-gate 	int		error	= 0;
15297c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock;
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	if (fnp->fn_realvp)
15327c478bd9Sstevel@tonic-gate 		error = VOP_SETATTR(fnp->fn_realvp, vap, flags, crp, ctp);
15337c478bd9Sstevel@tonic-gate 	if (error == 0) {
15347c478bd9Sstevel@tonic-gate 		fn_lock = fnp->fn_lock;
15357c478bd9Sstevel@tonic-gate 		mutex_enter(&fn_lock->flk_lock);
15367c478bd9Sstevel@tonic-gate 		if (vap->va_mask & AT_ATIME)
15377c478bd9Sstevel@tonic-gate 			fnp->fn_atime = vap->va_atime.tv_sec;
15387c478bd9Sstevel@tonic-gate 		if (vap->va_mask & AT_MTIME)
15397c478bd9Sstevel@tonic-gate 			fnp->fn_mtime = vap->va_mtime.tv_sec;
15407c478bd9Sstevel@tonic-gate 		fnp->fn_ctime = gethrestime_sec();
15417c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 	return (error);
15447c478bd9Sstevel@tonic-gate }
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate /*
15477c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply VOP_ACCESS to it.
15487c478bd9Sstevel@tonic-gate  * Otherwise, return 0 (allow all access).
15497c478bd9Sstevel@tonic-gate  */
15507c478bd9Sstevel@tonic-gate int
1551da6c28aaSamw fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp, caller_context_t *ct)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate 	if (VTOF(vp)->fn_realvp)
1554da6c28aaSamw 		return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp, ct));
15557c478bd9Sstevel@tonic-gate 	else
15567c478bd9Sstevel@tonic-gate 		return (0);
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate /*
15609acbbeafSnn35248  * This can be called if creat or an open with O_CREAT is done on the root
15619acbbeafSnn35248  * of a lofs mount where the mounted entity is a fifo.
15629acbbeafSnn35248  */
15639acbbeafSnn35248 /*ARGSUSED*/
15649acbbeafSnn35248 static int
15659acbbeafSnn35248 fifo_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
1566da6c28aaSamw     int mode, struct vnode **vpp, struct cred *cr, int flag,
1567da6c28aaSamw     caller_context_t *ct, vsecattr_t *vsecp)
15689acbbeafSnn35248 {
15699acbbeafSnn35248 	int error;
15709acbbeafSnn35248 
15719acbbeafSnn35248 	ASSERT(dvp && (dvp->v_flag & VROOT) && *name == '\0');
15729acbbeafSnn35248 	if (excl == NONEXCL) {
1573da6c28aaSamw 		if (mode && (error = fifo_access(dvp, mode, 0, cr, ct)))
15749acbbeafSnn35248 			return (error);
15759acbbeafSnn35248 		VN_HOLD(dvp);
15769acbbeafSnn35248 		return (0);
15779acbbeafSnn35248 	}
15789acbbeafSnn35248 	return (EEXIST);
15799acbbeafSnn35248 }
15809acbbeafSnn35248 
15819acbbeafSnn35248 /*
15827c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply the VOP_FSYNC to it.
15837c478bd9Sstevel@tonic-gate  * Otherwise, return 0.
15847c478bd9Sstevel@tonic-gate  */
15857c478bd9Sstevel@tonic-gate int
1586da6c28aaSamw fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
15877c478bd9Sstevel@tonic-gate {
15887c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp	= VTOF(vp);
15897c478bd9Sstevel@tonic-gate 	vattr_t		va;
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	if (fnp->fn_realvp == NULL)
15927c478bd9Sstevel@tonic-gate 		return (0);
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&va, sizeof (va));
15957c478bd9Sstevel@tonic-gate 	va.va_mask = AT_MTIME | AT_ATIME;
1596da6c28aaSamw 	if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp, ct) == 0) {
15977c478bd9Sstevel@tonic-gate 		va.va_mask = 0;
15987c478bd9Sstevel@tonic-gate 		if (fnp->fn_mtime > va.va_mtime.tv_sec) {
15997c478bd9Sstevel@tonic-gate 			va.va_mtime.tv_sec = fnp->fn_mtime;
16007c478bd9Sstevel@tonic-gate 			va.va_mask = AT_MTIME;
16017c478bd9Sstevel@tonic-gate 		}
16027c478bd9Sstevel@tonic-gate 		if (fnp->fn_atime > va.va_atime.tv_sec) {
16037c478bd9Sstevel@tonic-gate 			va.va_atime.tv_sec = fnp->fn_atime;
16047c478bd9Sstevel@tonic-gate 			va.va_mask |= AT_ATIME;
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		if (va.va_mask != 0)
1607da6c28aaSamw 			(void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, ct);
16087c478bd9Sstevel@tonic-gate 	}
1609da6c28aaSamw 	return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp, ct));
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate /*
16137c478bd9Sstevel@tonic-gate  * Called when the upper level no longer holds references to the
16147c478bd9Sstevel@tonic-gate  * vnode. Sync the file system and free the fifonode.
16157c478bd9Sstevel@tonic-gate  */
16167c478bd9Sstevel@tonic-gate void
1617da6c28aaSamw fifo_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
16187c478bd9Sstevel@tonic-gate {
16197c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp;
16207c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	mutex_enter(&ftable_lock);
16237c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
16247c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
16257c478bd9Sstevel@tonic-gate 	if (--vp->v_count != 0) {
16267c478bd9Sstevel@tonic-gate 		/*
16277c478bd9Sstevel@tonic-gate 		 * Somebody accessed the fifo before we got a chance to
16287c478bd9Sstevel@tonic-gate 		 * remove it.  They will remove it when they do a vn_rele.
16297c478bd9Sstevel@tonic-gate 		 */
16307c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
16317c478bd9Sstevel@tonic-gate 		mutex_exit(&ftable_lock);
16327c478bd9Sstevel@tonic-gate 		return;
16337c478bd9Sstevel@tonic-gate 	}
16347c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	fnp = VTOF(vp);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	/*
16397c478bd9Sstevel@tonic-gate 	 * remove fifo from fifo list so that no other process
16407c478bd9Sstevel@tonic-gate 	 * can grab it.
1641132c40dcSbpramod 	 * Drop the reference count on the fifo node's
1642132c40dcSbpramod 	 * underlying vfs.
16437c478bd9Sstevel@tonic-gate 	 */
16447c478bd9Sstevel@tonic-gate 	if (fnp->fn_realvp) {
16457c478bd9Sstevel@tonic-gate 		(void) fiforemove(fnp);
16467c478bd9Sstevel@tonic-gate 		mutex_exit(&ftable_lock);
1647da6c28aaSamw 		(void) fifo_fsync(vp, FSYNC, crp, ct);
16487c478bd9Sstevel@tonic-gate 		VN_RELE(fnp->fn_realvp);
1649132c40dcSbpramod 		VFS_RELE(vp->v_vfsp);
16507c478bd9Sstevel@tonic-gate 		vp->v_vfsp = NULL;
16517c478bd9Sstevel@tonic-gate 	} else
16527c478bd9Sstevel@tonic-gate 		mutex_exit(&ftable_lock);
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	fn_lock = fnp->fn_lock;
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	mutex_enter(&fn_lock->flk_lock);
16577c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream == NULL);
16587c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count == 0);
16597c478bd9Sstevel@tonic-gate 	/*
16607c478bd9Sstevel@tonic-gate 	 * if this is last reference to the lock, then we can
16617c478bd9Sstevel@tonic-gate 	 * free everything up.
16627c478bd9Sstevel@tonic-gate 	 */
16637c478bd9Sstevel@tonic-gate 	if (--fn_lock->flk_ref == 0) {
16647c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
16657c478bd9Sstevel@tonic-gate 		ASSERT(fnp->fn_open == 0);
16667c478bd9Sstevel@tonic-gate 		ASSERT(fnp->fn_dest->fn_open == 0);
16677c478bd9Sstevel@tonic-gate 		if (fnp->fn_mp) {
16687c478bd9Sstevel@tonic-gate 			freemsg(fnp->fn_mp);
16697c478bd9Sstevel@tonic-gate 			fnp->fn_mp = NULL;
16707c478bd9Sstevel@tonic-gate 			fnp->fn_count = 0;
16717c478bd9Sstevel@tonic-gate 		}
16727c478bd9Sstevel@tonic-gate 		if (fnp->fn_pcredp != NULL) {
16737c478bd9Sstevel@tonic-gate 			crfree(fnp->fn_pcredp);
16747c478bd9Sstevel@tonic-gate 			fnp->fn_pcredp = NULL;
16757c478bd9Sstevel@tonic-gate 		}
16767c478bd9Sstevel@tonic-gate 		if (fnp->fn_flag & ISPIPE) {
16777c478bd9Sstevel@tonic-gate 			fifonode_t *fn_dest = fnp->fn_dest;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 			vp = FTOV(fn_dest);
16807c478bd9Sstevel@tonic-gate 			if (fn_dest->fn_mp) {
16817c478bd9Sstevel@tonic-gate 				freemsg(fn_dest->fn_mp);
16827c478bd9Sstevel@tonic-gate 				fn_dest->fn_mp = NULL;
16837c478bd9Sstevel@tonic-gate 				fn_dest->fn_count = 0;
16847c478bd9Sstevel@tonic-gate 			}
16857c478bd9Sstevel@tonic-gate 			if (fn_dest->fn_pcredp != NULL) {
16867c478bd9Sstevel@tonic-gate 				crfree(fn_dest->fn_pcredp);
16877c478bd9Sstevel@tonic-gate 				fn_dest->fn_pcredp = NULL;
16887c478bd9Sstevel@tonic-gate 			}
16897c478bd9Sstevel@tonic-gate 			kmem_cache_free(pipe_cache, (fifodata_t *)fn_lock);
16907c478bd9Sstevel@tonic-gate 		} else
16917c478bd9Sstevel@tonic-gate 			kmem_cache_free(fnode_cache, (fifodata_t *)fn_lock);
16927c478bd9Sstevel@tonic-gate 	} else {
16937c478bd9Sstevel@tonic-gate 		mutex_exit(&fn_lock->flk_lock);
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate /*
16987c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply the VOP_FID to it.
16997c478bd9Sstevel@tonic-gate  * Otherwise, return EINVAL.
17007c478bd9Sstevel@tonic-gate  */
17017c478bd9Sstevel@tonic-gate int
1702da6c28aaSamw fifo_fid(vnode_t *vp, fid_t *fidfnp, caller_context_t *ct)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	if (VTOF(vp)->fn_realvp)
1705da6c28aaSamw 		return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp, ct));
17067c478bd9Sstevel@tonic-gate 	else
17077c478bd9Sstevel@tonic-gate 		return (EINVAL);
17087c478bd9Sstevel@tonic-gate }
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate /*
17117c478bd9Sstevel@tonic-gate  * Lock a fifonode.
17127c478bd9Sstevel@tonic-gate  */
17137c478bd9Sstevel@tonic-gate /* ARGSUSED */
17147c478bd9Sstevel@tonic-gate int
17157c478bd9Sstevel@tonic-gate fifo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate 	return (-1);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate /*
17217c478bd9Sstevel@tonic-gate  * Unlock a fifonode.
17227c478bd9Sstevel@tonic-gate  */
17237c478bd9Sstevel@tonic-gate /* ARGSUSED */
17247c478bd9Sstevel@tonic-gate void
17257c478bd9Sstevel@tonic-gate fifo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
17267c478bd9Sstevel@tonic-gate {
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate /*
17307c478bd9Sstevel@tonic-gate  * Return error since seeks are not allowed on pipes.
17317c478bd9Sstevel@tonic-gate  */
17327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17337c478bd9Sstevel@tonic-gate int
1734da6c28aaSamw fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
17357c478bd9Sstevel@tonic-gate {
17367c478bd9Sstevel@tonic-gate 	return (ESPIPE);
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate  * If there is a realvp associated with vp, return it.
17417c478bd9Sstevel@tonic-gate  */
17427c478bd9Sstevel@tonic-gate int
1743da6c28aaSamw fifo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
17447c478bd9Sstevel@tonic-gate {
17457c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	if ((rvp = VTOF(vp)->fn_realvp) != NULL) {
17487c478bd9Sstevel@tonic-gate 		vp = rvp;
1749da6c28aaSamw 		if (VOP_REALVP(vp, &rvp, ct) == 0)
17507c478bd9Sstevel@tonic-gate 			vp = rvp;
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	*vpp = vp;
17547c478bd9Sstevel@tonic-gate 	return (0);
17557c478bd9Sstevel@tonic-gate }
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate /*
17587c478bd9Sstevel@tonic-gate  * Poll for interesting events on a stream pipe
17597c478bd9Sstevel@tonic-gate  */
1760da6c28aaSamw /* ARGSUSED */
17617c478bd9Sstevel@tonic-gate int
17627c478bd9Sstevel@tonic-gate fifo_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
1763da6c28aaSamw 	pollhead_t **phpp, caller_context_t *ct)
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate 	fifonode_t	*fnp, *fn_dest;
17667c478bd9Sstevel@tonic-gate 	fifolock_t	*fn_lock;
17677c478bd9Sstevel@tonic-gate 	int		retevents;
17687c478bd9Sstevel@tonic-gate 	struct stdata	*stp;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_stream != NULL);
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
17737c478bd9Sstevel@tonic-gate 	retevents	= 0;
17747c478bd9Sstevel@tonic-gate 	fnp		= VTOF(vp);
17757c478bd9Sstevel@tonic-gate 	fn_dest		= fnp->fn_dest;
17767c478bd9Sstevel@tonic-gate 	fn_lock		= fnp->fn_lock;
17777c478bd9Sstevel@tonic-gate 
1778*f3bb54f3SPatrick Mooney 	if (polllock(&stp->sd_pollist, &fn_lock->flk_lock) != 0) {
1779*f3bb54f3SPatrick Mooney 		*reventsp = POLLNVAL;
1780*f3bb54f3SPatrick Mooney 		return (0);
1781*f3bb54f3SPatrick Mooney 	}
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	/*
17847c478bd9Sstevel@tonic-gate 	 * see if FIFO/pipe open
17857c478bd9Sstevel@tonic-gate 	 */
17867c478bd9Sstevel@tonic-gate 	if ((fnp->fn_flag & FIFOISOPEN) == 0) {
17877c478bd9Sstevel@tonic-gate 		if (((events & (POLLIN | POLLRDNORM | POLLPRI | POLLRDBAND)) &&
17887c478bd9Sstevel@tonic-gate 		    fnp->fn_rcnt == 0) ||
17897c478bd9Sstevel@tonic-gate 		    ((events & (POLLWRNORM | POLLWRBAND)) &&
17907c478bd9Sstevel@tonic-gate 		    fnp->fn_wcnt == 0)) {
17917c478bd9Sstevel@tonic-gate 			mutex_exit(&fnp->fn_lock->flk_lock);
17927c478bd9Sstevel@tonic-gate 			*reventsp = POLLERR;
17937c478bd9Sstevel@tonic-gate 			return (0);
17947c478bd9Sstevel@tonic-gate 		}
17957c478bd9Sstevel@tonic-gate 	}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	/*
17987c478bd9Sstevel@tonic-gate 	 * if not in fast mode, let the stream head take care of it
17997c478bd9Sstevel@tonic-gate 	 */
18007c478bd9Sstevel@tonic-gate 	if (!(fnp->fn_flag & FIFOFAST)) {
18017c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock->flk_lock);
18027c478bd9Sstevel@tonic-gate 		goto stream_mode;
18037c478bd9Sstevel@tonic-gate 	}
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	/*
18067c478bd9Sstevel@tonic-gate 	 * If this is a pipe.. check to see if the other
18077c478bd9Sstevel@tonic-gate 	 * end is gone.  If we are a fifo, check to see
18087c478bd9Sstevel@tonic-gate 	 * if write end is gone.
18097c478bd9Sstevel@tonic-gate 	 */
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	if ((fnp->fn_flag & ISPIPE) && (fn_dest->fn_open == 0)) {
18127c478bd9Sstevel@tonic-gate 		retevents = POLLHUP;
18137c478bd9Sstevel@tonic-gate 	} else if ((fnp->fn_flag & (FIFOCLOSE | ISPIPE)) == FIFOCLOSE &&
18147c478bd9Sstevel@tonic-gate 	    (fn_dest->fn_wcnt == 0)) {
18157c478bd9Sstevel@tonic-gate 		/*
18167c478bd9Sstevel@tonic-gate 		 * no writer at other end.
18177c478bd9Sstevel@tonic-gate 		 * it was closed (versus yet to be opened)
18187c478bd9Sstevel@tonic-gate 		 */
18197c478bd9Sstevel@tonic-gate 			retevents = POLLHUP;
18207c478bd9Sstevel@tonic-gate 	} else if (events & (POLLWRNORM | POLLWRBAND)) {
18217c478bd9Sstevel@tonic-gate 		if (events & POLLWRNORM) {
18227c478bd9Sstevel@tonic-gate 			if (fn_dest->fn_count < Fifohiwat)
18237c478bd9Sstevel@tonic-gate 				retevents = POLLWRNORM;
18247c478bd9Sstevel@tonic-gate 			else
18257c478bd9Sstevel@tonic-gate 				fnp->fn_flag |= FIFOHIWATW;
18267c478bd9Sstevel@tonic-gate 		}
18277c478bd9Sstevel@tonic-gate 		/*
18287c478bd9Sstevel@tonic-gate 		 * This is always true for fast pipes
18297c478bd9Sstevel@tonic-gate 		 * (Note: will go to STREAMS mode if band data is written)
18307c478bd9Sstevel@tonic-gate 		 */
18317c478bd9Sstevel@tonic-gate 		if (events & POLLWRBAND)
18327c478bd9Sstevel@tonic-gate 			retevents |= POLLWRBAND;
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 	if (events & (POLLIN | POLLRDNORM)) {
18357c478bd9Sstevel@tonic-gate 		if (fnp->fn_count)
18367c478bd9Sstevel@tonic-gate 			retevents |= (events & (POLLIN | POLLRDNORM));
18377c478bd9Sstevel@tonic-gate 	}
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	/*
1840a5eb7107SBryan Cantrill 	 * if we happened to get something and we're not edge-triggered, return
18417c478bd9Sstevel@tonic-gate 	 */
1842a5eb7107SBryan Cantrill 	if ((*reventsp = (short)retevents) != 0 && !(events & POLLET)) {
18437c478bd9Sstevel@tonic-gate 		mutex_exit(&fnp->fn_lock->flk_lock);
18447c478bd9Sstevel@tonic-gate 		return (0);
18457c478bd9Sstevel@tonic-gate 	}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	/*
1848a5eb7107SBryan Cantrill 	 * If poll() has not found any events yet or we're edge-triggered, set
1849a5eb7107SBryan Cantrill 	 * up event cell to wake up the poll if a requested event occurs on this
18507c478bd9Sstevel@tonic-gate 	 * pipe/fifo.
18517c478bd9Sstevel@tonic-gate 	 */
18527c478bd9Sstevel@tonic-gate 	if (!anyyet) {
18537c478bd9Sstevel@tonic-gate 		if (events & POLLWRNORM)
18547c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOPOLLW;
18557c478bd9Sstevel@tonic-gate 		if (events & (POLLIN | POLLRDNORM))
18567c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOPOLLR;
18577c478bd9Sstevel@tonic-gate 		if (events & POLLRDBAND)
18587c478bd9Sstevel@tonic-gate 			fnp->fn_flag |= FIFOPOLLRBAND;
18597c478bd9Sstevel@tonic-gate 		/*
18607c478bd9Sstevel@tonic-gate 		 * XXX Don't like exposing this from streams
18617c478bd9Sstevel@tonic-gate 		 */
18627c478bd9Sstevel@tonic-gate 		*phpp = &stp->sd_pollist;
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 	mutex_exit(&fnp->fn_lock->flk_lock);
18657c478bd9Sstevel@tonic-gate 	return (0);
18667c478bd9Sstevel@tonic-gate stream_mode:
18677c478bd9Sstevel@tonic-gate 	return (strpoll(stp, events, anyyet, reventsp, phpp));
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate /*
18717c478bd9Sstevel@tonic-gate  * POSIX pathconf() support.
18727c478bd9Sstevel@tonic-gate  */
18737c478bd9Sstevel@tonic-gate /* ARGSUSED */
18747c478bd9Sstevel@tonic-gate int
1875da6c28aaSamw fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1876da6c28aaSamw 	caller_context_t *ct)
18777c478bd9Sstevel@tonic-gate {
18787c478bd9Sstevel@tonic-gate 	ulong_t val;
18797c478bd9Sstevel@tonic-gate 	int error = 0;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	switch (cmd) {
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	case _PC_LINK_MAX:
18847c478bd9Sstevel@tonic-gate 		val = MAXLINK;
18857c478bd9Sstevel@tonic-gate 		break;
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	case _PC_MAX_CANON:
18887c478bd9Sstevel@tonic-gate 		val = MAX_CANON;
18897c478bd9Sstevel@tonic-gate 		break;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	case _PC_MAX_INPUT:
18927c478bd9Sstevel@tonic-gate 		val = MAX_INPUT;
18937c478bd9Sstevel@tonic-gate 		break;
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	case _PC_NAME_MAX:
18967c478bd9Sstevel@tonic-gate 		error = EINVAL;
18977c478bd9Sstevel@tonic-gate 		break;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	case _PC_PATH_MAX:
19007c478bd9Sstevel@tonic-gate 	case _PC_SYMLINK_MAX:
19017c478bd9Sstevel@tonic-gate 		val = MAXPATHLEN;
19027c478bd9Sstevel@tonic-gate 		break;
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	case _PC_PIPE_BUF:
19057c478bd9Sstevel@tonic-gate 		val = PIPE_BUF;
19067c478bd9Sstevel@tonic-gate 		break;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	case _PC_NO_TRUNC:
19097c478bd9Sstevel@tonic-gate 		if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
19107c478bd9Sstevel@tonic-gate 			val = 1;	/* NOTRUNC is enabled for vp */
19117c478bd9Sstevel@tonic-gate 		else
19127c478bd9Sstevel@tonic-gate 			val = (ulong_t)-1;
19137c478bd9Sstevel@tonic-gate 		break;
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	case _PC_VDISABLE:
19167c478bd9Sstevel@tonic-gate 		val = _POSIX_VDISABLE;
19177c478bd9Sstevel@tonic-gate 		break;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	case _PC_CHOWN_RESTRICTED:
19207c478bd9Sstevel@tonic-gate 		if (rstchown)
19217c478bd9Sstevel@tonic-gate 			val = rstchown;		/* chown restricted enabled */
19227c478bd9Sstevel@tonic-gate 		else
19237c478bd9Sstevel@tonic-gate 			val = (ulong_t)-1;
19247c478bd9Sstevel@tonic-gate 		break;
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	case _PC_FILESIZEBITS:
19277c478bd9Sstevel@tonic-gate 		val = (ulong_t)-1;
19287c478bd9Sstevel@tonic-gate 		break;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	default:
19317c478bd9Sstevel@tonic-gate 		if (VTOF(vp)->fn_realvp)
19327c478bd9Sstevel@tonic-gate 			error = VOP_PATHCONF(VTOF(vp)->fn_realvp, cmd,
1933da6c28aaSamw 			    &val, cr, ct);
19347c478bd9Sstevel@tonic-gate 		else
19357c478bd9Sstevel@tonic-gate 			error = EINVAL;
19367c478bd9Sstevel@tonic-gate 		break;
19377c478bd9Sstevel@tonic-gate 	}
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	if (error == 0)
19407c478bd9Sstevel@tonic-gate 		*valp = val;
19417c478bd9Sstevel@tonic-gate 	return (error);
19427c478bd9Sstevel@tonic-gate }
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate /*
19457c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply VOP_SETSECATTR to it.
19467c478bd9Sstevel@tonic-gate  * Otherwise, return NOSYS.
19477c478bd9Sstevel@tonic-gate  */
19487c478bd9Sstevel@tonic-gate int
1949da6c28aaSamw fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
1950da6c28aaSamw 	caller_context_t *ct)
19517c478bd9Sstevel@tonic-gate {
19527c478bd9Sstevel@tonic-gate 	int error;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	/*
19557c478bd9Sstevel@tonic-gate 	 * The acl(2) system call tries to grab the write lock on the
19567c478bd9Sstevel@tonic-gate 	 * file when setting an ACL, but fifofs does not implement
19577c478bd9Sstevel@tonic-gate 	 * VOP_RWLOCK or VOP_RWUNLOCK, so we do it here instead.
19587c478bd9Sstevel@tonic-gate 	 */
19597c478bd9Sstevel@tonic-gate 	if (VTOF(vp)->fn_realvp) {
1960da6c28aaSamw 		(void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
1961da6c28aaSamw 		error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
1962da6c28aaSamw 		    crp, ct);
1963da6c28aaSamw 		VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
19647c478bd9Sstevel@tonic-gate 		return (error);
19657c478bd9Sstevel@tonic-gate 	} else
19667c478bd9Sstevel@tonic-gate 		return (fs_nosys());
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate /*
19707c478bd9Sstevel@tonic-gate  * If shadowing a vnode, apply VOP_GETSECATTR to it. Otherwise, fabricate
19717c478bd9Sstevel@tonic-gate  * an ACL from the permission bits that fifo_getattr() makes up.
19727c478bd9Sstevel@tonic-gate  */
19737c478bd9Sstevel@tonic-gate int
1974da6c28aaSamw fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
1975da6c28aaSamw 	caller_context_t *ct)
19767c478bd9Sstevel@tonic-gate {
19777c478bd9Sstevel@tonic-gate 	if (VTOF(vp)->fn_realvp)
1978da6c28aaSamw 		return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
1979da6c28aaSamw 		    crp, ct));
19807c478bd9Sstevel@tonic-gate 	else
1981da6c28aaSamw 		return (fs_fab_acl(vp, vsap, flag, crp, ct));
19827c478bd9Sstevel@tonic-gate }
198339cba716Swroche 
198439cba716Swroche 
198539cba716Swroche /*
198639cba716Swroche  * Set the FIFOSTAYFAST flag so nobody can turn the fifo into stream mode.
198739cba716Swroche  * If the flag is already set then wait until it is removed - releasing
198839cba716Swroche  * the lock.
198939cba716Swroche  * If the fifo switches into stream mode while we are waiting, return failure.
199039cba716Swroche  */
199139cba716Swroche static boolean_t
199239cba716Swroche fifo_stayfast_enter(fifonode_t *fnp)
199339cba716Swroche {
199439cba716Swroche 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
199539cba716Swroche 	while (fnp->fn_flag & FIFOSTAYFAST) {
199639cba716Swroche 		fnp->fn_flag |= FIFOWAITMODE;
199739cba716Swroche 		cv_wait(&fnp->fn_wait_cv, &fnp->fn_lock->flk_lock);
199839cba716Swroche 		fnp->fn_flag &= ~FIFOWAITMODE;
199939cba716Swroche 	}
200039cba716Swroche 	if (!(fnp->fn_flag & FIFOFAST))
200139cba716Swroche 		return (B_FALSE);
200239cba716Swroche 
200339cba716Swroche 	fnp->fn_flag |= FIFOSTAYFAST;
200439cba716Swroche 	return (B_TRUE);
200539cba716Swroche }
200639cba716Swroche 
200739cba716Swroche /*
200839cba716Swroche  * Unset the FIFOSTAYFAST flag and notify anybody waiting for this flag
200939cba716Swroche  * to be removed:
201039cba716Swroche  *	- threads wanting to turn into stream mode waiting in fifo_fastoff(),
201139cba716Swroche  *	- other writers threads waiting in fifo_stayfast_enter().
201239cba716Swroche  */
201339cba716Swroche static void
201439cba716Swroche fifo_stayfast_exit(fifonode_t *fnp)
201539cba716Swroche {
201639cba716Swroche 	fifonode_t *fn_dest = fnp->fn_dest;
201739cba716Swroche 
201839cba716Swroche 	ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
201939cba716Swroche 
202039cba716Swroche 	fnp->fn_flag &= ~FIFOSTAYFAST;
202139cba716Swroche 
202239cba716Swroche 	if (fnp->fn_flag & FIFOWAITMODE)
202339cba716Swroche 		cv_broadcast(&fnp->fn_wait_cv);
202439cba716Swroche 
202539cba716Swroche 	if ((fnp->fn_flag & ISPIPE) && (fn_dest->fn_flag & FIFOWAITMODE))
202639cba716Swroche 		cv_broadcast(&fn_dest->fn_wait_cv);
202739cba716Swroche }
2028