#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/debug.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kmem.h>
#include <sys/inline.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/var.h>
#include <sys/vfs.h>
#include <sys/vfs_opreg.h>
#include <sys/vnode.h>
#include <sys/mode.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/uio.h>
#include <sys/flock.h>
#include <sys/stream.h>
#include <sys/fs/fifonode.h>
#include <sys/strsubr.h>
#include <sys/stropts.h>
#include <sys/cmn_err.h>
#include <fs/fs_subr.h>
#include <sys/ddi.h>
#if FIFODEBUG
int Fifo_fastmode = 1;
int Fifo_verbose = 0;
int Fifohiwat = FIFOHIWAT;
#endif
#include <sys/modctl.h>
extern struct qinit fifo_strdata;
struct vfsops *fifo_vfsops;
static vfsdef_t vfw = {
VFSDEF_VERSION,
"fifofs",
fifoinit,
VSW_ZMOUNT,
NULL
};
extern struct mod_ops mod_fsops;
static struct modlfs modlfs = {
&mod_fsops, "filesystem for fifo", &vfw
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlfs, NULL
};
int
_init()
{
return (mod_install(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
#define FIFOSHFT 5
#define FIFO_HASHSZ 63
#if ((FIFO_HASHSZ & (FIFO_HASHSZ - 1)) == 0)
#define FIFOHASH(vp) (((uintptr_t)(vp) >> FIFOSHFT) & (FIFO_HASHSZ - 1))
#else
#define FIFOHASH(vp) (((uintptr_t)(vp) >> FIFOSHFT) % FIFO_HASHSZ)
#endif
fifonode_t *fifoalloc[FIFO_HASHSZ];
dev_t fifodev;
struct vfs *fifovfsp;
int fifofstype;
kmutex_t ftable_lock;
static kmutex_t fino_lock;
struct kmem_cache *fnode_cache;
struct kmem_cache *pipe_cache;
static void fifoinsert(fifonode_t *);
static fifonode_t *fifofind(vnode_t *);
static int fifo_connld(struct vnode **, int, cred_t *);
static void fifo_fastturnoff(fifonode_t *);
static void fifo_reinit_vp(vnode_t *);
static void fnode_destructor(void *, void *);
static int
fnode_constructor(void *buf, void *cdrarg, int kmflags)
{
fifodata_t *fdp = buf;
fifolock_t *flp = &fdp->fifo_lock;
fifonode_t *fnp = &fdp->fifo_fnode[0];
size_t size = (uintptr_t)cdrarg;
mutex_init(&flp->flk_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&flp->flk_wait_cv, NULL, CV_DEFAULT, NULL);
flp->flk_ocsync = 0;
while ((char *)fnp < (char *)buf + size) {
vnode_t *vp;
vp = vn_alloc(kmflags);
if (vp == NULL) {
fnp->fn_vnode = NULL;
fnode_destructor(buf, cdrarg);
return (-1);
}
fnp->fn_vnode = vp;
fnp->fn_lock = flp;
fnp->fn_open = 0;
fnp->fn_dest = fnp;
fnp->fn_mp = NULL;
fnp->fn_count = 0;
fnp->fn_rsynccnt = 0;
fnp->fn_wsynccnt = 0;
fnp->fn_wwaitcnt = 0;
fnp->fn_insync = 0;
fnp->fn_pcredp = NULL;
fnp->fn_cpid = -1;
fnp->fn_ino = 0;
cv_init(&fnp->fn_wait_cv, NULL, CV_DEFAULT, NULL);
vn_setops(vp, fifo_vnodeops);
vp->v_stream = NULL;
vp->v_type = VFIFO;
vp->v_data = (caddr_t)fnp;
vp->v_flag = VNOMAP | VNOSWAP;
vn_exists(vp);
fnp++;
}
return (0);
}
static void
fnode_destructor(void *buf, void *cdrarg)
{
fifodata_t *fdp = buf;
fifolock_t *flp = &fdp->fifo_lock;
fifonode_t *fnp = &fdp->fifo_fnode[0];
size_t size = (uintptr_t)cdrarg;
mutex_destroy(&flp->flk_lock);
cv_destroy(&flp->flk_wait_cv);
ASSERT(flp->flk_ocsync == 0);
while ((char *)fnp < (char *)buf + size) {
vnode_t *vp = FTOV(fnp);
if (vp == NULL) {
return;
}
ASSERT(fnp->fn_mp == NULL);
ASSERT(fnp->fn_count == 0);
ASSERT(fnp->fn_lock == flp);
ASSERT(fnp->fn_open == 0);
ASSERT(fnp->fn_insync == 0);
ASSERT(fnp->fn_rsynccnt == 0 && fnp->fn_wsynccnt == 0);
ASSERT(fnp->fn_wwaitcnt == 0);
ASSERT(fnp->fn_pcredp == NULL);
ASSERT(vn_matchops(vp, fifo_vnodeops));
ASSERT(vp->v_stream == NULL);
ASSERT(vp->v_type == VFIFO);
ASSERT(vp->v_data == (caddr_t)fnp);
ASSERT((vp->v_flag & (VNOMAP|VNOSWAP)) == (VNOMAP|VNOSWAP));
cv_destroy(&fnp->fn_wait_cv);
vn_invalid(vp);
vn_free(vp);
fnp++;
}
}
static int
pipe_constructor(void *buf, void *cdrarg, int kmflags)
{
fifodata_t *fdp = buf;
fifonode_t *fnp1 = &fdp->fifo_fnode[0];
fifonode_t *fnp2 = &fdp->fifo_fnode[1];
vnode_t *vp1;
vnode_t *vp2;
(void) fnode_constructor(buf, cdrarg, kmflags);
vp1 = FTOV(fnp1);
vp2 = FTOV(fnp2);
vp1->v_vfsp = vp2->v_vfsp = fifovfsp;
vp1->v_rdev = vp2->v_rdev = fifodev;
fnp1->fn_realvp = fnp2->fn_realvp = NULL;
fnp1->fn_dest = fnp2;
fnp2->fn_dest = fnp1;
return (0);
}
static void
pipe_destructor(void *buf, void *cdrarg)
{
#ifdef DEBUG
fifodata_t *fdp = buf;
fifonode_t *fnp1 = &fdp->fifo_fnode[0];
fifonode_t *fnp2 = &fdp->fifo_fnode[1];
vnode_t *vp1 = FTOV(fnp1);
vnode_t *vp2 = FTOV(fnp2);
ASSERT(vp1->v_vfsp == fifovfsp);
ASSERT(vp2->v_vfsp == fifovfsp);
ASSERT(vp1->v_rdev == fifodev);
ASSERT(vp2->v_rdev == fifodev);
#endif
fnode_destructor(buf, cdrarg);
}
static void fifo_reinit_vp(vnode_t *vp)
{
vn_reinit(vp);
vp->v_type = VFIFO;
vp->v_flag &= VROOT;
vp->v_flag |= VNOMAP | VNOSWAP;
}
int
fifoinit(int fstype, char *name)
{
static const fs_operation_def_t fifo_vfsops_template[] = {
NULL, NULL
};
int error;
major_t dev;
fifofstype = fstype;
error = vfs_setfsops(fstype, fifo_vfsops_template, &fifo_vfsops);
if (error != 0) {
cmn_err(CE_WARN, "fifoinit: bad vfs ops template");
return (error);
}
error = vn_make_ops(name, fifo_vnodeops_template, &fifo_vnodeops);
if (error != 0) {
(void) vfs_freevfsops_by_type(fstype);
cmn_err(CE_WARN, "fifoinit: bad vnode ops template");
return (error);
}
if ((dev = getudev()) == (major_t)-1) {
cmn_err(CE_WARN, "fifoinit: can't get unique device number");
dev = 0;
}
fifodev = makedevice(dev, 0);
fifovfsp = fs_vfsp_global(fifo_vfsops, fifodev, fifofstype, 1024);
mutex_init(&ftable_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&fino_lock, NULL, MUTEX_DEFAULT, NULL);
fnode_cache = kmem_cache_create("fnode_cache",
sizeof (fifodata_t) - sizeof (fifonode_t), 32,
fnode_constructor, fnode_destructor, NULL,
(void *)(sizeof (fifodata_t) - sizeof (fifonode_t)), NULL, 0);
pipe_cache = kmem_cache_create("pipe_cache", sizeof (fifodata_t), 32,
pipe_constructor, pipe_destructor, NULL,
(void *)(sizeof (fifodata_t)), NULL, 0);
#if FIFODEBUG
if (Fifohiwat < FIFOHIWAT)
Fifohiwat = FIFOHIWAT;
#endif
fifo_strdata.qi_minfo->mi_hiwat = Fifohiwat;
return (0);
}
vnode_t *
fifovp(vnode_t *vp, cred_t *crp)
{
fifonode_t *fnp;
fifonode_t *spec_fnp;
fifodata_t *fdp;
vnode_t *newvp;
struct vattr va;
vnode_t *rvp;
ASSERT(vp != NULL);
fdp = kmem_cache_alloc(fnode_cache, KM_SLEEP);
fdp->fifo_lock.flk_ref = 1;
fnp = &fdp->fifo_fnode[0];
if (VOP_REALVP(vp, &rvp, NULL) == 0)
vp = rvp;
fnp->fn_realvp = vp;
fnp->fn_wcnt = 0;
fnp->fn_rcnt = 0;
#if FIFODEBUG
if (! Fifo_fastmode) {
fnp->fn_flag = 0;
} else {
fnp->fn_flag = FIFOFAST;
}
#else
fnp->fn_flag = FIFOFAST;
#endif
va.va_mask = AT_TIMES;
if (VOP_GETATTR(vp, &va, 0, crp, NULL) == 0) {
fnp->fn_atime = va.va_atime;
fnp->fn_mtime = va.va_mtime;
fnp->fn_ctime = va.va_ctime;
} else {
fnp->fn_atime.tv_sec = 0;
fnp->fn_atime.tv_nsec = 0;
fnp->fn_mtime.tv_sec = 0;
fnp->fn_mtime.tv_nsec = 0;
fnp->fn_ctime.tv_sec = 0;
fnp->fn_ctime.tv_nsec = 0;
}
VN_HOLD(vp);
mutex_enter(&ftable_lock);
if ((spec_fnp = fifofind(vp)) != NULL) {
mutex_exit(&ftable_lock);
VN_RELE(vp);
fdp->fifo_lock.flk_ref = 0;
kmem_cache_free(fnode_cache, fdp);
return (FTOV(spec_fnp));
}
newvp = FTOV(fnp);
fifo_reinit_vp(newvp);
VFS_HOLD(vp->v_vfsp);
newvp->v_vfsp = vp->v_vfsp;
newvp->v_rdev = vp->v_rdev;
newvp->v_flag |= (vp->v_flag & VROOT);
fifoinsert(fnp);
mutex_exit(&ftable_lock);
return (newvp);
}
void
makepipe(vnode_t **vpp1, vnode_t **vpp2)
{
fifonode_t *fnp1;
fifonode_t *fnp2;
vnode_t *nvp1;
vnode_t *nvp2;
fifodata_t *fdp;
timestruc_t now;
fdp = kmem_cache_alloc(pipe_cache, KM_SLEEP);
fdp->fifo_lock.flk_ref = 2;
fnp1 = &fdp->fifo_fnode[0];
fnp2 = &fdp->fifo_fnode[1];
fnp1->fn_wcnt = fnp2->fn_wcnt = 1;
fnp1->fn_rcnt = fnp2->fn_rcnt = 1;
#if FIFODEBUG
if (! Fifo_fastmode) {
fnp1->fn_flag = fnp2->fn_flag = ISPIPE;
} else {
fnp1->fn_flag = fnp2->fn_flag = ISPIPE | FIFOFAST;
}
#else
fnp1->fn_flag = fnp2->fn_flag = ISPIPE | FIFOFAST;
#endif
gethrestime(&now);
fnp1->fn_atime = fnp2->fn_atime = now;
fnp1->fn_mtime = fnp2->fn_mtime = now;
fnp1->fn_ctime = fnp2->fn_ctime = now;
*vpp1 = nvp1 = FTOV(fnp1);
*vpp2 = nvp2 = FTOV(fnp2);
fifo_reinit_vp(nvp1);
fifo_reinit_vp(nvp2);
nvp1->v_vfsp = fifovfsp;
nvp2->v_vfsp = fifovfsp;
nvp1->v_rdev = fifodev;
nvp2->v_rdev = fifodev;
}
ino_t
fifogetid(void)
{
static ino_t fifo_ino = 0;
ino_t fino;
mutex_enter(&fino_lock);
fino = fifo_ino++;
mutex_exit(&fino_lock);
return (fino);
}
int
fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
{
int error = 0;
vnode_t *oldvp = *vpp;
fifonode_t *fnp = VTOF(*vpp);
dev_t pdev = 0;
int firstopen = 0;
fifolock_t *fn_lock;
fn_lock = fnp->fn_lock;
if (!lockheld)
mutex_enter(&fn_lock->flk_lock);
ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
while (fnp->fn_flag & FIFOOPEN) {
if (!cv_wait_sig(&fnp->fn_wait_cv, &fn_lock->flk_lock)) {
fifo_cleanup(oldvp, flag);
if (!lockheld)
mutex_exit(&fn_lock->flk_lock);
return (EINTR);
}
}
if ((fnp->fn_flag & (FIFOCLOSE|ISPIPE)) == (FIFOCLOSE|ISPIPE)) {
fifo_cleanup(oldvp, flag);
cv_broadcast(&fnp->fn_wait_cv);
if (!lockheld)
mutex_exit(&fn_lock->flk_lock);
return (ENXIO);
}
fnp->fn_flag |= FIFOOPEN;
while (fn_lock->flk_ocsync)
cv_wait(&fn_lock->flk_wait_cv, &fn_lock->flk_lock);
fn_lock->flk_ocsync = 1;
if (fnp->fn_flag & FIFOCONNLD) {
mutex_exit(&fn_lock->flk_lock);
if ((error = stropen(oldvp, &pdev, flag, crp)) != 0) {
mutex_enter(&fn_lock->flk_lock);
fifo_cleanup(oldvp, flag);
fn_lock->flk_ocsync = 0;
cv_broadcast(&fn_lock->flk_wait_cv);
goto out;
}
mutex_enter(&fn_lock->flk_lock);
ASSERT(fnp->fn_open > 0);
fnp->fn_open++;
fn_lock->flk_ocsync = 0;
cv_broadcast(&fn_lock->flk_wait_cv);
mutex_exit(&fn_lock->flk_lock);
if (error = fifo_connld(vpp, flag, crp)) {
(void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
mutex_enter(&fn_lock->flk_lock);
goto out;
}
(void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
fnp = VTOF(*vpp);
fn_lock = fnp->fn_lock;
mutex_enter(&fn_lock->flk_lock);
} else {
mutex_exit(&fn_lock->flk_lock);
if (oldvp->v_stream == NULL)
firstopen = 1;
if ((error = stropen(oldvp, &pdev, flag, crp)) != 0) {
mutex_enter(&fn_lock->flk_lock);
fifo_cleanup(oldvp, flag);
ASSERT(fnp->fn_open != 0 || oldvp->v_stream == NULL);
fn_lock->flk_ocsync = 0;
cv_broadcast(&fn_lock->flk_wait_cv);
goto out;
}
mutex_enter(&fn_lock->flk_lock);
if (dotwist && firstopen)
strmate(*vpp, *vpp);
fnp->fn_open++;
fn_lock->flk_ocsync = 0;
cv_broadcast(&fn_lock->flk_wait_cv);
}
out:
fnp->fn_flag &= ~FIFOOPEN;
if (error == 0) {
fnp->fn_flag |= FIFOISOPEN;
if (((fnp->fn_flag & (ISPIPE|FIFOCLOSE)) == FIFOCLOSE) &&
fnp->fn_wcnt > 0)
fnp->fn_flag &= ~FIFOCLOSE;
}
cv_broadcast(&fnp->fn_wait_cv);
if (!lockheld)
mutex_exit(&fn_lock->flk_lock);
return (error);
}
void
fifo_cleanup(vnode_t *vp, int flag)
{
fifonode_t *fnp = VTOF(vp);
ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
cleanlocks(vp, curproc->p_pid, 0);
cleanshares(vp, curproc->p_pid);
if (flag & FREAD) {
fnp->fn_rcnt--;
}
if (flag & FWRITE) {
fnp->fn_wcnt--;
}
cv_broadcast(&fnp->fn_wait_cv);
}
static void
fifoinsert(fifonode_t *fnp)
{
int idx = FIFOHASH(fnp->fn_realvp);
ASSERT(MUTEX_HELD(&ftable_lock));
fnp->fn_backp = NULL;
fnp->fn_nextp = fifoalloc[idx];
fifoalloc[idx] = fnp;
if (fnp->fn_nextp)
fnp->fn_nextp->fn_backp = fnp;
}
static fifonode_t *
fifofind(vnode_t *vp)
{
fifonode_t *fnode;
ASSERT(MUTEX_HELD(&ftable_lock));
for (fnode = fifoalloc[FIFOHASH(vp)]; fnode; fnode = fnode->fn_nextp) {
if (fnode->fn_realvp == vp) {
VN_HOLD(FTOV(fnode));
return (fnode);
}
}
return (NULL);
}
void
fiforemove(fifonode_t *fnp)
{
int idx = FIFOHASH(fnp->fn_realvp);
fifonode_t *fnode;
ASSERT(MUTEX_HELD(&ftable_lock));
fnode = fifoalloc[idx];
if (fnode != NULL && fnode == fnp &&
!fnode->fn_nextp && !fnode->fn_backp) {
fifoalloc[idx] = NULL;
} else {
for (; fnode; fnode = fnode->fn_nextp) {
if (fnode == fnp) {
if (fnp == fifoalloc[idx])
fifoalloc[idx] = fnp->fn_nextp;
if (fnode->fn_nextp)
fnode->fn_nextp->fn_backp =
fnode->fn_backp;
if (fnode->fn_backp)
fnode->fn_backp->fn_nextp =
fnode->fn_nextp;
break;
}
}
}
}
void
fifo_fastflush(fifonode_t *fnp)
{
mblk_t *bp;
ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
if ((bp = fnp->fn_mp) != NULL) {
fnp->fn_mp = NULL;
fnp->fn_count = 0;
freemsg(bp);
}
fifo_wakewriter(fnp->fn_dest, fnp->fn_lock);
}
static int
fifo_connld(struct vnode **vpp, int flag, cred_t *crp)
{
struct vnode *vp1;
struct vnode *vp2;
struct fifonode *oldfnp;
struct fifonode *fn_dest;
int error;
struct file *filep;
struct fifolock *fn_lock;
cred_t *c;
makepipe(&vp1, &vp2);
if (error = falloc(vp1, FWRITE|FREAD, &filep, NULL)) {
VN_RELE(vp1);
VN_RELE(vp2);
return (error);
}
mutex_exit(&filep->f_tlock);
oldfnp = VTOF(*vpp);
fn_lock = oldfnp->fn_lock;
fn_dest = oldfnp->fn_dest;
if ((error = fifo_stropen(&vp1, FREAD|FWRITE, filep->f_cred, 0, 0)) !=
0 ||
(error = fifo_stropen(&vp2, flag, filep->f_cred, 0, 0)) != 0) {
#if DEBUG
cmn_err(CE_NOTE, "fifo stropen failed error 0x%x", error);
#endif
(void) closef(filep);
VN_RELE(vp2);
return (error);
}
strmate(vp1, vp2);
VTOF(vp2)->fn_flag |= FIFOOPEN;
mutex_enter(&fn_lock->flk_lock);
fn_dest->fn_flag |= FIFOSEND;
if (!(fn_dest->fn_flag & FIFOISOPEN)) {
error = ENXIO;
fn_dest->fn_flag &= ~FIFOSEND;
mutex_exit(&fn_lock->flk_lock);
goto out;
}
mutex_exit(&fn_lock->flk_lock);
crhold(VTOF(vp1)->fn_pcredp = crp);
VTOF(vp1)->fn_cpid = curproc->p_pid;
if (error = do_sendfp((*vpp)->v_stream, filep, crp)) {
mutex_enter(&fn_lock->flk_lock);
fn_dest->fn_flag &= ~FIFOSEND;
mutex_exit(&fn_lock->flk_lock);
goto out;
}
mutex_enter(&fn_lock->flk_lock);
while ((fn_dest->fn_flag & (FIFOCLOSE | FIFOSEND)) == FIFOSEND) {
if (!cv_wait_sig(&oldfnp->fn_wait_cv, &fn_lock->flk_lock)) {
error = EINTR;
fn_dest->fn_flag &= ~FIFOSEND;
mutex_exit(&fn_lock->flk_lock);
goto out;
}
}
if ((fn_dest->fn_flag & FIFOSEND)) {
error = ENXIO;
fn_dest->fn_flag &= ~FIFOSEND;
mutex_exit(&fn_lock->flk_lock);
goto out;
}
oldfnp->fn_flag &= ~FIFOOPEN;
cv_broadcast(&oldfnp->fn_wait_cv);
mutex_exit(&fn_lock->flk_lock);
VN_RELE(*vpp);
*vpp = vp2;
(void) closef(filep);
return (0);
out:
c = filep->f_cred;
crhold(c);
(void) closef(filep);
VTOF(vp2)->fn_flag &= ~FIFOOPEN;
(void) fifo_close(vp2, flag, 1, (offset_t)0, c, NULL);
crfree(c);
VN_RELE(vp2);
return (error);
}
void
fifo_fastoff(fifonode_t *fnp)
{
ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
ASSERT(FTOV(fnp)->v_stream);
while ((fnp->fn_flag & FIFOSTAYFAST) || ((fnp->fn_flag & ISPIPE) &&
(fnp->fn_dest->fn_flag & FIFOSTAYFAST))) {
ASSERT(fnp->fn_flag & FIFOFAST);
fnp->fn_flag |= FIFOWAITMODE;
cv_wait(&fnp->fn_wait_cv, &fnp->fn_lock->flk_lock);
fnp->fn_flag &= ~FIFOWAITMODE;
}
if (!(fnp->fn_flag & FIFOFAST))
return;
#if FIFODEBUG
if (Fifo_verbose)
cmn_err(CE_NOTE, "Fifo reverting to streams mode\n");
#endif
fifo_fastturnoff(fnp);
if (fnp->fn_flag & ISPIPE) {
fifo_fastturnoff(fnp->fn_dest);
}
}
static void
fifo_fastturnoff(fifonode_t *fnp)
{
fifonode_t *fn_dest = fnp->fn_dest;
mblk_t *fn_mp;
int fn_flag;
ASSERT(MUTEX_HELD(&fnp->fn_lock->flk_lock));
if ((fn_mp = fnp->fn_mp) != NULL) {
ASSERT(fnp->fn_flag & FIFOISOPEN);
ASSERT(FTOV(fnp)->v_stream != NULL);
ASSERT(FTOV(fnp)->v_stream->sd_wrq != NULL);
ASSERT(RD(FTOV(fnp)->v_stream->sd_wrq) != NULL);
ASSERT(strvp2wq(FTOV(fnp)) != NULL);
fnp->fn_mp = NULL;
fnp->fn_count = 0;
put(RD(strvp2wq(FTOV(fnp))), fn_mp);
}
if ((fnp->fn_flag & (FIFOISOPEN | FIFOPOLLW)) ==
(FIFOISOPEN | FIFOPOLLW)) {
strpollwakeup(FTOV(fnp), POLLWRNORM);
}
fn_flag = fn_dest->fn_flag;
if ((fn_flag & FIFOISOPEN) == FIFOISOPEN) {
if ((fn_flag & (FIFOPOLLR | FIFOPOLLRBAND))) {
strpollwakeup(FTOV(fn_dest), POLLIN|POLLRDNORM);
}
}
fnp->fn_flag &= ~(FIFOFAST|FIFOWANTW|FIFOWANTR);
cv_broadcast(&fnp->fn_wait_cv);
}
void
fifo_vfastoff(vnode_t *vp)
{
fifonode_t *fnp = VTOF(vp);
mutex_enter(&fnp->fn_lock->flk_lock);
if (!(fnp->fn_flag & FIFOFAST)) {
mutex_exit(&fnp->fn_lock->flk_lock);
return;
}
fifo_fastoff(fnp);
mutex_exit(&fnp->fn_lock->flk_lock);
}
void
fifo_wakewriter(fifonode_t *fn_dest, fifolock_t *fn_lock)
{
int fn_dflag = fn_dest->fn_flag;
ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
ASSERT(fn_dest->fn_dest->fn_count < Fifohiwat);
if ((fn_dflag & FIFOWANTW)) {
cv_broadcast(&fn_dest->fn_wait_cv);
}
if ((fn_dflag & (FIFOHIWATW | FIFOISOPEN)) ==
(FIFOHIWATW | FIFOISOPEN)) {
if (fn_dflag & FIFOPOLLW)
strpollwakeup(FTOV(fn_dest), POLLWRNORM);
if (fn_dflag & FIFOSETSIG)
str_sendsig(FTOV(fn_dest), S_WRNORM, 0, 0);
}
fn_dest->fn_flag = fn_dflag & ~(FIFOWANTW | FIFOHIWATW | FIFOPOLLW);
}
void
fifo_wakereader(fifonode_t *fn_dest, fifolock_t *fn_lock)
{
int fn_dflag = fn_dest->fn_flag;
ASSERT(MUTEX_HELD(&fn_lock->flk_lock));
if (fn_dflag & FIFOWANTR) {
cv_broadcast(&fn_dest->fn_wait_cv);
}
if (fn_dflag & FIFOISOPEN) {
if (fn_dflag & FIFOPOLLR)
strpollwakeup(FTOV(fn_dest), POLLIN | POLLRDNORM);
if (fn_dflag & FIFOSETSIG)
str_sendsig(FTOV(fn_dest), S_INPUT | S_RDNORM, 0, 0);
}
fn_dest->fn_flag = fn_dflag & ~(FIFOWANTR | FIFOPOLLR);
}