140292Smckusick /* 240292Smckusick * Copyright (c) 1990 The Regents of the University of California. 340292Smckusick * All rights reserved. 440292Smckusick * 540292Smckusick * Redistribution and use in source and binary forms are permitted 640292Smckusick * provided that the above copyright notice and this paragraph are 740292Smckusick * duplicated in all such forms and that any documentation, 840292Smckusick * advertising materials, and other materials related to such 940292Smckusick * distribution and use acknowledge that the software was developed 1040292Smckusick * by the University of California, Berkeley. The name of the 1140292Smckusick * University may not be used to endorse or promote products derived 1240292Smckusick * from this software without specific prior written permission. 1340292Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1440292Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1540292Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1640292Smckusick * 17*40655Smckusick * @(#)fifo_vnops.c 7.3 (Berkeley) 03/27/90 1840292Smckusick */ 1940292Smckusick 2040292Smckusick #include "param.h" 2140292Smckusick #include "time.h" 2240292Smckusick #include "namei.h" 2340292Smckusick #include "vnode.h" 2440292Smckusick #include "socket.h" 2540292Smckusick #include "socketvar.h" 2640292Smckusick #include "stat.h" 2740292Smckusick #include "ioctl.h" 2840292Smckusick #include "file.h" 2940292Smckusick #include "errno.h" 3040292Smckusick #include "malloc.h" 3140292Smckusick 3240292Smckusick /* 3340292Smckusick * This structure is associated with the FIFO vnode and stores 3440292Smckusick * the state associated with the FIFO. 3540292Smckusick */ 3640292Smckusick struct fifoinfo { 3740292Smckusick struct socket *fi_readsock; 3840292Smckusick struct socket *fi_writesock; 3940292Smckusick long fi_readers; 4040292Smckusick long fi_writers; 4140292Smckusick }; 4240292Smckusick 4340292Smckusick int fifo_lookup(), 4440292Smckusick fifo_open(), 4540292Smckusick fifo_read(), 4640292Smckusick fifo_write(), 4740292Smckusick fifo_strategy(), 4840292Smckusick fifo_bmap(), 4940292Smckusick fifo_ioctl(), 5040292Smckusick fifo_select(), 5140292Smckusick fifo_lock(), 5240292Smckusick fifo_unlock(), 5340292Smckusick fifo_close(), 5440292Smckusick fifo_print(), 5540292Smckusick fifo_ebadf(), 5640292Smckusick fifo_badop(), 5740292Smckusick fifo_nullop(); 5840292Smckusick 5940292Smckusick struct vnodeops fifo_vnodeops = { 6040292Smckusick fifo_lookup, /* lookup */ 6140292Smckusick fifo_badop, /* create */ 6240292Smckusick fifo_badop, /* mknod */ 6340292Smckusick fifo_open, /* open */ 6440292Smckusick fifo_close, /* close */ 6540292Smckusick fifo_ebadf, /* access */ 6640292Smckusick fifo_ebadf, /* getattr */ 6740292Smckusick fifo_ebadf, /* setattr */ 6840292Smckusick fifo_read, /* read */ 6940292Smckusick fifo_write, /* write */ 7040292Smckusick fifo_ioctl, /* ioctl */ 7140292Smckusick fifo_select, /* select */ 7240292Smckusick fifo_badop, /* mmap */ 7340292Smckusick fifo_nullop, /* fsync */ 7440292Smckusick fifo_badop, /* seek */ 7540292Smckusick fifo_badop, /* remove */ 7640292Smckusick fifo_badop, /* link */ 7740292Smckusick fifo_badop, /* rename */ 7840292Smckusick fifo_badop, /* mkdir */ 7940292Smckusick fifo_badop, /* rmdir */ 8040292Smckusick fifo_badop, /* symlink */ 8140292Smckusick fifo_badop, /* readdir */ 8240292Smckusick fifo_badop, /* readlink */ 8340292Smckusick fifo_badop, /* abortop */ 8440292Smckusick fifo_nullop, /* inactive */ 8540292Smckusick fifo_nullop, /* reclaim */ 8640292Smckusick fifo_lock, /* lock */ 8740292Smckusick fifo_unlock, /* unlock */ 8840292Smckusick fifo_bmap, /* bmap */ 8940292Smckusick fifo_badop, /* strategy */ 9040292Smckusick fifo_print, /* print */ 9140292Smckusick fifo_nullop, /* islocked */ 9240292Smckusick }; 9340292Smckusick 9440292Smckusick /* 9540292Smckusick * Trivial lookup routine that always fails. 9640292Smckusick */ 9740292Smckusick fifo_lookup(vp, ndp) 9840292Smckusick struct vnode *vp; 9940292Smckusick struct nameidata *ndp; 10040292Smckusick { 10140292Smckusick 10240292Smckusick ndp->ni_dvp = vp; 10340292Smckusick ndp->ni_vp = NULL; 10440292Smckusick return (ENOTDIR); 10540292Smckusick } 10640292Smckusick 10740292Smckusick /* 10840292Smckusick * Open called to set up a new instance of a fifo or 10940292Smckusick * to find an active instance of a fifo. 11040292Smckusick */ 11140292Smckusick /* ARGSUSED */ 11240292Smckusick fifo_open(vp, mode, cred) 11340292Smckusick register struct vnode *vp; 11440292Smckusick int mode; 11540292Smckusick struct ucred *cred; 11640292Smckusick { 11740292Smckusick register struct fifoinfo *fip; 11840292Smckusick struct socket *rso, *wso; 11940292Smckusick int error; 12040637Skarels static char openstr[] = "fifo"; 12140292Smckusick 12240292Smckusick if ((mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) 12340292Smckusick return (EINVAL); 12440292Smckusick if ((fip = vp->v_fifoinfo) == NULL) { 12540292Smckusick MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); 12640292Smckusick vp->v_fifoinfo = fip; 127*40655Smckusick if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) { 128*40655Smckusick free(fip, M_VNODE); 129*40655Smckusick vp->v_fifoinfo = NULL; 13040292Smckusick return (error); 131*40655Smckusick } 13240292Smckusick fip->fi_readsock = rso; 13340292Smckusick if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) { 13440292Smckusick (void)soclose(rso); 135*40655Smckusick free(fip, M_VNODE); 136*40655Smckusick vp->v_fifoinfo = NULL; 13740292Smckusick return (error); 13840292Smckusick } 13940292Smckusick fip->fi_writesock = wso; 14040292Smckusick if (error = unp_connect2(wso, rso)) { 14140292Smckusick (void)soclose(wso); 14240292Smckusick (void)soclose(rso); 143*40655Smckusick free(fip, M_VNODE); 144*40655Smckusick vp->v_fifoinfo = NULL; 14540292Smckusick return (error); 14640292Smckusick } 14740292Smckusick wso->so_state |= SS_CANTRCVMORE; 14840292Smckusick rso->so_state |= SS_CANTSENDMORE; 14940292Smckusick } 15040292Smckusick error = 0; 15140292Smckusick if (mode & FREAD) { 15240292Smckusick fip->fi_readers++; 15340292Smckusick if (fip->fi_readers == 1) { 15440292Smckusick fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; 15540292Smckusick if (fip->fi_writers > 0) 15640292Smckusick wakeup((caddr_t)&fip->fi_writers); 15740292Smckusick } 15840292Smckusick if (mode & O_NONBLOCK) 15940292Smckusick return (0); 16040292Smckusick while (fip->fi_writers == 0) 16140637Skarels if (error = tsleep((caddr_t)&fip->fi_readers, PSOCK, 16240637Skarels openstr, 0)) 16340292Smckusick break; 16440292Smckusick } else { 16540292Smckusick fip->fi_writers++; 16640292Smckusick if (fip->fi_readers == 0 && (mode & O_NONBLOCK)) { 16740292Smckusick error = ENXIO; 16840292Smckusick } else { 16940292Smckusick if (fip->fi_writers == 1) { 17040292Smckusick fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; 17140292Smckusick if (fip->fi_readers > 0) 17240292Smckusick wakeup((caddr_t)&fip->fi_readers); 17340292Smckusick } 17440292Smckusick while (fip->fi_readers == 0) 17540637Skarels if (error = tsleep((caddr_t)&fip->fi_writers, 17640637Skarels PSOCK, openstr, 0)) 17740292Smckusick break; 17840292Smckusick } 17940292Smckusick } 18040292Smckusick if (error) 18140292Smckusick fifo_close(vp, mode, cred); 18240292Smckusick return (error); 18340292Smckusick } 18440292Smckusick 18540292Smckusick /* 18640292Smckusick * Vnode op for read 18740292Smckusick */ 18840292Smckusick /* ARGSUSED */ 18940292Smckusick fifo_read(vp, uio, ioflag, cred) 19040292Smckusick struct vnode *vp; 19140292Smckusick register struct uio *uio; 19240292Smckusick int ioflag; 19340292Smckusick struct ucred *cred; 19440292Smckusick { 19540292Smckusick register struct socket *rso = vp->v_fifoinfo->fi_readsock; 19640292Smckusick int error, startresid; 19740292Smckusick 19840292Smckusick if (uio->uio_rw != UIO_READ) 19940292Smckusick panic("fifo_read mode"); 20040292Smckusick if (uio->uio_resid == 0) 20140292Smckusick return (0); 20240292Smckusick if (ioflag & IO_NDELAY) 20340292Smckusick rso->so_state |= SS_NBIO; 20440292Smckusick startresid = uio->uio_resid; 20540292Smckusick VOP_UNLOCK(vp); 20640292Smckusick error = soreceive(rso, (struct mbuf **)0, uio, (int *)0, 20740292Smckusick (struct mbuf **)0, (struct mbuf **)0); 20840292Smckusick VOP_LOCK(vp); 20940292Smckusick /* 21040292Smckusick * Clear EOF indication after first such return. 21140292Smckusick */ 21240292Smckusick if (uio->uio_resid == startresid) 21340292Smckusick rso->so_state &= ~SS_CANTRCVMORE; 21440292Smckusick if (ioflag & IO_NDELAY) 21540292Smckusick rso->so_state &= ~SS_NBIO; 21640292Smckusick return (error); 21740292Smckusick } 21840292Smckusick 21940292Smckusick /* 22040292Smckusick * Vnode op for write 22140292Smckusick */ 22240292Smckusick /* ARGSUSED */ 22340292Smckusick fifo_write(vp, uio, ioflag, cred) 22440292Smckusick struct vnode *vp; 22540292Smckusick register struct uio *uio; 22640292Smckusick int ioflag; 22740292Smckusick struct ucred *cred; 22840292Smckusick { 22940292Smckusick struct socket *wso = vp->v_fifoinfo->fi_writesock; 23040292Smckusick int error; 23140292Smckusick 23240292Smckusick if (uio->uio_rw != UIO_WRITE) 23340292Smckusick panic("fifo_write mode"); 23440292Smckusick if (ioflag & IO_NDELAY) 23540292Smckusick wso->so_state |= SS_NBIO; 23640292Smckusick VOP_UNLOCK(vp); 23740292Smckusick error = sosend(wso, (struct mbuf *)0, uio, 0, (struct mbuf *)0); 23840292Smckusick VOP_LOCK(vp); 23940292Smckusick if (ioflag & IO_NDELAY) 24040292Smckusick wso->so_state &= ~SS_NBIO; 24140292Smckusick return (error); 24240292Smckusick } 24340292Smckusick 24440292Smckusick /* 24540292Smckusick * Device ioctl operation. 24640292Smckusick */ 24740292Smckusick /* ARGSUSED */ 24840292Smckusick fifo_ioctl(vp, com, data, fflag, cred) 24940292Smckusick struct vnode *vp; 25040292Smckusick int com; 25140292Smckusick caddr_t data; 25240292Smckusick int fflag; 25340292Smckusick struct ucred *cred; 25440292Smckusick { 25540292Smckusick struct file filetmp; 25640292Smckusick int error; 25740292Smckusick 25840292Smckusick if (com == FIONBIO) 25940292Smckusick return (0); 26040292Smckusick if (fflag & FREAD) 26140292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; 26240292Smckusick else 26340292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; 26440292Smckusick return (soo_ioctl(&filetmp, com, data)); 26540292Smckusick } 26640292Smckusick 26740292Smckusick /* ARGSUSED */ 26840292Smckusick fifo_select(vp, which, fflag, cred) 26940292Smckusick struct vnode *vp; 27040292Smckusick int which, fflag; 27140292Smckusick struct ucred *cred; 27240292Smckusick { 27340292Smckusick struct file filetmp; 27440292Smckusick int error; 27540292Smckusick 27640292Smckusick if (fflag & FREAD) 27740292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; 27840292Smckusick else 27940292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; 28040292Smckusick return (soo_select(&filetmp, which)); 28140292Smckusick } 28240292Smckusick 28340292Smckusick /* 28440292Smckusick * This is a noop, simply returning what one has been given. 28540292Smckusick */ 28640292Smckusick fifo_bmap(vp, bn, vpp, bnp) 28740292Smckusick struct vnode *vp; 28840292Smckusick daddr_t bn; 28940292Smckusick struct vnode **vpp; 29040292Smckusick daddr_t *bnp; 29140292Smckusick { 29240292Smckusick 29340292Smckusick if (vpp != NULL) 29440292Smckusick *vpp = vp; 29540292Smckusick if (bnp != NULL) 29640292Smckusick *bnp = bn; 29740292Smckusick return (0); 29840292Smckusick } 29940292Smckusick 30040292Smckusick /* 30140292Smckusick * At the moment we do not do any locking. 30240292Smckusick */ 30340292Smckusick /* ARGSUSED */ 30440292Smckusick fifo_lock(vp) 30540292Smckusick struct vnode *vp; 30640292Smckusick { 30740292Smckusick 30840292Smckusick return (0); 30940292Smckusick } 31040292Smckusick 31140292Smckusick /* ARGSUSED */ 31240292Smckusick fifo_unlock(vp) 31340292Smckusick struct vnode *vp; 31440292Smckusick { 31540292Smckusick 31640292Smckusick return (0); 31740292Smckusick } 31840292Smckusick 31940292Smckusick /* 32040292Smckusick * Device close routine 32140292Smckusick */ 32240292Smckusick /* ARGSUSED */ 32340292Smckusick fifo_close(vp, fflag, cred) 32440292Smckusick register struct vnode *vp; 32540292Smckusick int fflag; 32640292Smckusick struct ucred *cred; 32740292Smckusick { 32840292Smckusick register struct fifoinfo *fip = vp->v_fifoinfo; 32940292Smckusick int error1, error2; 33040292Smckusick 33140292Smckusick if (fflag & FWRITE) { 33240292Smckusick fip->fi_writers--; 33340292Smckusick if (fip->fi_writers == 0) 33440292Smckusick socantrcvmore(fip->fi_readsock); 33540292Smckusick } else { 33640292Smckusick fip->fi_readers--; 33740292Smckusick if (fip->fi_readers == 0) 33840292Smckusick socantsendmore(fip->fi_writesock); 33940292Smckusick } 34040292Smckusick if (vp->v_usecount > 1) 34140292Smckusick return (0); 34240292Smckusick error1 = soclose(fip->fi_readsock); 34340292Smckusick error2 = soclose(fip->fi_writesock); 34440292Smckusick FREE(fip, M_VNODE); 34540292Smckusick vp->v_fifoinfo = NULL; 34640292Smckusick if (error1) 34740292Smckusick return (error1); 34840292Smckusick return (error2); 34940292Smckusick } 35040292Smckusick 35140292Smckusick /* 35240292Smckusick * Print out the contents of a fifo vnode. 35340292Smckusick */ 35440292Smckusick fifo_print(vp) 35540292Smckusick struct vnode *vp; 35640292Smckusick { 35740292Smckusick 35840292Smckusick printf("tag VT_NON"); 35940292Smckusick fifo_printinfo(vp); 36040292Smckusick printf("\n"); 36140292Smckusick } 36240292Smckusick 36340292Smckusick /* 36440292Smckusick * Print out internal contents of a fifo vnode. 36540292Smckusick */ 36640292Smckusick fifo_printinfo(vp) 36740292Smckusick struct vnode *vp; 36840292Smckusick { 36940292Smckusick register struct fifoinfo *fip = vp->v_fifoinfo; 37040292Smckusick 37140292Smckusick printf(", fifo with %d readers and %d writers", 37240292Smckusick fip->fi_readers, fip->fi_writers); 37340292Smckusick } 37440292Smckusick 37540292Smckusick /* 37640292Smckusick * Fifo failed operation 37740292Smckusick */ 37840292Smckusick fifo_ebadf() 37940292Smckusick { 38040292Smckusick 38140292Smckusick return (EBADF); 38240292Smckusick } 38340292Smckusick 38440292Smckusick /* 38540292Smckusick * Fifo bad operation 38640292Smckusick */ 38740292Smckusick fifo_badop() 38840292Smckusick { 38940292Smckusick 39040292Smckusick panic("fifo_badop called"); 39140292Smckusick /* NOTREACHED */ 39240292Smckusick } 39340292Smckusick 39440292Smckusick /* 39540292Smckusick * Fifo null operation 39640292Smckusick */ 39740292Smckusick fifo_nullop() 39840292Smckusick { 39940292Smckusick 40040292Smckusick return (0); 40140292Smckusick } 402