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