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