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*40637Skarels * @(#)fifo_vnops.c 7.2 (Berkeley) 03/26/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; 120*40637Skarels 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; 12740292Smckusick if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) 12840292Smckusick return (error); 12940292Smckusick fip->fi_readsock = rso; 13040292Smckusick if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) { 13140292Smckusick (void)soclose(rso); 13240292Smckusick return (error); 13340292Smckusick } 13440292Smckusick fip->fi_writesock = wso; 13540292Smckusick if (error = unp_connect2(wso, rso)) { 13640292Smckusick (void)soclose(wso); 13740292Smckusick (void)soclose(rso); 13840292Smckusick return (error); 13940292Smckusick } 14040292Smckusick wso->so_state |= SS_CANTRCVMORE; 14140292Smckusick rso->so_state |= SS_CANTSENDMORE; 14240292Smckusick } 14340292Smckusick error = 0; 14440292Smckusick if (mode & FREAD) { 14540292Smckusick fip->fi_readers++; 14640292Smckusick if (fip->fi_readers == 1) { 14740292Smckusick fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; 14840292Smckusick if (fip->fi_writers > 0) 14940292Smckusick wakeup((caddr_t)&fip->fi_writers); 15040292Smckusick } 15140292Smckusick if (mode & O_NONBLOCK) 15240292Smckusick return (0); 15340292Smckusick while (fip->fi_writers == 0) 154*40637Skarels if (error = tsleep((caddr_t)&fip->fi_readers, PSOCK, 155*40637Skarels openstr, 0)) 15640292Smckusick break; 15740292Smckusick } else { 15840292Smckusick fip->fi_writers++; 15940292Smckusick if (fip->fi_readers == 0 && (mode & O_NONBLOCK)) { 16040292Smckusick error = ENXIO; 16140292Smckusick } else { 16240292Smckusick if (fip->fi_writers == 1) { 16340292Smckusick fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; 16440292Smckusick if (fip->fi_readers > 0) 16540292Smckusick wakeup((caddr_t)&fip->fi_readers); 16640292Smckusick } 16740292Smckusick while (fip->fi_readers == 0) 168*40637Skarels if (error = tsleep((caddr_t)&fip->fi_writers, 169*40637Skarels PSOCK, openstr, 0)) 17040292Smckusick break; 17140292Smckusick } 17240292Smckusick } 17340292Smckusick if (error) 17440292Smckusick fifo_close(vp, mode, cred); 17540292Smckusick return (error); 17640292Smckusick } 17740292Smckusick 17840292Smckusick /* 17940292Smckusick * Vnode op for read 18040292Smckusick */ 18140292Smckusick /* ARGSUSED */ 18240292Smckusick fifo_read(vp, uio, ioflag, cred) 18340292Smckusick struct vnode *vp; 18440292Smckusick register struct uio *uio; 18540292Smckusick int ioflag; 18640292Smckusick struct ucred *cred; 18740292Smckusick { 18840292Smckusick register struct socket *rso = vp->v_fifoinfo->fi_readsock; 18940292Smckusick int error, startresid; 19040292Smckusick 19140292Smckusick if (uio->uio_rw != UIO_READ) 19240292Smckusick panic("fifo_read mode"); 19340292Smckusick if (uio->uio_resid == 0) 19440292Smckusick return (0); 19540292Smckusick if (ioflag & IO_NDELAY) 19640292Smckusick rso->so_state |= SS_NBIO; 19740292Smckusick startresid = uio->uio_resid; 19840292Smckusick VOP_UNLOCK(vp); 19940292Smckusick error = soreceive(rso, (struct mbuf **)0, uio, (int *)0, 20040292Smckusick (struct mbuf **)0, (struct mbuf **)0); 20140292Smckusick VOP_LOCK(vp); 20240292Smckusick /* 20340292Smckusick * Clear EOF indication after first such return. 20440292Smckusick */ 20540292Smckusick if (uio->uio_resid == startresid) 20640292Smckusick rso->so_state &= ~SS_CANTRCVMORE; 20740292Smckusick if (ioflag & IO_NDELAY) 20840292Smckusick rso->so_state &= ~SS_NBIO; 20940292Smckusick return (error); 21040292Smckusick } 21140292Smckusick 21240292Smckusick /* 21340292Smckusick * Vnode op for write 21440292Smckusick */ 21540292Smckusick /* ARGSUSED */ 21640292Smckusick fifo_write(vp, uio, ioflag, cred) 21740292Smckusick struct vnode *vp; 21840292Smckusick register struct uio *uio; 21940292Smckusick int ioflag; 22040292Smckusick struct ucred *cred; 22140292Smckusick { 22240292Smckusick struct socket *wso = vp->v_fifoinfo->fi_writesock; 22340292Smckusick int error; 22440292Smckusick 22540292Smckusick if (uio->uio_rw != UIO_WRITE) 22640292Smckusick panic("fifo_write mode"); 22740292Smckusick if (ioflag & IO_NDELAY) 22840292Smckusick wso->so_state |= SS_NBIO; 22940292Smckusick VOP_UNLOCK(vp); 23040292Smckusick error = sosend(wso, (struct mbuf *)0, uio, 0, (struct mbuf *)0); 23140292Smckusick VOP_LOCK(vp); 23240292Smckusick if (ioflag & IO_NDELAY) 23340292Smckusick wso->so_state &= ~SS_NBIO; 23440292Smckusick return (error); 23540292Smckusick } 23640292Smckusick 23740292Smckusick /* 23840292Smckusick * Device ioctl operation. 23940292Smckusick */ 24040292Smckusick /* ARGSUSED */ 24140292Smckusick fifo_ioctl(vp, com, data, fflag, cred) 24240292Smckusick struct vnode *vp; 24340292Smckusick int com; 24440292Smckusick caddr_t data; 24540292Smckusick int fflag; 24640292Smckusick struct ucred *cred; 24740292Smckusick { 24840292Smckusick struct file filetmp; 24940292Smckusick int error; 25040292Smckusick 25140292Smckusick if (com == FIONBIO) 25240292Smckusick return (0); 25340292Smckusick if (fflag & FREAD) 25440292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; 25540292Smckusick else 25640292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; 25740292Smckusick return (soo_ioctl(&filetmp, com, data)); 25840292Smckusick } 25940292Smckusick 26040292Smckusick /* ARGSUSED */ 26140292Smckusick fifo_select(vp, which, fflag, cred) 26240292Smckusick struct vnode *vp; 26340292Smckusick int which, fflag; 26440292Smckusick struct ucred *cred; 26540292Smckusick { 26640292Smckusick struct file filetmp; 26740292Smckusick int error; 26840292Smckusick 26940292Smckusick if (fflag & FREAD) 27040292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; 27140292Smckusick else 27240292Smckusick filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; 27340292Smckusick return (soo_select(&filetmp, which)); 27440292Smckusick } 27540292Smckusick 27640292Smckusick /* 27740292Smckusick * This is a noop, simply returning what one has been given. 27840292Smckusick */ 27940292Smckusick fifo_bmap(vp, bn, vpp, bnp) 28040292Smckusick struct vnode *vp; 28140292Smckusick daddr_t bn; 28240292Smckusick struct vnode **vpp; 28340292Smckusick daddr_t *bnp; 28440292Smckusick { 28540292Smckusick 28640292Smckusick if (vpp != NULL) 28740292Smckusick *vpp = vp; 28840292Smckusick if (bnp != NULL) 28940292Smckusick *bnp = bn; 29040292Smckusick return (0); 29140292Smckusick } 29240292Smckusick 29340292Smckusick /* 29440292Smckusick * At the moment we do not do any locking. 29540292Smckusick */ 29640292Smckusick /* ARGSUSED */ 29740292Smckusick fifo_lock(vp) 29840292Smckusick struct vnode *vp; 29940292Smckusick { 30040292Smckusick 30140292Smckusick return (0); 30240292Smckusick } 30340292Smckusick 30440292Smckusick /* ARGSUSED */ 30540292Smckusick fifo_unlock(vp) 30640292Smckusick struct vnode *vp; 30740292Smckusick { 30840292Smckusick 30940292Smckusick return (0); 31040292Smckusick } 31140292Smckusick 31240292Smckusick /* 31340292Smckusick * Device close routine 31440292Smckusick */ 31540292Smckusick /* ARGSUSED */ 31640292Smckusick fifo_close(vp, fflag, cred) 31740292Smckusick register struct vnode *vp; 31840292Smckusick int fflag; 31940292Smckusick struct ucred *cred; 32040292Smckusick { 32140292Smckusick register struct fifoinfo *fip = vp->v_fifoinfo; 32240292Smckusick int error1, error2; 32340292Smckusick 32440292Smckusick if (fflag & FWRITE) { 32540292Smckusick fip->fi_writers--; 32640292Smckusick if (fip->fi_writers == 0) 32740292Smckusick socantrcvmore(fip->fi_readsock); 32840292Smckusick } else { 32940292Smckusick fip->fi_readers--; 33040292Smckusick if (fip->fi_readers == 0) 33140292Smckusick socantsendmore(fip->fi_writesock); 33240292Smckusick } 33340292Smckusick if (vp->v_usecount > 1) 33440292Smckusick return (0); 33540292Smckusick error1 = soclose(fip->fi_readsock); 33640292Smckusick error2 = soclose(fip->fi_writesock); 33740292Smckusick FREE(fip, M_VNODE); 33840292Smckusick vp->v_fifoinfo = NULL; 33940292Smckusick if (error1) 34040292Smckusick return (error1); 34140292Smckusick return (error2); 34240292Smckusick } 34340292Smckusick 34440292Smckusick /* 34540292Smckusick * Print out the contents of a fifo vnode. 34640292Smckusick */ 34740292Smckusick fifo_print(vp) 34840292Smckusick struct vnode *vp; 34940292Smckusick { 35040292Smckusick 35140292Smckusick printf("tag VT_NON"); 35240292Smckusick fifo_printinfo(vp); 35340292Smckusick printf("\n"); 35440292Smckusick } 35540292Smckusick 35640292Smckusick /* 35740292Smckusick * Print out internal contents of a fifo vnode. 35840292Smckusick */ 35940292Smckusick fifo_printinfo(vp) 36040292Smckusick struct vnode *vp; 36140292Smckusick { 36240292Smckusick register struct fifoinfo *fip = vp->v_fifoinfo; 36340292Smckusick 36440292Smckusick printf(", fifo with %d readers and %d writers", 36540292Smckusick fip->fi_readers, fip->fi_writers); 36640292Smckusick } 36740292Smckusick 36840292Smckusick /* 36940292Smckusick * Fifo failed operation 37040292Smckusick */ 37140292Smckusick fifo_ebadf() 37240292Smckusick { 37340292Smckusick 37440292Smckusick return (EBADF); 37540292Smckusick } 37640292Smckusick 37740292Smckusick /* 37840292Smckusick * Fifo bad operation 37940292Smckusick */ 38040292Smckusick fifo_badop() 38140292Smckusick { 38240292Smckusick 38340292Smckusick panic("fifo_badop called"); 38440292Smckusick /* NOTREACHED */ 38540292Smckusick } 38640292Smckusick 38740292Smckusick /* 38840292Smckusick * Fifo null operation 38940292Smckusick */ 39040292Smckusick fifo_nullop() 39140292Smckusick { 39240292Smckusick 39340292Smckusick return (0); 39440292Smckusick } 395