fifovnops.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * CDDL HEADER START
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * The contents of this file are subject to the terms of the
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Common Development and Distribution License, Version 1.0 only
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (the "License"). You may not use this file except in compliance
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * with the License.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * or http://www.opensolaris.org/os/licensing.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * See the License for the specific language governing permissions
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and limitations under the License.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * When distributing Covered Code, include this CDDL HEADER in each
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If applicable, add the following below this CDDL HEADER, with the
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner]
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * CDDL HEADER END
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/* All rights reserved. */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Use is subject to license terms.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#pragma ident "%Z%%M% %I% %E% SMI"
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * FIFOFS file system vnode operations. This file system
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * type supports STREAMS-based pipes and FIFOs.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/types.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/param.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/systm.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/sysmacros.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/cred.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/errno.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/time.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/file.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/fcntl.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/kmem.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/uio.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/vfs.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/vnode.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/signal.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/user.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/strsubr.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/stream.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/strsun.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/strredir.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/fs/fifonode.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/fs/namenode.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/stropts.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/proc.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/unistd.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/debug.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <fs/fs_subr.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/filio.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/termio.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/ddi.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/vtrace.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#include <sys/policy.h>
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Define the routines/data structures used in this file.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_write(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_setattr(vnode_t *, vattr_t *, int, cred_t *,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland caller_context_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_realvp(vnode_t *, vnode_t **);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_access(vnode_t *, int, int, cred_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_fid(vnode_t *, fid_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_fsync(vnode_t *, int, cred_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_seek(vnode_t *, offset_t, offset_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_fastioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_strioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_poll(vnode_t *, short, int, short *, pollhead_t **);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic void fifo_inactive(vnode_t *, cred_t *);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9okstatic int fifo_rwlock(vnode_t *, int, caller_context_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic void fifo_rwunlock(vnode_t *, int, caller_context_t *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Define the data structures external to this file.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandextern dev_t fifodev;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandextern struct qinit fifo_stwdata;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandextern struct qinit fifo_strdata;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandextern kmutex_t ftable_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstruct streamtab fifoinfo = { &fifo_strdata, &fifo_stwdata, NULL, NULL };
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstruct vnodeops *fifo_vnodeops;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandconst fs_operation_def_t fifo_vnodeops_template[] = {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_OPEN, fifo_open,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_CLOSE, fifo_close,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_READ, fifo_read,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_WRITE, fifo_write,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_IOCTL, fifo_ioctl,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_GETATTR, fifo_getattr,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_SETATTR, fifo_setattr,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_ACCESS, fifo_access,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_FSYNC, fifo_fsync,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_INACTIVE, (fs_generic_func_p) fifo_inactive,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_FID, fifo_fid,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_RWLOCK, fifo_rwlock,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_RWUNLOCK, (fs_generic_func_p) fifo_rwunlock,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_SEEK, fifo_seek,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_REALVP, fifo_realvp,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_POLL, (fs_generic_func_p) fifo_poll,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_PATHCONF, fifo_pathconf,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_DISPOSE, fs_error,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_SETSECATTR, fifo_setsecattr,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland VOPNAME_GETSECATTR, fifo_getsecattr,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland NULL, NULL
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland};
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Return the fifoinfo structure.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstruct streamtab *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandfifo_getinfo()
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland{
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (&fifoinfo);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland}
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Open and stream a FIFO.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If this is the first open of the file (FIFO is not streaming),
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * initialize the fifonode and attach a stream to the vnode.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Each end of a fifo must be synchronized with the other end.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If not, the mated end may complete an open, I/O, close sequence
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * before the end waiting in open ever wakes up.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: namefs pipes come through this routine too.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandint
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandfifo_open(vnode_t **vpp, int flag, cred_t *crp)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland{
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland vnode_t *vp = *vpp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifonode_t *fnp = VTOF(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifolock_t *fn_lock = fnp->fn_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int error;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vp->v_type == VFIFO);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vn_matchops(vp, fifo_vnodeops));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If we are the first reader, wake up any writers that
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * may be waiting around. wait for all of them to
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wake up before proceeding (i.e. fn_wsynccnt == 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FREAD) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_rcnt++; /* record reader present */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (! (fnp->fn_flag & ISPIPE))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_rsynccnt++; /* record reader in open */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If we are the first writer, wake up any readers that
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * may be waiting around. wait for all of them to
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wake up before proceeding (i.e. fn_rsynccnt == 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FWRITE) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wcnt++; /* record writer present */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (! (fnp->fn_flag & ISPIPE))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wsynccnt++; /* record writer in open */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fifo_stropen will take care of twisting the queues on the first
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * open. The 1 being passed in means twist the queues on the first
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * open.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = fifo_stropen(vpp, flag, crp, 1, 1);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fifo_stropen() could have replaced vpp
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * since fifo's are the only thing we need to sync up,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * everything else just returns;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: don't need to hold lock since ISPIPE can't change
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and both old and new vp need to be pipes
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(MUTEX_HELD(&VTOF(*vpp)->fn_lock->flk_lock));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fnp->fn_flag & ISPIPE) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(VTOF(*vpp)->fn_flag & ISPIPE);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(VTOF(*vpp)->fn_rsynccnt == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(VTOF(*vpp)->fn_rsynccnt == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * XXX note: should probably hold locks, but
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * These values should not be changing
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_rsynccnt == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_wsynccnt == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&VTOF(*vpp)->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (error);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * vp can't change for FIFOS
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vp == *vpp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If we are opening for read (or writer)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * indicate that the reader (or writer) is done with open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * if there is a writer (or reader) waiting for us, wake them up
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and indicate that at least 1 read (or write) open has occured
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * this is need in the event the read (or write) side closes
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * before the writer (or reader) has a chance to wake up
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * i.e. it sees that a reader (or writer) was once there
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FREAD) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_rsynccnt--; /* reader done with open */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fnp->fn_flag & FIFOSYNC) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This indicates that a read open has occured
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Only need to set if writer is actually asleep
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Flag will be consumed by writer.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOROCR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fnp->fn_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FWRITE) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wsynccnt--; /* writer done with open */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fnp->fn_flag & FIFOSYNC) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This indicates that a write open has occured
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Only need to set if reader is actually asleep
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Flag will be consumed by reader.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOWOCR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fnp->fn_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag &= ~FIFOSYNC;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * errors don't wait around.. just return
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: XXX other end will wake up and continue despite error.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * There is no defined semantic on the correct course of option
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * so we do what we've done in the past
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (error != 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fnp->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_rsynccnt <= fnp->fn_rcnt);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_wsynccnt <= fnp->fn_wcnt);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * FIFOWOCR (or FIFOROCR) indicates that the writer (or reader)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * has woken us up and is done with open (this way, if the other
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * end has made it to close, we don't block forever in open)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fn_wnct == fn_wsynccnt (or fn_rcnt == fn_rsynccnt) indicates
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * that no writer (or reader) has yet made it through open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This has the side benifit of that the first
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * reader (or writer) will wait until the other end finishes open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FREAD) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland while ((fnp->fn_flag & FIFOWOCR) == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wcnt == fnp->fn_wsynccnt) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & (FNDELAY|FNONBLOCK)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fnp->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_insync++;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOSYNC;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland &fnp->fn_lock->flk_lock)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Last reader to wakeup clear writer
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Clear both writer and reader open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * occured flag incase other end is O_RDWR
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_insync == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag & FIFOWOCR) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fnp->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) fifo_close(*vpp, flag, 1, 0, crp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = EINTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Last reader to wakeup clear writer open occured flag
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Clear both writer and reader open occured flag
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * incase other end is O_RDWR
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_insync == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag & FIFOWOCR) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland break;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else if (flag & FWRITE) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland while ((fnp->fn_flag & FIFOROCR) == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_rcnt == fnp->fn_rsynccnt) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((flag & (FNDELAY|FNONBLOCK)) && fnp->fn_rcnt == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fnp->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) fifo_close(*vpp, flag, 1, 0, crp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = ENXIO;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOSYNC;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_insync++;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland &fnp->fn_lock->flk_lock)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Last writer to wakeup clear
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Clear both writer and reader open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * occured flag in case other end is O_RDWR
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_insync == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (fnp->fn_flag & FIFOROCR) != 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fnp->fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) fifo_close(*vpp, flag, 1, 0, crp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = EINTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Last writer to wakeup clear reader open occured flag
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Clear both writer and reader open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * occured flag in case other end is O_RDWR
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_insync == 0 &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (fnp->fn_flag & FIFOROCR) != 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland break;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlanddone:
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (error);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland}
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Close down a stream.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Call cleanlocks() and strclean() on every close.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * For last close send hangup message and force
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * the other end of a named pipe to be unmounted.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Mount guarantees that the mounted end will only call fifo_close()
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * with a count of 1 when the unmount occurs.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This routine will close down one end of a pipe or FIFO
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and free the stream head via strclose()
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*ARGSUSED*/
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandint
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandfifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland{
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifonode_t *fnp = VTOF(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifonode_t *fn_dest = fnp->fn_dest;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int error = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifolock_t *fn_lock = fnp->fn_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland queue_t *sd_wrq;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland vnode_t *fn_dest_vp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int senthang = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vp->v_stream != NULL);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * clean locks and clear events.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cleanshares(vp, ttoproc(curthread)->p_pid);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland strclean(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If a file still has the pipe/FIFO open, return.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (count > 1)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland sd_wrq = strvp2wq(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wait for pending opens to finish up
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * note: this also has the side effect of single threading closes
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok while (fn_lock->flk_ocsync)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_wait(&fn_lock->flk_wait_cv, &fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_lock->flk_ocsync = 1;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FREAD) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_rcnt--;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If we are last writer wake up sleeping readers
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (They'll figure out that there are no more writers
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and do the right thing)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * send hangup down stream so that stream head will do the
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * right thing.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (flag & FWRITE) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_wcnt == 0 && fn_dest->fn_rcnt > 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((fn_dest->fn_flag & (FIFOFAST | FIFOWANTR)) ==
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (FIFOFAST | FIFOWANTR)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * While we're at it, clear FIFOWANTW too
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Wake up any sleeping readers or
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * writers.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_flag &= ~(FIFOWANTR | FIFOWANTW);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fn_dest->fn_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This is needed incase the other side
4656d4747c8743290bfbe910c64cd75eb4e4af8dGarrett D'Amore * was opened non-blocking. It is the
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * only way we can tell that wcnt is 0 because
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * of close instead of never having a writer
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & ISPIPE))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOCLOSE;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: sending hangup effectively shuts down
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * both reader and writer at other end.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) putnextctl_wait(sd_wrq, M_HANGUP);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland senthang = 1;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
4656d4747c8743290bfbe910c64cd75eb4e4af8dGarrett D'Amore }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * For FIFOs we need to indicate to stream head that last reader
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * has gone away so that an error is generated
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Pipes just need to wake up the other end so that it can
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * notice this end has gone away.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fnp->fn_rcnt == 0 && fn_dest->fn_wcnt > 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((fn_dest->fn_flag & (FIFOFAST | FIFOWANTW)) ==
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (FIFOFAST | FIFOWANTW)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wake up any sleeping writers
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_flag &= ~FIFOWANTW;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fn_dest->fn_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
4656d4747c8743290bfbe910c64cd75eb4e4af8dGarrett D'Amore /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * if there are still processes with this FIFO open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * clear open/close sync flag
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * and just return;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (--fnp->fn_open > 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT((fnp->fn_rcnt + fnp->fn_wcnt) != 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_lock->flk_ocsync = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fn_lock->flk_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
4656d4747c8743290bfbe910c64cd75eb4e4af8dGarrett D'Amore return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Need to send HANGUP if other side is still open
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (fnp->fn_rcnt or fnp->fn_wcnt may not be zero (some thread
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * on this end of the pipe may still be in fifo_open())
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: we can get here with fn_rcnt and fn_wcnt != 0 if some
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * thread is blocked somewhere in the fifo_open() path prior to
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fifo_stropen() incrementing fn_open. This can occur for
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * normal FIFOs as well as named pipes. fn_rcnt and
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * fn_wcnt only indicate attempts to open. fn_open indicates
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * successful opens. Partially opened FIFOs should proceed
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * normally; i.e. they will appear to be new opens. Partially
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * opened pipes will probably fail.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_open && senthang == 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) putnextctl_wait(sd_wrq, M_HANGUP);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If this a pipe and this is the first end to close,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * then we have a bit of cleanup work to do.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Mark both ends of pipe as closed.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Wake up anybody blocked at the other end and for named pipes,
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * Close down this end of the stream
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * Allow other opens/closes to continue
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * force an unmount of other end.
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * Otherwise if this is last close,
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * flush messages,
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * close down the stream
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * allow other opens/closes to continue
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok */
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fnp->fn_flag &= ~FIFOISOPEN;
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if ((fnp->fn_flag & ISPIPE) && !(fnp->fn_flag & FIFOCLOSE)) {
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fnp->fn_flag |= FIFOCLOSE;
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fn_dest->fn_flag |= FIFOCLOSE;
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if (fnp->fn_flag & FIFOFAST)
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fifo_fastflush(fnp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if (vp->v_stream != NULL) {
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok mutex_exit(&fn_lock->flk_lock);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok (void) strclose(vp, flag, crp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok mutex_enter(&fn_lock->flk_lock);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok }
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok cv_broadcast(&fn_dest->fn_wait_cv);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok /*
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * allow opens and closes to proceed
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * Since this end is now closed down, any attempt
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * to do anything with this end will fail
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok */
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fn_lock->flk_ocsync = 0;
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok cv_broadcast(&fn_lock->flk_wait_cv);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fn_dest_vp = FTOV(fn_dest);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok /*
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * if other end of pipe has been opened and it's
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * a named pipe, unmount it
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok */
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if (fn_dest_vp->v_stream &&
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok (fn_dest_vp->v_stream->sd_flag & STRMOUNT)) {
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok /*
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * We must hold the destination vnode because
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * nm_unmountall() causes close to be called
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * for the other end of named pipe. This
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok * could free the vnode before we are ready.
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok */
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok VN_HOLD(fn_dest_vp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok mutex_exit(&fn_lock->flk_lock);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok error = nm_unmountall(fn_dest_vp, crp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok ASSERT(error == 0);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok VN_RELE(fn_dest_vp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok } else {
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok ASSERT(vp->v_count >= 1);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok mutex_exit(&fn_lock->flk_lock);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok }
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok } else {
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if (fnp->fn_flag & FIFOFAST)
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fifo_fastflush(fnp);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok#if DEBUG
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok fn_dest_vp = FTOV(fn_dest);
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok if (fn_dest_vp->v_stream)
b46ec01af51b4e66dbdba8ceb0a8e5ed36241df9ok ASSERT((fn_dest_vp->v_stream->sd_flag & STRMOUNT) == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland#endif
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (vp->v_stream != NULL) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (void) strclose(vp, flag, crp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_lock->flk_ocsync = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fn_lock->flk_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland cv_broadcast(&fn_dest->fn_wait_cv);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (error);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland}
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Read from a pipe or FIFO.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * return 0 if....
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (1) user read request is 0 or no stream
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (2) broken pipe with no data
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (3) write-only FIFO with no data
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (4) no data and FNDELAY flag is set.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Otherwise return
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * EAGAIN if FNONBLOCK is set and no data to read
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * EINTR if signal recieved while waiting for data
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * While there is no data to read....
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * - if the NDELAY/NONBLOCK flag is set, return 0/EAGAIN.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * - wait for a write.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland *
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*ARGSUSED*/
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandfifo_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *crp,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland caller_context_t *ct)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland{
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifonode_t *fnp = VTOF(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifonode_t *fn_dest;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifolock_t *fn_lock = fnp->fn_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int error = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mblk_t *bp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vp->v_stream != NULL);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_resid == 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_2(TR_FAC_FIFO,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TR_FIFOREAD_IN, "fifo_read in:%p fnp %p", vp, fnp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (! (fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest = fnp->fn_dest;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Check for data on our input queue
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland while (fnp->fn_count == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * No data on first attempt and no writer, then EOF
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_wcnt == 0 || fn_dest->fn_rcnt == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * no data found.. if non-blocking, return EAGAIN
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * otherwise 0.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_fmode & FNONBLOCK)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (EAGAIN);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: FIFOs can get here with FIFOCLOSE set if
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * write side is in the middle of opeining after
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * it once closed. Pipes better not have FIFOCLOSE set
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT((fnp->fn_flag & (ISPIPE|FIFOCLOSE)) !=
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland (ISPIPE|FIFOCLOSE));
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wait for data
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOWANTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_1(TR_FAC_FIFO, TR_FIFOREAD_WAIT,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "fiforead wait: %p", vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland &fn_lock->flk_lock)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = EINTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_1(TR_FAC_FIFO, TR_FIFOREAD_WAKE,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "fiforead awake: %p", vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * check to make sure we are still in fast mode
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_mp != NULL);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* For pipes copy should not bypass cache */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland uiop->uio_extflg |= UIO_COPY_CACHED;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland do {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int bpsize = MBLKL(fnp->fn_mp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int uiosize = MIN(bpsize, uiop->uio_resid);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = uiomove(fnp->fn_mp->b_rptr, uiosize, UIO_READ, uiop);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (error != 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland break;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_count -= uiosize;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (bpsize <= uiosize) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland bp = fnp->fn_mp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_mp = fnp->fn_mp->b_cont;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland freeb(bp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_resid == 0)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland break;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland while (fnp->fn_mp == NULL && fn_dest->fn_wwaitcnt > 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(fnp->fn_count == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_fmode & (FNDELAY|FNONBLOCK))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto trywake;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * We've consumed all available data but there
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * are threads waiting to write more, let them
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * proceed before bailing.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOWANTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifo_wakewriter(fn_dest, fn_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!cv_wait_sig(&fnp->fn_wait_cv,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland &fn_lock->flk_lock))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto trywake;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_mp->b_rptr += uiosize;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(uiop->uio_resid == 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } while (uiop->uio_resid != 0 && fnp->fn_mp != NULL);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandtrywake:
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(msgdsize(fnp->fn_mp) == fnp->fn_count);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wake up any blocked writers, processes
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * sleeping on POLLWRNORM, or processes waiting for SIGPOLL
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: checking for fn_count < Fifohiwat emulates
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * STREAMS functionality when low water mark is 0
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_flag & (FIFOWANTW | FIFOHIWATW) &&
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_count < Fifohiwat) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifo_wakewriter(fn_dest, fn_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * FIFO is in streams mode.. let the stream head handle it
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstream_mode:
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_1(TR_FAC_FIFO,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TR_FIFOREAD_STREAM, "fifo_read stream_mode:%p", vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = strread(vp, uiop, crp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlanddone:
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * vnode update access time
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (error == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland time_t now = gethrestime_sec();
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fnp->fn_flag & ISPIPE)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_dest->fn_atime = now;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_atime = now;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_2(TR_FAC_FIFO,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TR_FIFOREAD_OUT, "fifo_read out:%p error %d",
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland vp, error);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (error);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland}
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * send SIGPIPE and return EPIPE if ...
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (1) broken pipe (essentially, reader is gone)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (2) FIFO is not open for reading
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * return 0 if...
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (1) no stream
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * (2) user write request is for 0 bytes and SW_SNDZERO is not set
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: SW_SNDZERO can't be set in fast mode
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * While the stream is flow controlled....
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * - if the NDELAY/NONBLOCK flag is set, return 0/EAGAIN.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * - unlock the fifonode and sleep waiting for a reader.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * - if a pipe and it has a mate, sleep waiting for its mate
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * to read.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland/*ARGSUSED*/
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandstatic int
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterlandfifo_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *crp,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland caller_context_t *ct)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland{
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland struct fifonode *fnp, *fn_dest;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifolock_t *fn_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland struct stdata *stp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int error = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int write_size;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int size;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland int fmode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mblk_t *bp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland boolean_t hotread;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(vp->v_stream);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland uiop->uio_loffset = 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland stp = vp->v_stream;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * remember original number of bytes requested. Used to determine if
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * we actually have written anything at all
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland write_size = uiop->uio_resid;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * only send zero-length messages if SW_SNDZERO is set
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Note: we will be in streams mode if SW_SNDZERO is set
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * XXX this streams interface should not be exposed
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((write_size == 0) && !(stp->sd_wput_opt & SW_SNDZERO))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp = VTOF(vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_lock = fnp->fn_lock;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest = fnp->fn_dest;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_3(TR_FAC_FIFO,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TR_FIFOWRITE_IN, "fifo_write in:%p fnp %p size %d",
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland vp, fnp, write_size);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * oops, no readers, error
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto epipe;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * if we are not in fast mode, let streams handle it
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fmode = uiop->uio_fmode & (FNDELAY|FNONBLOCK);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /* For pipes copy should not bypass cache */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland uiop->uio_extflg |= UIO_COPY_CACHED;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland do {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * check to make sure we are not over high water mark
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland while (fn_dest->fn_count >= Fifohiwat) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Indicate that we have gone over high
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * water mark
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * if non-blocking, return
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * only happens first time through loop
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fmode) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOHIWATW;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_resid == write_size) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fmode & FNDELAY)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland else
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland return (EAGAIN);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * wait for things to drain
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_flag |= FIFOWANTW;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wwaitcnt++;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_1(TR_FAC_FIFO, TR_FIFOWRITE_WAIT,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "fifo_write wait: %p", vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!cv_wait_sig_swap(&fnp->fn_wait_cv,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland &fn_lock->flk_lock)) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = EINTR;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wwaitcnt--;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fifo_wakereader(fn_dest, fn_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fnp->fn_wwaitcnt--;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland TRACE_1(TR_FAC_FIFO, TR_FIFOWRITE_WAKE,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland "fifo_write wake: %p", vp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * check to make sure we're still in fast mode
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * make sure readers didn't go away
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto epipe;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * If the write will put us over the high water mark,
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * then we must break the message up into PIPE_BUF
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * chunks to stay compliant with STREAMS
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (uiop->uio_resid + fn_dest->fn_count > Fifohiwat)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland size = MIN(uiop->uio_resid, PIPE_BUF);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland else
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland size = uiop->uio_resid;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * We don't need to hold flk_lock across the allocb() and
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * uiomove(). However, on a multiprocessor machine where both
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * the reader and writer thread are on cpu's, we must be
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * careful to only drop the lock if there's data to be read.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This forces threads entering fifo_read() to spin or block
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * on flk_lock, rather than acquiring flk_lock only to
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * discover there's no data to read and being forced to go
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * back to sleep, only to be woken up microseconds later by
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * this writer thread.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland hotread = fn_dest->fn_count > 0;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (hotread)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland ASSERT(size != 0);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * Align the mblk with the user data so that
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * copying in the data can take advantage of
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * the double word alignment
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if ((bp = allocb(size + 8, BPRI_MED)) == NULL) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!hotread)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_exit(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = strwaitbuf(size, BPRI_MED);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (error != 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * check to make sure we're still in fast mode
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (!(fnp->fn_flag & FIFOFAST))
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto stream_mode;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * make sure readers didn't go away
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto epipe;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * some other thread could have gotten in
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * need to go back and check hi water mark
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland continue;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland bp->b_rptr += ((uintptr_t)uiop->uio_iov->iov_base & 0x7);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland bp->b_wptr = bp->b_rptr + size;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland error = uiomove((caddr_t)bp->b_rptr, size, UIO_WRITE, uiop);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (hotread)
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland mutex_enter(&fn_lock->flk_lock);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (error != 0) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland freeb(bp);
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland goto done;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland }
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_count += size;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland if (fn_dest->fn_mp != NULL) {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_tail->b_cont = bp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_tail = bp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland } else {
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland fn_dest->fn_mp = fn_dest->fn_tail = bp;
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland /*
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * This is the first bit of data; wake up any sleeping
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * readers, processes blocked in poll, and those
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland * expecting a SIGPOLL.
5c51f1241dbbdf2656d0e10011981411ed0c9673Moriah Waterland */
fifo_wakereader(fn_dest, fn_lock);
}
} while (uiop->uio_resid != 0);
goto done;
stream_mode:
/*
* streams mode
* let the stream head handle the write
*/
ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
mutex_exit(&fn_lock->flk_lock);
TRACE_1(TR_FAC_FIFO,
TR_FIFOWRITE_STREAM, "fifo_write stream_mode:%p", vp);
error = strwrite(vp, uiop, crp);
mutex_enter(&fn_lock->flk_lock);
done:
/*
* update vnode modification and change times
* make sure there were no errors and some data was transfered
*/
if (error == 0 && write_size != uiop->uio_resid) {
time_t now = gethrestime_sec();
if (fnp->fn_flag & ISPIPE) {
fn_dest->fn_mtime = fn_dest->fn_ctime = now;
}
fnp->fn_mtime = fnp->fn_ctime = now;
} else if (fn_dest->fn_rcnt == 0 || fn_dest->fn_wcnt == 0) {
goto epipe;
}
TRACE_3(TR_FAC_FIFO, TR_FIFOWRITE_OUT,
"fifo_write out: vp %p error %d fnp %p", vp, error, fnp);
mutex_exit(&fn_lock->flk_lock);
return (error);
epipe:
error = EPIPE;
TRACE_3(TR_FAC_FIFO, TR_FIFOWRITE_OUT,
"fifo_write out: vp %p error %d fnp %p",
vp, error, fnp);
mutex_exit(&fn_lock->flk_lock);
tsignal(curthread, SIGPIPE);
return (error);
}
static int
fifo_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
cred_t *cr, int *rvalp)
{
/*
* Just a quick check
* Once we go to streams mode we don't ever revert back
* So we do this quick check so as not to incur the overhead
* associated with acquiring the lock
*/
return ((VTOF(vp)->fn_flag & FIFOFAST) ?
fifo_fastioctl(vp, cmd, arg, mode, cr, rvalp) :
fifo_strioctl(vp, cmd, arg, mode, cr, rvalp));
}
static int
fifo_fastioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
cred_t *cr, int *rvalp)
{
fifonode_t *fnp = VTOF(vp);
fifonode_t *fn_dest;
int error = 0;
fifolock_t *fn_lock = fnp->fn_lock;
int cnt;
/*
* tty operations not allowed
*/
if (((cmd & IOCTYPE) == LDIOC) ||
((cmd & IOCTYPE) == tIOC) ||
((cmd & IOCTYPE) == TIOC)) {
return (EINVAL);
}
mutex_enter(&fn_lock->flk_lock);
if (!(fnp->fn_flag & FIFOFAST)) {
goto stream_mode;
}
switch (cmd) {
/*
* Things we can't handle
* These will switch us to streams mode.
*/
default:
case I_STR:
case I_SRDOPT:
case I_PUSH:
case I_FDINSERT:
case I_SENDFD:
case I_RECVFD:
case I_E_RECVFD:
case I_ATMARK:
case I_CKBAND:
case I_GETBAND:
case I_SWROPT:
goto turn_fastoff;
/*
* Things that don't do damage
* These things don't adjust the state of the
* stream head (i_setcltime does, but we don't care)
*/
case I_FIND:
case I_GETSIG:
case FIONBIO:
case FIOASYNC:
case I_GRDOPT: /* probably should not get this, but no harm */
case I_GWROPT:
case I_LIST:
case I_SETCLTIME:
case I_GETCLTIME:
mutex_exit(&fn_lock->flk_lock);
return (strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp));
case I_CANPUT:
/*
* We can only handle normal band canputs.
* XXX : We could just always go to stream mode; after all
* canput is a streams semantics type thing
*/
if (arg != 0) {
goto turn_fastoff;
}
*rvalp = (fnp->fn_dest->fn_count < Fifohiwat) ? 1 : 0;
mutex_exit(&fn_lock->flk_lock);
return (0);
case I_NREAD:
/*
* This may seem a bit silly for non-streams semantics,
* (After all, if they really want a message, they'll
* probably use getmsg() anyway). but it doesn't hurt
*/
error = copyout((caddr_t)&fnp->fn_count, (caddr_t)arg,
sizeof (cnt));
if (error == 0) {
*rvalp = (fnp->fn_count == 0) ? 0 : 1;
}
break;
case FIORDCHK:
*rvalp = fnp->fn_count;
break;
case I_PEEK:
{
STRUCT_DECL(strpeek, strpeek);
struct uio uio;
struct iovec iov;
int count;
mblk_t *bp;
STRUCT_INIT(strpeek, mode);
if (fnp->fn_count == 0) {
*rvalp = 0;
break;
}
error = copyin((caddr_t)arg, STRUCT_BUF(strpeek),
STRUCT_SIZE(strpeek));
if (error)
break;
/*
* can't have any high priority message when in fast mode
*/
if (STRUCT_FGET(strpeek, flags) & RS_HIPRI) {
*rvalp = 0;
break;
}
iov.iov_base = STRUCT_FGETP(strpeek, databuf.buf);
iov.iov_len = STRUCT_FGET(strpeek, databuf.maxlen);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_loffset = 0;
uio.uio_segflg = UIO_USERSPACE;
uio.uio_fmode = 0;
/* For pipes copy should not bypass cache */
uio.uio_extflg = UIO_COPY_CACHED;
uio.uio_resid = iov.iov_len;
count = fnp->fn_count;
bp = fnp->fn_mp;
while (count > 0 && uio.uio_resid) {
cnt = MIN(uio.uio_resid, bp->b_wptr - bp->b_rptr);
if ((error = uiomove((char *)bp->b_rptr, cnt,
UIO_READ, &uio)) != 0) {
break;
}
count -= cnt;
bp = bp->b_cont;
}
STRUCT_FSET(strpeek, databuf.len,
STRUCT_FGET(strpeek, databuf.maxlen) - uio.uio_resid);
STRUCT_FSET(strpeek, flags, 0);
STRUCT_FSET(strpeek, ctlbuf.len,
STRUCT_FGET(strpeek, ctlbuf.maxlen));
error = copyout(STRUCT_BUF(strpeek), (caddr_t)arg,
STRUCT_SIZE(strpeek));
if (error == 0)
*rvalp = 1;
break;
}
case FIONREAD:
/*
* let user know total number of bytes in message queue
*/
error = copyout((caddr_t)&fnp->fn_count, (caddr_t)arg,
sizeof (fnp->fn_count));
if (error == 0)
*rvalp = 0;
break;
case I_SETSIG:
/*
* let streams set up the signal masking for us
* we just check to see if it's set
* XXX : this interface should not be visible
* i.e. STREAM's framework is exposed.
*/
error = strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp);
if (vp->v_stream->sd_sigflags & (S_INPUT|S_RDNORM|S_WRNORM))
fnp->fn_flag |= FIFOSETSIG;
else
fnp->fn_flag &= ~FIFOSETSIG;
break;
case I_FLUSH:
/*
* flush them message queues
*/
if (arg & ~FLUSHRW) {
error = EINVAL;
break;
}
if (arg & FLUSHR) {
fifo_fastflush(fnp);
}
fn_dest = fnp->fn_dest;
if ((arg & FLUSHW)) {
fifo_fastflush(fn_dest);
}
/*
* wake up any sleeping readers or writers
* (waking readers probably doesn't make sense, but it
* doesn't hurt; i.e. we just got rid of all the data
* what's to read ?)
*/
if (fn_dest->fn_flag & (FIFOWANTW | FIFOWANTR)) {
fn_dest->fn_flag &= ~(FIFOWANTW | FIFOWANTR);
cv_broadcast(&fn_dest->fn_wait_cv);
}
*rvalp = 0;
break;
/*
* Since no band data can ever get on a fifo in fast mode
* just return 0.
*/
case I_FLUSHBAND:
error = 0;
*rvalp = 0;
break;
/*
* invalid calls for stream head or fifos
*/
case I_POP: /* shouldn't happen */
case I_LOOK:
case I_LINK:
case I_PLINK:
case I_UNLINK:
case I_PUNLINK:
/*
* more invalid tty type of ioctls
*/
case SRIOCSREDIR:
case SRIOCISREDIR:
error = EINVAL;
break;
}
mutex_exit(&fn_lock->flk_lock);
return (error);
turn_fastoff:
fifo_fastoff(fnp);
stream_mode:
/*
* streams mode
*/
mutex_exit(&fn_lock->flk_lock);
return (fifo_strioctl(vp, cmd, arg, mode, cr, rvalp));
}
/*
* FIFO is in STREAMS mode; STREAMS framework does most of the work.
*/
static int
fifo_strioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
cred_t *cr, int *rvalp)
{
fifonode_t *fnp = VTOF(vp);
int error;
fifolock_t *fn_lock;
if (cmd == _I_GETPEERCRED) {
if (mode == FKIOCTL && fnp->fn_pcredp != NULL) {
k_peercred_t *kp = (k_peercred_t *)arg;
crhold(fnp->fn_pcredp);
kp->pc_cr = fnp->fn_pcredp;
kp->pc_cpid = fnp->fn_cpid;
return (0);
} else {
return (ENOTSUP);
}
}
error = strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp);
switch (cmd) {
/*
* The FIFOSEND flag is set to inform other processes that a file
* descriptor is pending at the stream head of this pipe.
* The flag is cleared and the sending process is awoken when
* this process has completed recieving the file descriptor.
* XXX This could become out of sync if the process does I_SENDFDs
* and opens on connld attached to the same pipe.
*/
case I_RECVFD:
case I_E_RECVFD:
if (error == 0) {
fn_lock = fnp->fn_lock;
mutex_enter(&fn_lock->flk_lock);
if (fnp->fn_flag & FIFOSEND) {
fnp->fn_flag &= ~FIFOSEND;
cv_broadcast(&fnp->fn_dest->fn_wait_cv);
}
mutex_exit(&fn_lock->flk_lock);
}
break;
default:
break;
}
return (error);
}
/*
* If shadowing a vnode (FIFOs), apply the VOP_GETATTR to the shadowed
* vnode to Obtain the node information. If not shadowing (pipes), obtain
* the node information from the credentials structure.
*/
int
fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
{
int error = 0;
fifonode_t *fnp = VTOF(vp);
queue_t *qp;
qband_t *bandp;
fifolock_t *fn_lock = fnp->fn_lock;
if (fnp->fn_realvp) {
/*
* for FIFOs or mounted pipes
*/
if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp))
return (error);
mutex_enter(&fn_lock->flk_lock);
/* set current times from fnode, even if older than vnode */
vap->va_atime.tv_sec = fnp->fn_atime;
vap->va_atime.tv_nsec = 0;
vap->va_mtime.tv_sec = fnp->fn_mtime;
vap->va_mtime.tv_nsec = 0;
vap->va_ctime.tv_sec = fnp->fn_ctime;
vap->va_ctime.tv_nsec = 0;
} else {
/*
* for non-attached/ordinary pipes
*/
vap->va_mode = 0;
mutex_enter(&fn_lock->flk_lock);
vap->va_atime.tv_sec = fnp->fn_atime;
vap->va_atime.tv_nsec = 0;
vap->va_mtime.tv_sec = fnp->fn_mtime;
vap->va_mtime.tv_nsec = 0;
vap->va_ctime.tv_sec = fnp->fn_ctime;
vap->va_ctime.tv_nsec = 0;
vap->va_uid = crgetuid(crp);
vap->va_gid = crgetgid(crp);
vap->va_nlink = 0;
vap->va_fsid = fifodev;
vap->va_nodeid = (ino64_t)fnp->fn_ino;
vap->va_rdev = 0;
}
vap->va_type = VFIFO;
vap->va_blksize = PIPE_BUF;
/*
* Size is number of un-read bytes at the stream head and
* nblocks is the unread bytes expressed in blocks.
*/
if (vp->v_stream && (fnp->fn_flag & FIFOISOPEN)) {
if ((fnp->fn_flag & FIFOFAST)) {
vap->va_size = (u_offset_t)fnp->fn_count;
} else {
qp = RD((strvp2wq(vp)));
vap->va_size = (u_offset_t)qp->q_count;
if (qp->q_nband != 0) {
mutex_enter(QLOCK(qp));
for (bandp = qp->q_bandp; bandp;
bandp = bandp->qb_next)
vap->va_size += bandp->qb_count;
mutex_exit(QLOCK(qp));
}
}
vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
} else {
vap->va_size = (u_offset_t)0;
vap->va_nblocks = (fsblkcnt64_t)0;
}
mutex_exit(&fn_lock->flk_lock);
vap->va_seq = 0;
return (0);
}
/*
* If shadowing a vnode, apply the VOP_SETATTR to it, and to the fnode.
* Otherwise, set the time and return 0.
*/
int
fifo_setattr(
vnode_t *vp,
vattr_t *vap,
int flags,
cred_t *crp,
caller_context_t *ctp)
{
fifonode_t *fnp = VTOF(vp);
int error = 0;
fifolock_t *fn_lock;
if (fnp->fn_realvp)
error = VOP_SETATTR(fnp->fn_realvp, vap, flags, crp, ctp);
if (error == 0) {
fn_lock = fnp->fn_lock;
mutex_enter(&fn_lock->flk_lock);
if (vap->va_mask & AT_ATIME)
fnp->fn_atime = vap->va_atime.tv_sec;
if (vap->va_mask & AT_MTIME)
fnp->fn_mtime = vap->va_mtime.tv_sec;
fnp->fn_ctime = gethrestime_sec();
mutex_exit(&fn_lock->flk_lock);
}
return (error);
}
/*
* If shadowing a vnode, apply VOP_ACCESS to it.
* Otherwise, return 0 (allow all access).
*/
int
fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp)
{
if (VTOF(vp)->fn_realvp)
return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp));
else
return (0);
}
/*
* If shadowing a vnode, apply the VOP_FSYNC to it.
* Otherwise, return 0.
*/
int
fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
{
fifonode_t *fnp = VTOF(vp);
vattr_t va;
if (fnp->fn_realvp == NULL)
return (0);
bzero((caddr_t)&va, sizeof (va));
va.va_mask = AT_MTIME | AT_ATIME;
if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp) == 0) {
va.va_mask = 0;
if (fnp->fn_mtime > va.va_mtime.tv_sec) {
va.va_mtime.tv_sec = fnp->fn_mtime;
va.va_mask = AT_MTIME;
}
if (fnp->fn_atime > va.va_atime.tv_sec) {
va.va_atime.tv_sec = fnp->fn_atime;
va.va_mask |= AT_ATIME;
}
if (va.va_mask != 0)
(void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, NULL);
}
return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp));
}
/*
* Called when the upper level no longer holds references to the
* vnode. Sync the file system and free the fifonode.
*/
void
fifo_inactive(vnode_t *vp, cred_t *crp)
{
fifonode_t *fnp;
fifolock_t *fn_lock;
mutex_enter(&ftable_lock);
mutex_enter(&vp->v_lock);
ASSERT(vp->v_count >= 1);
if (--vp->v_count != 0) {
/*
* Somebody accessed the fifo before we got a chance to
* remove it. They will remove it when they do a vn_rele.
*/
mutex_exit(&vp->v_lock);
mutex_exit(&ftable_lock);
return;
}
mutex_exit(&vp->v_lock);
fnp = VTOF(vp);
/*
* remove fifo from fifo list so that no other process
* can grab it.
*/
if (fnp->fn_realvp) {
(void) fiforemove(fnp);
mutex_exit(&ftable_lock);
(void) fifo_fsync(vp, FSYNC, crp);
VN_RELE(fnp->fn_realvp);
vp->v_vfsp = NULL;
} else
mutex_exit(&ftable_lock);
fn_lock = fnp->fn_lock;
mutex_enter(&fn_lock->flk_lock);
ASSERT(vp->v_stream == NULL);
ASSERT(vp->v_count == 0);
/*
* if this is last reference to the lock, then we can
* free everything up.
*/
if (--fn_lock->flk_ref == 0) {
mutex_exit(&fn_lock->flk_lock);
ASSERT(fnp->fn_open == 0);
ASSERT(fnp->fn_dest->fn_open == 0);
if (fnp->fn_mp) {
freemsg(fnp->fn_mp);
fnp->fn_mp = NULL;
fnp->fn_count = 0;
}
if (fnp->fn_pcredp != NULL) {
crfree(fnp->fn_pcredp);
fnp->fn_pcredp = NULL;
}
if (fnp->fn_flag & ISPIPE) {
fifonode_t *fn_dest = fnp->fn_dest;
vp = FTOV(fn_dest);
if (fn_dest->fn_mp) {
freemsg(fn_dest->fn_mp);
fn_dest->fn_mp = NULL;
fn_dest->fn_count = 0;
}
if (fn_dest->fn_pcredp != NULL) {
crfree(fn_dest->fn_pcredp);
fn_dest->fn_pcredp = NULL;
}
kmem_cache_free(pipe_cache, (fifodata_t *)fn_lock);
} else
kmem_cache_free(fnode_cache, (fifodata_t *)fn_lock);
} else {
mutex_exit(&fn_lock->flk_lock);
}
}
/*
* If shadowing a vnode, apply the VOP_FID to it.
* Otherwise, return EINVAL.
*/
int
fifo_fid(vnode_t *vp, fid_t *fidfnp)
{
if (VTOF(vp)->fn_realvp)
return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp));
else
return (EINVAL);
}
/*
* Lock a fifonode.
*/
/* ARGSUSED */
int
fifo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
{
return (-1);
}
/*
* Unlock a fifonode.
*/
/* ARGSUSED */
void
fifo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
{
}
/*
* Return error since seeks are not allowed on pipes.
*/
/*ARGSUSED*/
int
fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
{
return (ESPIPE);
}
/*
* If there is a realvp associated with vp, return it.
*/
int
fifo_realvp(vnode_t *vp, vnode_t **vpp)
{
vnode_t *rvp;
if ((rvp = VTOF(vp)->fn_realvp) != NULL) {
vp = rvp;
if (VOP_REALVP(vp, &rvp) == 0)
vp = rvp;
}
*vpp = vp;
return (0);
}
/*
* Poll for interesting events on a stream pipe
*/
int
fifo_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
pollhead_t **phpp)
{
fifonode_t *fnp, *fn_dest;
fifolock_t *fn_lock;
int retevents;
struct stdata *stp;
ASSERT(vp->v_stream != NULL);
stp = vp->v_stream;
retevents = 0;
fnp = VTOF(vp);
fn_dest = fnp->fn_dest;
fn_lock = fnp->fn_lock;
polllock(&stp->sd_pollist, &fn_lock->flk_lock);
/*
* see if FIFO/pipe open
*/
if ((fnp->fn_flag & FIFOISOPEN) == 0) {
if (((events & (POLLIN | POLLRDNORM | POLLPRI | POLLRDBAND)) &&
fnp->fn_rcnt == 0) ||
((events & (POLLWRNORM | POLLWRBAND)) &&
fnp->fn_wcnt == 0)) {
mutex_exit(&fnp->fn_lock->flk_lock);
*reventsp = POLLERR;
return (0);
}
}
/*
* if not in fast mode, let the stream head take care of it
*/
if (!(fnp->fn_flag & FIFOFAST)) {
mutex_exit(&fnp->fn_lock->flk_lock);
goto stream_mode;
}
/*
* If this is a pipe.. check to see if the other
* end is gone. If we are a fifo, check to see
* if write end is gone.
*/
if ((fnp->fn_flag & ISPIPE) && (fn_dest->fn_open == 0)) {
retevents = POLLHUP;
} else if ((fnp->fn_flag & (FIFOCLOSE | ISPIPE)) == FIFOCLOSE &&
(fn_dest->fn_wcnt == 0)) {
/*
* no writer at other end.
* it was closed (versus yet to be opened)
*/
retevents = POLLHUP;
} else if (events & (POLLWRNORM | POLLWRBAND)) {
if (events & POLLWRNORM) {
if (fn_dest->fn_count < Fifohiwat)
retevents = POLLWRNORM;
else
fnp->fn_flag |= FIFOHIWATW;
}
/*
* This is always true for fast pipes
* (Note: will go to STREAMS mode if band data is written)
*/
if (events & POLLWRBAND)
retevents |= POLLWRBAND;
}
if (events & (POLLIN | POLLRDNORM)) {
if (fnp->fn_count)
retevents |= (events & (POLLIN | POLLRDNORM));
}
/*
* if we happened to get something, return
*/
if ((*reventsp = (short)retevents) != 0) {
mutex_exit(&fnp->fn_lock->flk_lock);
return (0);
}
/*
* If poll() has not found any events yet, set up event cell
* to wake up the poll if a requested event occurs on this
* pipe/fifo.
*/
if (!anyyet) {
if (events & POLLWRNORM)
fnp->fn_flag |= FIFOPOLLW;
if (events & (POLLIN | POLLRDNORM))
fnp->fn_flag |= FIFOPOLLR;
if (events & POLLRDBAND)
fnp->fn_flag |= FIFOPOLLRBAND;
/*
* XXX Don't like exposing this from streams
*/
*phpp = &stp->sd_pollist;
}
mutex_exit(&fnp->fn_lock->flk_lock);
return (0);
stream_mode:
return (strpoll(stp, events, anyyet, reventsp, phpp));
}
/*
* POSIX pathconf() support.
*/
/* ARGSUSED */
int
fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
{
ulong_t val;
int error = 0;
switch (cmd) {
case _PC_LINK_MAX:
val = MAXLINK;
break;
case _PC_MAX_CANON:
val = MAX_CANON;
break;
case _PC_MAX_INPUT:
val = MAX_INPUT;
break;
case _PC_NAME_MAX:
error = EINVAL;
break;
case _PC_PATH_MAX:
case _PC_SYMLINK_MAX:
val = MAXPATHLEN;
break;
case _PC_PIPE_BUF:
val = PIPE_BUF;
break;
case _PC_NO_TRUNC:
if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
val = 1; /* NOTRUNC is enabled for vp */
else
val = (ulong_t)-1;
break;
case _PC_VDISABLE:
val = _POSIX_VDISABLE;
break;
case _PC_CHOWN_RESTRICTED:
if (rstchown)
val = rstchown; /* chown restricted enabled */
else
val = (ulong_t)-1;
break;
case _PC_FILESIZEBITS:
val = (ulong_t)-1;
break;
default:
if (VTOF(vp)->fn_realvp)
error = VOP_PATHCONF(VTOF(vp)->fn_realvp, cmd,
&val, cr);
else
error = EINVAL;
break;
}
if (error == 0)
*valp = val;
return (error);
}
/*
* If shadowing a vnode, apply VOP_SETSECATTR to it.
* Otherwise, return NOSYS.
*/
int
fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
{
int error;
/*
* The acl(2) system call tries to grab the write lock on the
* file when setting an ACL, but fifofs does not implement
* VOP_RWLOCK or VOP_RWUNLOCK, so we do it here instead.
*/
if (VTOF(vp)->fn_realvp) {
(void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp);
VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
return (error);
} else
return (fs_nosys());
}
/*
* If shadowing a vnode, apply VOP_GETSECATTR to it. Otherwise, fabricate
* an ACL from the permission bits that fifo_getattr() makes up.
*/
int
fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
{
if (VTOF(vp)->fn_realvp)
return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp));
else
return (fs_fab_acl(vp, vsap, flag, crp));
}