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*39446Smckusick * @(#)spec_vnops.c 7.11 (Berkeley) 10/29/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" 2839432Smckusick #include "stat.h" 2937486Smckusick #include "errno.h" 3037486Smckusick 31*39446Smckusick int spec_lookup(), 32*39446Smckusick spec_open(), 33*39446Smckusick spec_read(), 34*39446Smckusick spec_write(), 35*39446Smckusick spec_strategy(), 36*39446Smckusick spec_ioctl(), 37*39446Smckusick spec_select(), 38*39446Smckusick spec_lock(), 39*39446Smckusick spec_unlock(), 40*39446Smckusick spec_close(), 41*39446Smckusick spec_badop(), 42*39446Smckusick spec_nullop(); 4337486Smckusick 44*39446Smckusick struct vnodeops spec_vnodeops = { 45*39446Smckusick spec_lookup, 46*39446Smckusick spec_badop, 47*39446Smckusick spec_badop, 48*39446Smckusick spec_open, 49*39446Smckusick spec_close, 50*39446Smckusick spec_badop, 51*39446Smckusick spec_badop, 52*39446Smckusick spec_badop, 53*39446Smckusick spec_read, 54*39446Smckusick spec_write, 55*39446Smckusick spec_ioctl, 56*39446Smckusick spec_select, 57*39446Smckusick spec_badop, 58*39446Smckusick spec_nullop, 59*39446Smckusick spec_badop, 60*39446Smckusick spec_badop, 61*39446Smckusick spec_badop, 62*39446Smckusick spec_badop, 63*39446Smckusick spec_badop, 64*39446Smckusick spec_badop, 65*39446Smckusick spec_badop, 66*39446Smckusick spec_badop, 67*39446Smckusick spec_badop, 68*39446Smckusick spec_badop, 69*39446Smckusick spec_nullop, 70*39446Smckusick spec_nullop, 71*39446Smckusick spec_lock, 72*39446Smckusick spec_unlock, 73*39446Smckusick spec_badop, 74*39446Smckusick spec_strategy, 7537486Smckusick }; 7637486Smckusick 7737486Smckusick /* 7839292Smckusick * Trivial lookup routine that always fails. 7939292Smckusick */ 80*39446Smckusick spec_lookup(vp, ndp) 8139292Smckusick struct vnode *vp; 8239292Smckusick struct nameidata *ndp; 8339292Smckusick { 8439292Smckusick 8539292Smckusick ndp->ni_dvp = vp; 8639292Smckusick ndp->ni_vp = NULL; 8739292Smckusick return (ENOTDIR); 8839292Smckusick } 8939292Smckusick 9039292Smckusick /* 9137486Smckusick * Open called to allow handler 9237486Smckusick * of special files to initialize and 9337486Smckusick * validate before actual IO. 9437486Smckusick */ 9537725Smckusick /* ARGSUSED */ 96*39446Smckusick spec_open(vp, mode, cred) 9737486Smckusick register struct vnode *vp; 9837486Smckusick int mode; 9937486Smckusick struct ucred *cred; 10037486Smckusick { 10137486Smckusick dev_t dev = (dev_t)vp->v_rdev; 10237486Smckusick register int maj = major(dev); 10337486Smckusick 10439365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 10539365Smckusick return (ENXIO); 10639365Smckusick 10737486Smckusick switch (vp->v_type) { 10837486Smckusick 10937486Smckusick case VCHR: 11037486Smckusick if ((u_int)maj >= nchrdev) 11137486Smckusick return (ENXIO); 11239432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 11337486Smckusick 11437486Smckusick case VBLK: 11537486Smckusick if ((u_int)maj >= nblkdev) 11637486Smckusick return (ENXIO); 11739432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 11837486Smckusick } 11937486Smckusick return (0); 12037486Smckusick } 12137486Smckusick 12237486Smckusick /* 12337486Smckusick * Vnode op for read 12437486Smckusick */ 125*39446Smckusick spec_read(vp, uio, offp, ioflag, cred) 12637486Smckusick register struct vnode *vp; 12737486Smckusick struct uio *uio; 12837486Smckusick off_t *offp; 12937486Smckusick int ioflag; 13037486Smckusick struct ucred *cred; 13137486Smckusick { 13237486Smckusick int count, error; 13337486Smckusick 13437725Smckusick if (vp->v_type == VBLK && vp->v_data) 13537725Smckusick VOP_LOCK(vp); 13637486Smckusick uio->uio_offset = *offp; 13737486Smckusick count = uio->uio_resid; 13837725Smckusick error = readblkvp(vp, uio, cred, ioflag); 13937486Smckusick *offp += count - uio->uio_resid; 14037725Smckusick if (vp->v_type == VBLK && vp->v_data) 14137725Smckusick VOP_UNLOCK(vp); 14237486Smckusick return (error); 14337486Smckusick } 14437486Smckusick 14537486Smckusick /* 14637486Smckusick * Vnode op for write 14737486Smckusick */ 148*39446Smckusick spec_write(vp, uio, offp, ioflag, cred) 14937486Smckusick register struct vnode *vp; 15037486Smckusick struct uio *uio; 15137486Smckusick off_t *offp; 15237486Smckusick int ioflag; 15337486Smckusick struct ucred *cred; 15437486Smckusick { 15537486Smckusick int count, error; 15637486Smckusick 15737725Smckusick if (vp->v_type == VBLK && vp->v_data) 15837725Smckusick VOP_LOCK(vp); 15937486Smckusick uio->uio_offset = *offp; 16037486Smckusick count = uio->uio_resid; 16137725Smckusick error = writeblkvp(vp, uio, cred, ioflag); 16237486Smckusick *offp += count - uio->uio_resid; 16337725Smckusick if (vp->v_type == VBLK && vp->v_data) 16437725Smckusick VOP_UNLOCK(vp); 16537486Smckusick return (error); 16637486Smckusick } 16737486Smckusick 16837486Smckusick /* 16937486Smckusick * Device ioctl operation. 17037486Smckusick */ 17137725Smckusick /* ARGSUSED */ 172*39446Smckusick spec_ioctl(vp, com, data, fflag, cred) 17337486Smckusick struct vnode *vp; 17437486Smckusick register int com; 17537486Smckusick caddr_t data; 17637486Smckusick int fflag; 17737486Smckusick struct ucred *cred; 17837486Smckusick { 17937725Smckusick dev_t dev = vp->v_rdev; 18037486Smckusick 18137486Smckusick switch (vp->v_type) { 18237486Smckusick 18337486Smckusick case VCHR: 18437486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 18537486Smckusick 18637486Smckusick case VBLK: 18737486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 18837486Smckusick 18937486Smckusick default: 190*39446Smckusick panic("spec_ioctl"); 19137486Smckusick /* NOTREACHED */ 19237486Smckusick } 19337486Smckusick } 19437486Smckusick 19537725Smckusick /* ARGSUSED */ 196*39446Smckusick spec_select(vp, which, cred) 19737486Smckusick struct vnode *vp; 19837486Smckusick int which; 19937486Smckusick struct ucred *cred; 20037486Smckusick { 20137486Smckusick register dev_t dev; 20237486Smckusick 20337486Smckusick switch (vp->v_type) { 20437486Smckusick 20537486Smckusick default: 20637486Smckusick return (1); /* XXX */ 20737486Smckusick 20837486Smckusick case VCHR: 20937725Smckusick dev = vp->v_rdev; 21037486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 21137486Smckusick } 21237486Smckusick } 21337486Smckusick 21437486Smckusick /* 21537486Smckusick * Just call the device strategy routine 21637486Smckusick */ 217*39446Smckusick spec_strategy(bp) 21837486Smckusick register struct buf *bp; 21937486Smckusick { 22037486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 22137486Smckusick return (0); 22237486Smckusick } 22337486Smckusick 22439432Smckusick /* 22539432Smckusick * At the moment we do not do any locking. 22639432Smckusick */ 227*39446Smckusick spec_lock(vp) 22837486Smckusick struct vnode *vp; 22937486Smckusick { 23037486Smckusick 23137486Smckusick return (0); 23237486Smckusick } 23337486Smckusick 234*39446Smckusick spec_unlock(vp) 23537486Smckusick struct vnode *vp; 23637486Smckusick { 23737486Smckusick 23837486Smckusick return (0); 23937486Smckusick } 24037486Smckusick 24137486Smckusick /* 24237486Smckusick * Device close routine 24337486Smckusick */ 24437725Smckusick /* ARGSUSED */ 245*39446Smckusick spec_close(vp, flag, cred) 24637725Smckusick register struct vnode *vp; 24737486Smckusick int flag; 24837486Smckusick struct ucred *cred; 24937486Smckusick { 25037486Smckusick dev_t dev = vp->v_rdev; 25137725Smckusick int (*cfunc)(); 25237725Smckusick int error, mode; 25337486Smckusick 25437725Smckusick switch (vp->v_type) { 25537725Smckusick 25637725Smckusick case VCHR: 25737725Smckusick if (vp->v_count > 1) 25837725Smckusick return (0); 25937725Smckusick cfunc = cdevsw[major(dev)].d_close; 26039432Smckusick mode = S_IFCHR; 26137725Smckusick break; 26237725Smckusick 26337725Smckusick case VBLK: 26437725Smckusick /* 26537725Smckusick * On last close of a block device (that isn't mounted) 26637725Smckusick * we must invalidate any in core blocks, so that 26737725Smckusick * we can, for instance, change floppy disks. 26837725Smckusick */ 26938777Smckusick bflush(vp->v_mount); 27038777Smckusick if (binval(vp->v_mount)) 27138613Smckusick return (0); 27237725Smckusick /* 27337725Smckusick * We don't want to really close the device if it is still 27439432Smckusick * in use. Since every use (buffer, vnode, swap, cmap) 27537725Smckusick * holds a reference to the vnode, and because we ensure 27637725Smckusick * that there cannot be more than one vnode per device, 27737725Smckusick * we need only check that we are down to the last 27837725Smckusick * reference before closing. 27937725Smckusick */ 28037725Smckusick if (vp->v_count > 1) 28137725Smckusick return (0); 28237725Smckusick cfunc = bdevsw[major(dev)].d_close; 28339432Smckusick mode = S_IFBLK; 28437725Smckusick break; 28537725Smckusick 28637725Smckusick default: 287*39446Smckusick panic("spec_close: not special"); 28837725Smckusick } 28937725Smckusick 29037725Smckusick if (setjmp(&u.u_qsave)) { 29137725Smckusick /* 29237725Smckusick * If device close routine is interrupted, 29337725Smckusick * must return so closef can clean up. 29437725Smckusick */ 29537725Smckusick error = EINTR; 29637725Smckusick } else 29737725Smckusick error = (*cfunc)(dev, flag, mode); 29837725Smckusick return (error); 29937486Smckusick } 30037486Smckusick 30137486Smckusick /* 30237486Smckusick * Block device bad operation 30337486Smckusick */ 304*39446Smckusick spec_badop() 30537486Smckusick { 30637486Smckusick 307*39446Smckusick panic("spec_badop called"); 30839292Smckusick /* NOTREACHED */ 30937486Smckusick } 31037486Smckusick 31137486Smckusick /* 31237486Smckusick * Block device null operation 31337486Smckusick */ 314*39446Smckusick spec_nullop() 31537486Smckusick { 31637486Smckusick 31737486Smckusick return (0); 31837486Smckusick } 319