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*39630Smckusick * @(#)spec_vnops.c 7.19 (Berkeley) 11/25/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" 3039614Smckusick #include "ioctl.h" 3139614Smckusick #include "file.h" 3239614Smckusick #include "disklabel.h" 3337486Smckusick 3439446Smckusick int spec_lookup(), 3539446Smckusick spec_open(), 3639446Smckusick spec_read(), 3739446Smckusick spec_write(), 3839446Smckusick spec_strategy(), 3939446Smckusick spec_ioctl(), 4039446Smckusick spec_select(), 4139446Smckusick spec_lock(), 4239446Smckusick spec_unlock(), 4339446Smckusick spec_close(), 4439507Smckusick spec_ebadf(), 4539446Smckusick spec_badop(), 4639446Smckusick spec_nullop(); 4737486Smckusick 4839446Smckusick struct vnodeops spec_vnodeops = { 4939507Smckusick spec_lookup, /* lookup */ 5039507Smckusick spec_badop, /* create */ 5139507Smckusick spec_badop, /* mknod */ 5239507Smckusick spec_open, /* open */ 5339507Smckusick spec_close, /* close */ 5439507Smckusick spec_ebadf, /* access */ 5539507Smckusick spec_ebadf, /* getattr */ 5639507Smckusick spec_ebadf, /* setattr */ 5739507Smckusick spec_read, /* read */ 5839507Smckusick spec_write, /* write */ 5939507Smckusick spec_ioctl, /* ioctl */ 6039507Smckusick spec_select, /* select */ 6139507Smckusick spec_badop, /* mmap */ 6239507Smckusick spec_nullop, /* fsync */ 6339507Smckusick spec_badop, /* seek */ 6439507Smckusick spec_badop, /* remove */ 6539507Smckusick spec_badop, /* link */ 6639507Smckusick spec_badop, /* rename */ 6739507Smckusick spec_badop, /* mkdir */ 6839507Smckusick spec_badop, /* rmdir */ 6939507Smckusick spec_badop, /* symlink */ 7039507Smckusick spec_badop, /* readdir */ 7139507Smckusick spec_badop, /* readlink */ 7239507Smckusick spec_badop, /* abortop */ 7339507Smckusick spec_nullop, /* inactive */ 7439507Smckusick spec_nullop, /* reclaim */ 7539507Smckusick spec_lock, /* lock */ 7639507Smckusick spec_unlock, /* unlock */ 7739507Smckusick spec_badop, /* bmap */ 7839507Smckusick spec_strategy, /* strategy */ 7937486Smckusick }; 8037486Smckusick 8137486Smckusick /* 8239292Smckusick * Trivial lookup routine that always fails. 8339292Smckusick */ 8439446Smckusick spec_lookup(vp, ndp) 8539292Smckusick struct vnode *vp; 8639292Smckusick struct nameidata *ndp; 8739292Smckusick { 8839292Smckusick 8939292Smckusick ndp->ni_dvp = vp; 9039292Smckusick ndp->ni_vp = NULL; 9139292Smckusick return (ENOTDIR); 9239292Smckusick } 9339292Smckusick 9439292Smckusick /* 9537486Smckusick * Open called to allow handler 9637486Smckusick * of special files to initialize and 9737486Smckusick * validate before actual IO. 9837486Smckusick */ 9937725Smckusick /* ARGSUSED */ 10039446Smckusick spec_open(vp, mode, cred) 10137486Smckusick register struct vnode *vp; 10237486Smckusick int mode; 10337486Smckusick struct ucred *cred; 10437486Smckusick { 10537486Smckusick dev_t dev = (dev_t)vp->v_rdev; 10637486Smckusick register int maj = major(dev); 10737486Smckusick 10839365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 10939365Smckusick return (ENXIO); 11039365Smckusick 11137486Smckusick switch (vp->v_type) { 11237486Smckusick 11337486Smckusick case VCHR: 11437486Smckusick if ((u_int)maj >= nchrdev) 11537486Smckusick return (ENXIO); 11639432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 11737486Smckusick 11837486Smckusick case VBLK: 11937486Smckusick if ((u_int)maj >= nblkdev) 12037486Smckusick return (ENXIO); 12139432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 12237486Smckusick } 12337486Smckusick return (0); 12437486Smckusick } 12537486Smckusick 12637486Smckusick /* 12737486Smckusick * Vnode op for read 12837486Smckusick */ 12939588Smckusick spec_read(vp, uio, ioflag, cred) 13037486Smckusick register struct vnode *vp; 13139614Smckusick register struct uio *uio; 13237486Smckusick int ioflag; 13337486Smckusick struct ucred *cred; 13437486Smckusick { 13539614Smckusick struct buf *bp; 13639614Smckusick daddr_t bn; 13739614Smckusick long bsize, bscale; 13839614Smckusick struct partinfo dpart; 13939614Smckusick register int n, on; 14039614Smckusick int error = 0; 14139588Smckusick extern int mem_no; 14237486Smckusick 14339588Smckusick if (uio->uio_rw != UIO_READ) 14439588Smckusick panic("spec_read mode"); 14539588Smckusick if (uio->uio_resid == 0) 14639588Smckusick return (0); 14739588Smckusick 14839588Smckusick switch (vp->v_type) { 14939588Smckusick 15039588Smckusick case VCHR: 15139588Smckusick /* 15239588Smckusick * Negative offsets allowed only for /dev/kmem 15339588Smckusick */ 15439588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 15539588Smckusick return (EINVAL); 15639588Smckusick VOP_UNLOCK(vp); 15739588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 15839588Smckusick (vp->v_rdev, uio, ioflag); 15937725Smckusick VOP_LOCK(vp); 16039588Smckusick return (error); 16139588Smckusick 16239588Smckusick case VBLK: 16339588Smckusick if (uio->uio_offset < 0) 16439588Smckusick return (EINVAL); 16539614Smckusick bsize = BLKDEV_IOSIZE; 16639614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 16739614Smckusick (caddr_t)&dpart, FREAD) == 0) { 16839614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 16939614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17039614Smckusick bsize = dpart.part->p_frag * 17139614Smckusick dpart.part->p_fsize; 17239614Smckusick } 17339614Smckusick bscale = bsize / DEV_BSIZE; 17439614Smckusick do { 17539614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 17639614Smckusick on = uio->uio_offset % bsize; 17739614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 17839614Smckusick if (vp->v_lastr + bscale == bn) 17939614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 18039614Smckusick (int)bsize, NOCRED, &bp); 18139614Smckusick else 18239614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 18339614Smckusick vp->v_lastr = bn; 18439614Smckusick n = MIN(n, bsize - bp->b_resid); 18539614Smckusick if (error) { 18639614Smckusick brelse(bp); 18739614Smckusick return (error); 18839614Smckusick } 18939614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 19039614Smckusick if (n + on == bsize) 19139614Smckusick bp->b_flags |= B_AGE; 19239614Smckusick brelse(bp); 19339614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 19439614Smckusick return (error); 19539588Smckusick 19639588Smckusick default: 19739588Smckusick panic("spec_read type"); 19839588Smckusick } 19939588Smckusick /* NOTREACHED */ 20037486Smckusick } 20137486Smckusick 20237486Smckusick /* 20337486Smckusick * Vnode op for write 20437486Smckusick */ 20539588Smckusick spec_write(vp, uio, ioflag, cred) 20637486Smckusick register struct vnode *vp; 20739614Smckusick register struct uio *uio; 20837486Smckusick int ioflag; 20937486Smckusick struct ucred *cred; 21037486Smckusick { 21139614Smckusick struct buf *bp; 21239614Smckusick daddr_t bn; 21339614Smckusick int bsize, blkmask; 21439614Smckusick struct partinfo dpart; 21539614Smckusick register int n, on, i; 21639614Smckusick int count, error = 0; 21739588Smckusick extern int mem_no; 21837486Smckusick 21939588Smckusick if (uio->uio_rw != UIO_WRITE) 22039588Smckusick panic("spec_write mode"); 22139588Smckusick 22239588Smckusick switch (vp->v_type) { 22339588Smckusick 22439588Smckusick case VCHR: 22539588Smckusick /* 22639588Smckusick * Negative offsets allowed only for /dev/kmem 22739588Smckusick */ 22839588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 22939588Smckusick return (EINVAL); 23039588Smckusick VOP_UNLOCK(vp); 23139588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 23239588Smckusick (vp->v_rdev, uio, ioflag); 23337725Smckusick VOP_LOCK(vp); 23439588Smckusick return (error); 23539588Smckusick 23639588Smckusick case VBLK: 23739588Smckusick if (uio->uio_resid == 0) 23839588Smckusick return (0); 23939588Smckusick if (uio->uio_offset < 0) 24039588Smckusick return (EINVAL); 24139614Smckusick bsize = BLKDEV_IOSIZE; 24239614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 24339614Smckusick (caddr_t)&dpart, FREAD) == 0) { 24439614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 24539614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 24639614Smckusick bsize = dpart.part->p_frag * 24739614Smckusick dpart.part->p_fsize; 24839614Smckusick } 24939614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 25039614Smckusick do { 25139614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 25239614Smckusick on = uio->uio_offset % bsize; 25339614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 25439614Smckusick count = howmany(bsize, CLBYTES); 25539614Smckusick for (i = 0; i < count; i++) 25639614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 25739614Smckusick if (n == bsize) 25839614Smckusick bp = getblk(vp, bn, bsize); 25939614Smckusick else 26039614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 26139614Smckusick n = MIN(n, bsize - bp->b_resid); 26239614Smckusick if (error) { 26339614Smckusick brelse(bp); 26439614Smckusick return (error); 26539614Smckusick } 26639614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 26739614Smckusick if (n + on == bsize) { 26839614Smckusick bp->b_flags |= B_AGE; 26939614Smckusick bawrite(bp); 27039614Smckusick } else 27139614Smckusick bdwrite(bp); 27239614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 27339614Smckusick return (error); 27439588Smckusick 27539588Smckusick default: 27639588Smckusick panic("spec_write type"); 27739588Smckusick } 27839588Smckusick /* NOTREACHED */ 27937486Smckusick } 28037486Smckusick 28137486Smckusick /* 28237486Smckusick * Device ioctl operation. 28337486Smckusick */ 28437725Smckusick /* ARGSUSED */ 28539446Smckusick spec_ioctl(vp, com, data, fflag, cred) 28637486Smckusick struct vnode *vp; 28737486Smckusick register int com; 28837486Smckusick caddr_t data; 28937486Smckusick int fflag; 29037486Smckusick struct ucred *cred; 29137486Smckusick { 29237725Smckusick dev_t dev = vp->v_rdev; 29337486Smckusick 29437486Smckusick switch (vp->v_type) { 29537486Smckusick 29637486Smckusick case VCHR: 29737486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 29837486Smckusick 29937486Smckusick case VBLK: 30037486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 30137486Smckusick 30237486Smckusick default: 30339446Smckusick panic("spec_ioctl"); 30437486Smckusick /* NOTREACHED */ 30537486Smckusick } 30637486Smckusick } 30737486Smckusick 30837725Smckusick /* ARGSUSED */ 30939446Smckusick spec_select(vp, which, cred) 31037486Smckusick struct vnode *vp; 31137486Smckusick int which; 31237486Smckusick struct ucred *cred; 31337486Smckusick { 31437486Smckusick register dev_t dev; 31537486Smckusick 31637486Smckusick switch (vp->v_type) { 31737486Smckusick 31837486Smckusick default: 31937486Smckusick return (1); /* XXX */ 32037486Smckusick 32137486Smckusick case VCHR: 32237725Smckusick dev = vp->v_rdev; 32337486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 32437486Smckusick } 32537486Smckusick } 32637486Smckusick 32737486Smckusick /* 32837486Smckusick * Just call the device strategy routine 32937486Smckusick */ 33039446Smckusick spec_strategy(bp) 33137486Smckusick register struct buf *bp; 33237486Smckusick { 33337486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 33437486Smckusick return (0); 33537486Smckusick } 33637486Smckusick 33739432Smckusick /* 33839432Smckusick * At the moment we do not do any locking. 33939432Smckusick */ 34039489Smckusick /* ARGSUSED */ 34139446Smckusick spec_lock(vp) 34237486Smckusick struct vnode *vp; 34337486Smckusick { 34437486Smckusick 34537486Smckusick return (0); 34637486Smckusick } 34737486Smckusick 34839489Smckusick /* ARGSUSED */ 34939446Smckusick spec_unlock(vp) 35037486Smckusick struct vnode *vp; 35137486Smckusick { 35237486Smckusick 35337486Smckusick return (0); 35437486Smckusick } 35537486Smckusick 35637486Smckusick /* 35737486Smckusick * Device close routine 35837486Smckusick */ 35937725Smckusick /* ARGSUSED */ 36039446Smckusick spec_close(vp, flag, cred) 36137725Smckusick register struct vnode *vp; 36237486Smckusick int flag; 36337486Smckusick struct ucred *cred; 36437486Smckusick { 36537486Smckusick dev_t dev = vp->v_rdev; 36637725Smckusick int (*cfunc)(); 36737725Smckusick int error, mode; 36837486Smckusick 36937725Smckusick switch (vp->v_type) { 37037725Smckusick 37137725Smckusick case VCHR: 37239485Smckusick /* 37339485Smckusick * If the vnode is locked, then we are in the midst 37439485Smckusick * of forcably closing the device, otherwise we only 37539485Smckusick * close on last reference. 37639485Smckusick */ 377*39630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 37837725Smckusick return (0); 37937725Smckusick cfunc = cdevsw[major(dev)].d_close; 38039432Smckusick mode = S_IFCHR; 38137725Smckusick break; 38237725Smckusick 38337725Smckusick case VBLK: 38437725Smckusick /* 38537725Smckusick * On last close of a block device (that isn't mounted) 38637725Smckusick * we must invalidate any in core blocks, so that 38737725Smckusick * we can, for instance, change floppy disks. 38837725Smckusick */ 38939622Smckusick bflush(vp->v_mounton); 39039622Smckusick if (binval(vp->v_mounton)) 39138613Smckusick return (0); 39237725Smckusick /* 39339485Smckusick * We do not want to really close the device if it 39439485Smckusick * is still in use unless we are trying to close it 39539485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 396*39630Smckusick * holds a reference to the vnode, and because we mark 397*39630Smckusick * any other vnodes that alias this device, when the 398*39630Smckusick * sum of the reference counts on all the aliased 399*39630Smckusick * vnodes descends to one, we are on last close. 40037725Smckusick */ 401*39630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 40237725Smckusick return (0); 40337725Smckusick cfunc = bdevsw[major(dev)].d_close; 40439432Smckusick mode = S_IFBLK; 40537725Smckusick break; 40637725Smckusick 40737725Smckusick default: 40839446Smckusick panic("spec_close: not special"); 40937725Smckusick } 41037725Smckusick 41137725Smckusick if (setjmp(&u.u_qsave)) { 41237725Smckusick /* 41337725Smckusick * If device close routine is interrupted, 41437725Smckusick * must return so closef can clean up. 41537725Smckusick */ 41637725Smckusick error = EINTR; 41737725Smckusick } else 41837725Smckusick error = (*cfunc)(dev, flag, mode); 41937725Smckusick return (error); 42037486Smckusick } 42137486Smckusick 42237486Smckusick /* 42339507Smckusick * Special device failed operation 42437486Smckusick */ 42539507Smckusick spec_ebadf() 42639507Smckusick { 42739507Smckusick 42839507Smckusick return (EBADF); 42939507Smckusick } 43039507Smckusick 43139507Smckusick /* 43239507Smckusick * Special device bad operation 43339507Smckusick */ 43439446Smckusick spec_badop() 43537486Smckusick { 43637486Smckusick 43739446Smckusick panic("spec_badop called"); 43839292Smckusick /* NOTREACHED */ 43937486Smckusick } 44037486Smckusick 44137486Smckusick /* 44239507Smckusick * Special device null operation 44337486Smckusick */ 44439446Smckusick spec_nullop() 44537486Smckusick { 44637486Smckusick 44737486Smckusick return (0); 44837486Smckusick } 449