137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 537486Smckusick * Redistribution and use in source and binary forms are permitted 637486Smckusick * provided that the above copyright notice and this paragraph are 737486Smckusick * duplicated in all such forms and that any documentation, 837486Smckusick * advertising materials, and other materials related to such 937486Smckusick * distribution and use acknowledge that the software was developed 1037486Smckusick * by the University of California, Berkeley. The name of the 1137486Smckusick * University may not be used to endorse or promote products derived 1237486Smckusick * from this software without specific prior written permission. 1337486Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437486Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537486Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637486Smckusick * 17*39588Smckusick * @(#)spec_vnops.c 7.15 (Berkeley) 11/22/89 1837486Smckusick */ 1937486Smckusick 2037486Smckusick #include "param.h" 2137486Smckusick #include "systm.h" 2237725Smckusick #include "user.h" 2337725Smckusick #include "kernel.h" 2437486Smckusick #include "conf.h" 2537486Smckusick #include "buf.h" 2639365Smckusick #include "mount.h" 2737486Smckusick #include "vnode.h" 28*39588Smckusick #include "../ufs/inode.h" 2939432Smckusick #include "stat.h" 3037486Smckusick #include "errno.h" 3137486Smckusick 3239446Smckusick int spec_lookup(), 3339446Smckusick spec_open(), 3439446Smckusick spec_read(), 3539446Smckusick spec_write(), 3639446Smckusick spec_strategy(), 3739446Smckusick spec_ioctl(), 3839446Smckusick spec_select(), 3939446Smckusick spec_lock(), 4039446Smckusick spec_unlock(), 4139446Smckusick spec_close(), 4239507Smckusick spec_ebadf(), 4339446Smckusick spec_badop(), 4439446Smckusick spec_nullop(); 4537486Smckusick 4639446Smckusick struct vnodeops spec_vnodeops = { 4739507Smckusick spec_lookup, /* lookup */ 4839507Smckusick spec_badop, /* create */ 4939507Smckusick spec_badop, /* mknod */ 5039507Smckusick spec_open, /* open */ 5139507Smckusick spec_close, /* close */ 5239507Smckusick spec_ebadf, /* access */ 5339507Smckusick spec_ebadf, /* getattr */ 5439507Smckusick spec_ebadf, /* setattr */ 5539507Smckusick spec_read, /* read */ 5639507Smckusick spec_write, /* write */ 5739507Smckusick spec_ioctl, /* ioctl */ 5839507Smckusick spec_select, /* select */ 5939507Smckusick spec_badop, /* mmap */ 6039507Smckusick spec_nullop, /* fsync */ 6139507Smckusick spec_badop, /* seek */ 6239507Smckusick spec_badop, /* remove */ 6339507Smckusick spec_badop, /* link */ 6439507Smckusick spec_badop, /* rename */ 6539507Smckusick spec_badop, /* mkdir */ 6639507Smckusick spec_badop, /* rmdir */ 6739507Smckusick spec_badop, /* symlink */ 6839507Smckusick spec_badop, /* readdir */ 6939507Smckusick spec_badop, /* readlink */ 7039507Smckusick spec_badop, /* abortop */ 7139507Smckusick spec_nullop, /* inactive */ 7239507Smckusick spec_nullop, /* reclaim */ 7339507Smckusick spec_lock, /* lock */ 7439507Smckusick spec_unlock, /* unlock */ 7539507Smckusick spec_badop, /* bmap */ 7639507Smckusick spec_strategy, /* strategy */ 7737486Smckusick }; 7837486Smckusick 7937486Smckusick /* 8039292Smckusick * Trivial lookup routine that always fails. 8139292Smckusick */ 8239446Smckusick spec_lookup(vp, ndp) 8339292Smckusick struct vnode *vp; 8439292Smckusick struct nameidata *ndp; 8539292Smckusick { 8639292Smckusick 8739292Smckusick ndp->ni_dvp = vp; 8839292Smckusick ndp->ni_vp = NULL; 8939292Smckusick return (ENOTDIR); 9039292Smckusick } 9139292Smckusick 9239292Smckusick /* 9337486Smckusick * Open called to allow handler 9437486Smckusick * of special files to initialize and 9537486Smckusick * validate before actual IO. 9637486Smckusick */ 9737725Smckusick /* ARGSUSED */ 9839446Smckusick spec_open(vp, mode, cred) 9937486Smckusick register struct vnode *vp; 10037486Smckusick int mode; 10137486Smckusick struct ucred *cred; 10237486Smckusick { 10337486Smckusick dev_t dev = (dev_t)vp->v_rdev; 10437486Smckusick register int maj = major(dev); 10537486Smckusick 10639365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 10739365Smckusick return (ENXIO); 10839365Smckusick 10937486Smckusick switch (vp->v_type) { 11037486Smckusick 11137486Smckusick case VCHR: 11237486Smckusick if ((u_int)maj >= nchrdev) 11337486Smckusick return (ENXIO); 11439432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 11537486Smckusick 11637486Smckusick case VBLK: 11737486Smckusick if ((u_int)maj >= nblkdev) 11837486Smckusick return (ENXIO); 11939432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 12037486Smckusick } 12137486Smckusick return (0); 12237486Smckusick } 12337486Smckusick 12437486Smckusick /* 12537486Smckusick * Vnode op for read 12637486Smckusick */ 127*39588Smckusick spec_read(vp, uio, ioflag, cred) 12837486Smckusick register struct vnode *vp; 12937486Smckusick struct uio *uio; 13037486Smckusick int ioflag; 13137486Smckusick struct ucred *cred; 13237486Smckusick { 133*39588Smckusick int error; 134*39588Smckusick extern int mem_no; 13537486Smckusick 136*39588Smckusick if (uio->uio_rw != UIO_READ) 137*39588Smckusick panic("spec_read mode"); 138*39588Smckusick if (uio->uio_resid == 0) 139*39588Smckusick return (0); 140*39588Smckusick /* 141*39588Smckusick * XXX Set access flag for the ufs filesystem. 142*39588Smckusick */ 143*39588Smckusick if (vp->v_tag == VT_UFS) 144*39588Smckusick VTOI(vp)->i_flag |= IACC; 145*39588Smckusick 146*39588Smckusick switch (vp->v_type) { 147*39588Smckusick 148*39588Smckusick case VCHR: 149*39588Smckusick /* 150*39588Smckusick * Negative offsets allowed only for /dev/kmem 151*39588Smckusick */ 152*39588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 153*39588Smckusick return (EINVAL); 154*39588Smckusick VOP_UNLOCK(vp); 155*39588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 156*39588Smckusick (vp->v_rdev, uio, ioflag); 15737725Smckusick VOP_LOCK(vp); 158*39588Smckusick return (error); 159*39588Smckusick 160*39588Smckusick case VBLK: 161*39588Smckusick if (uio->uio_offset < 0) 162*39588Smckusick return (EINVAL); 163*39588Smckusick return (readblkvp(vp, uio, cred, ioflag)); 164*39588Smckusick 165*39588Smckusick default: 166*39588Smckusick panic("spec_read type"); 167*39588Smckusick } 168*39588Smckusick /* NOTREACHED */ 16937486Smckusick } 17037486Smckusick 17137486Smckusick /* 17237486Smckusick * Vnode op for write 17337486Smckusick */ 174*39588Smckusick spec_write(vp, uio, ioflag, cred) 17537486Smckusick register struct vnode *vp; 17637486Smckusick struct uio *uio; 17737486Smckusick int ioflag; 17837486Smckusick struct ucred *cred; 17937486Smckusick { 180*39588Smckusick int error; 181*39588Smckusick extern int mem_no; 18237486Smckusick 183*39588Smckusick if (uio->uio_rw != UIO_WRITE) 184*39588Smckusick panic("spec_write mode"); 185*39588Smckusick /* 186*39588Smckusick * XXX Set update and change flags for the ufs filesystem. 187*39588Smckusick */ 188*39588Smckusick if (vp->v_tag == VT_UFS) 189*39588Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 190*39588Smckusick 191*39588Smckusick switch (vp->v_type) { 192*39588Smckusick 193*39588Smckusick case VCHR: 194*39588Smckusick /* 195*39588Smckusick * Negative offsets allowed only for /dev/kmem 196*39588Smckusick */ 197*39588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 198*39588Smckusick return (EINVAL); 199*39588Smckusick VOP_UNLOCK(vp); 200*39588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 201*39588Smckusick (vp->v_rdev, uio, ioflag); 20237725Smckusick VOP_LOCK(vp); 203*39588Smckusick return (error); 204*39588Smckusick 205*39588Smckusick case VBLK: 206*39588Smckusick if (uio->uio_resid == 0) 207*39588Smckusick return (0); 208*39588Smckusick if (uio->uio_offset < 0) 209*39588Smckusick return (EINVAL); 210*39588Smckusick return (writeblkvp(vp, uio, cred, ioflag)); 211*39588Smckusick 212*39588Smckusick default: 213*39588Smckusick panic("spec_write type"); 214*39588Smckusick } 215*39588Smckusick /* NOTREACHED */ 21637486Smckusick } 21737486Smckusick 21837486Smckusick /* 21937486Smckusick * Device ioctl operation. 22037486Smckusick */ 22137725Smckusick /* ARGSUSED */ 22239446Smckusick spec_ioctl(vp, com, data, fflag, cred) 22337486Smckusick struct vnode *vp; 22437486Smckusick register int com; 22537486Smckusick caddr_t data; 22637486Smckusick int fflag; 22737486Smckusick struct ucred *cred; 22837486Smckusick { 22937725Smckusick dev_t dev = vp->v_rdev; 23037486Smckusick 23137486Smckusick switch (vp->v_type) { 23237486Smckusick 23337486Smckusick case VCHR: 23437486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 23537486Smckusick 23637486Smckusick case VBLK: 23737486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 23837486Smckusick 23937486Smckusick default: 24039446Smckusick panic("spec_ioctl"); 24137486Smckusick /* NOTREACHED */ 24237486Smckusick } 24337486Smckusick } 24437486Smckusick 24537725Smckusick /* ARGSUSED */ 24639446Smckusick spec_select(vp, which, cred) 24737486Smckusick struct vnode *vp; 24837486Smckusick int which; 24937486Smckusick struct ucred *cred; 25037486Smckusick { 25137486Smckusick register dev_t dev; 25237486Smckusick 25337486Smckusick switch (vp->v_type) { 25437486Smckusick 25537486Smckusick default: 25637486Smckusick return (1); /* XXX */ 25737486Smckusick 25837486Smckusick case VCHR: 25937725Smckusick dev = vp->v_rdev; 26037486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 26137486Smckusick } 26237486Smckusick } 26337486Smckusick 26437486Smckusick /* 26537486Smckusick * Just call the device strategy routine 26637486Smckusick */ 26739446Smckusick spec_strategy(bp) 26837486Smckusick register struct buf *bp; 26937486Smckusick { 27037486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 27137486Smckusick return (0); 27237486Smckusick } 27337486Smckusick 27439432Smckusick /* 27539432Smckusick * At the moment we do not do any locking. 27639432Smckusick */ 27739489Smckusick /* ARGSUSED */ 27839446Smckusick spec_lock(vp) 27937486Smckusick struct vnode *vp; 28037486Smckusick { 28137486Smckusick 28237486Smckusick return (0); 28337486Smckusick } 28437486Smckusick 28539489Smckusick /* ARGSUSED */ 28639446Smckusick spec_unlock(vp) 28737486Smckusick struct vnode *vp; 28837486Smckusick { 28937486Smckusick 29037486Smckusick return (0); 29137486Smckusick } 29237486Smckusick 29337486Smckusick /* 29437486Smckusick * Device close routine 29537486Smckusick */ 29637725Smckusick /* ARGSUSED */ 29739446Smckusick spec_close(vp, flag, cred) 29837725Smckusick register struct vnode *vp; 29937486Smckusick int flag; 30037486Smckusick struct ucred *cred; 30137486Smckusick { 30237486Smckusick dev_t dev = vp->v_rdev; 30337725Smckusick int (*cfunc)(); 30437725Smckusick int error, mode; 30537486Smckusick 30637725Smckusick switch (vp->v_type) { 30737725Smckusick 30837725Smckusick case VCHR: 30939485Smckusick /* 31039485Smckusick * If the vnode is locked, then we are in the midst 31139485Smckusick * of forcably closing the device, otherwise we only 31239485Smckusick * close on last reference. 31339485Smckusick */ 31439485Smckusick if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0) 31537725Smckusick return (0); 31637725Smckusick cfunc = cdevsw[major(dev)].d_close; 31739432Smckusick mode = S_IFCHR; 31837725Smckusick break; 31937725Smckusick 32037725Smckusick case VBLK: 32137725Smckusick /* 32237725Smckusick * On last close of a block device (that isn't mounted) 32337725Smckusick * we must invalidate any in core blocks, so that 32437725Smckusick * we can, for instance, change floppy disks. 32537725Smckusick */ 32638777Smckusick bflush(vp->v_mount); 32738777Smckusick if (binval(vp->v_mount)) 32838613Smckusick return (0); 32937725Smckusick /* 33039485Smckusick * We do not want to really close the device if it 33139485Smckusick * is still in use unless we are trying to close it 33239485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 33337725Smckusick * holds a reference to the vnode, and because we ensure 33437725Smckusick * that there cannot be more than one vnode per device, 33537725Smckusick * we need only check that we are down to the last 33639485Smckusick * reference to detect last close. 33737725Smckusick */ 33839485Smckusick if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0) 33937725Smckusick return (0); 34037725Smckusick cfunc = bdevsw[major(dev)].d_close; 34139432Smckusick mode = S_IFBLK; 34237725Smckusick break; 34337725Smckusick 34437725Smckusick default: 34539446Smckusick panic("spec_close: not special"); 34637725Smckusick } 34737725Smckusick 34837725Smckusick if (setjmp(&u.u_qsave)) { 34937725Smckusick /* 35037725Smckusick * If device close routine is interrupted, 35137725Smckusick * must return so closef can clean up. 35237725Smckusick */ 35337725Smckusick error = EINTR; 35437725Smckusick } else 35537725Smckusick error = (*cfunc)(dev, flag, mode); 35637725Smckusick return (error); 35737486Smckusick } 35837486Smckusick 35937486Smckusick /* 36039507Smckusick * Special device failed operation 36137486Smckusick */ 36239507Smckusick spec_ebadf() 36339507Smckusick { 36439507Smckusick 36539507Smckusick return (EBADF); 36639507Smckusick } 36739507Smckusick 36839507Smckusick /* 36939507Smckusick * Special device bad operation 37039507Smckusick */ 37139446Smckusick spec_badop() 37237486Smckusick { 37337486Smckusick 37439446Smckusick panic("spec_badop called"); 37539292Smckusick /* NOTREACHED */ 37637486Smckusick } 37737486Smckusick 37837486Smckusick /* 37939507Smckusick * Special device null operation 38037486Smckusick */ 38139446Smckusick spec_nullop() 38237486Smckusick { 38337486Smckusick 38437486Smckusick return (0); 38537486Smckusick } 386