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