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*40189Smckusick * @(#)spec_vnops.c 7.22 (Berkeley) 02/21/90 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(), 3939666Smckusick spec_bmap(), 4039446Smckusick spec_ioctl(), 4139446Smckusick spec_select(), 4239446Smckusick spec_lock(), 4339446Smckusick spec_unlock(), 4439446Smckusick spec_close(), 4539666Smckusick spec_print(), 4639507Smckusick spec_ebadf(), 4739446Smckusick spec_badop(), 4839446Smckusick spec_nullop(); 4937486Smckusick 5039446Smckusick struct vnodeops spec_vnodeops = { 5139507Smckusick spec_lookup, /* lookup */ 5239507Smckusick spec_badop, /* create */ 5339507Smckusick spec_badop, /* mknod */ 5439507Smckusick spec_open, /* open */ 5539507Smckusick spec_close, /* close */ 5639507Smckusick spec_ebadf, /* access */ 5739507Smckusick spec_ebadf, /* getattr */ 5839507Smckusick spec_ebadf, /* setattr */ 5939507Smckusick spec_read, /* read */ 6039507Smckusick spec_write, /* write */ 6139507Smckusick spec_ioctl, /* ioctl */ 6239507Smckusick spec_select, /* select */ 6339507Smckusick spec_badop, /* mmap */ 6439507Smckusick spec_nullop, /* fsync */ 6539507Smckusick spec_badop, /* seek */ 6639507Smckusick spec_badop, /* remove */ 6739507Smckusick spec_badop, /* link */ 6839507Smckusick spec_badop, /* rename */ 6939507Smckusick spec_badop, /* mkdir */ 7039507Smckusick spec_badop, /* rmdir */ 7139507Smckusick spec_badop, /* symlink */ 7239507Smckusick spec_badop, /* readdir */ 7339507Smckusick spec_badop, /* readlink */ 7439507Smckusick spec_badop, /* abortop */ 7539507Smckusick spec_nullop, /* inactive */ 7639507Smckusick spec_nullop, /* reclaim */ 7739507Smckusick spec_lock, /* lock */ 7839507Smckusick spec_unlock, /* unlock */ 7939666Smckusick spec_bmap, /* bmap */ 8039507Smckusick spec_strategy, /* strategy */ 8139666Smckusick spec_print, /* print */ 8239912Smckusick spec_nullop, /* islocked */ 8337486Smckusick }; 8437486Smckusick 8537486Smckusick /* 8639292Smckusick * Trivial lookup routine that always fails. 8739292Smckusick */ 8839446Smckusick spec_lookup(vp, ndp) 8939292Smckusick struct vnode *vp; 9039292Smckusick struct nameidata *ndp; 9139292Smckusick { 9239292Smckusick 9339292Smckusick ndp->ni_dvp = vp; 9439292Smckusick ndp->ni_vp = NULL; 9539292Smckusick return (ENOTDIR); 9639292Smckusick } 9739292Smckusick 9839292Smckusick /* 9937486Smckusick * Open called to allow handler 10037486Smckusick * of special files to initialize and 10137486Smckusick * validate before actual IO. 10237486Smckusick */ 10337725Smckusick /* ARGSUSED */ 10439446Smckusick spec_open(vp, mode, cred) 10537486Smckusick register struct vnode *vp; 10637486Smckusick int mode; 10737486Smckusick struct ucred *cred; 10837486Smckusick { 10937486Smckusick dev_t dev = (dev_t)vp->v_rdev; 11037486Smckusick register int maj = major(dev); 11137486Smckusick 11239365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 11339365Smckusick return (ENXIO); 11439365Smckusick 11537486Smckusick switch (vp->v_type) { 11637486Smckusick 11737486Smckusick case VCHR: 11837486Smckusick if ((u_int)maj >= nchrdev) 11937486Smckusick return (ENXIO); 12039432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 12137486Smckusick 12237486Smckusick case VBLK: 12337486Smckusick if ((u_int)maj >= nblkdev) 12437486Smckusick return (ENXIO); 12539432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 12637486Smckusick } 12737486Smckusick return (0); 12837486Smckusick } 12937486Smckusick 13037486Smckusick /* 13137486Smckusick * Vnode op for read 13237486Smckusick */ 13339588Smckusick spec_read(vp, uio, ioflag, cred) 13437486Smckusick register struct vnode *vp; 13539614Smckusick register struct uio *uio; 13637486Smckusick int ioflag; 13737486Smckusick struct ucred *cred; 13837486Smckusick { 13939614Smckusick struct buf *bp; 14039614Smckusick daddr_t bn; 14139614Smckusick long bsize, bscale; 14239614Smckusick struct partinfo dpart; 14339614Smckusick register int n, on; 14439614Smckusick int error = 0; 14539588Smckusick extern int mem_no; 14637486Smckusick 14739588Smckusick if (uio->uio_rw != UIO_READ) 14839588Smckusick panic("spec_read mode"); 14939588Smckusick if (uio->uio_resid == 0) 15039588Smckusick return (0); 15139588Smckusick 15239588Smckusick switch (vp->v_type) { 15339588Smckusick 15439588Smckusick case VCHR: 15539588Smckusick /* 15639588Smckusick * Negative offsets allowed only for /dev/kmem 15739588Smckusick */ 15839588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 15939588Smckusick return (EINVAL); 16039588Smckusick VOP_UNLOCK(vp); 16139588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 16239588Smckusick (vp->v_rdev, uio, ioflag); 16337725Smckusick VOP_LOCK(vp); 16439588Smckusick return (error); 16539588Smckusick 16639588Smckusick case VBLK: 16739588Smckusick if (uio->uio_offset < 0) 16839588Smckusick return (EINVAL); 16939614Smckusick bsize = BLKDEV_IOSIZE; 17039614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17139614Smckusick (caddr_t)&dpart, FREAD) == 0) { 17239614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17339614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17439614Smckusick bsize = dpart.part->p_frag * 17539614Smckusick dpart.part->p_fsize; 17639614Smckusick } 17739614Smckusick bscale = bsize / DEV_BSIZE; 17839614Smckusick do { 17939614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18039614Smckusick on = uio->uio_offset % bsize; 18139614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 18239614Smckusick if (vp->v_lastr + bscale == bn) 18339614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 18439614Smckusick (int)bsize, NOCRED, &bp); 18539614Smckusick else 18639614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 18739614Smckusick vp->v_lastr = bn; 18839614Smckusick n = MIN(n, bsize - bp->b_resid); 18939614Smckusick if (error) { 19039614Smckusick brelse(bp); 19139614Smckusick return (error); 19239614Smckusick } 19339614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 19439614Smckusick if (n + on == bsize) 19539614Smckusick bp->b_flags |= B_AGE; 19639614Smckusick brelse(bp); 19739614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 19839614Smckusick return (error); 19939588Smckusick 20039588Smckusick default: 20139588Smckusick panic("spec_read type"); 20239588Smckusick } 20339588Smckusick /* NOTREACHED */ 20437486Smckusick } 20537486Smckusick 20637486Smckusick /* 20737486Smckusick * Vnode op for write 20837486Smckusick */ 20939588Smckusick spec_write(vp, uio, ioflag, cred) 21037486Smckusick register struct vnode *vp; 21139614Smckusick register struct uio *uio; 21237486Smckusick int ioflag; 21337486Smckusick struct ucred *cred; 21437486Smckusick { 21539614Smckusick struct buf *bp; 21639614Smckusick daddr_t bn; 21739614Smckusick int bsize, blkmask; 21839614Smckusick struct partinfo dpart; 21939614Smckusick register int n, on, i; 22039614Smckusick int count, error = 0; 22139588Smckusick extern int mem_no; 22237486Smckusick 22339588Smckusick if (uio->uio_rw != UIO_WRITE) 22439588Smckusick panic("spec_write mode"); 22539588Smckusick 22639588Smckusick switch (vp->v_type) { 22739588Smckusick 22839588Smckusick case VCHR: 22939588Smckusick /* 23039588Smckusick * Negative offsets allowed only for /dev/kmem 23139588Smckusick */ 23239588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 23339588Smckusick return (EINVAL); 23439588Smckusick VOP_UNLOCK(vp); 23539588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 23639588Smckusick (vp->v_rdev, uio, ioflag); 23737725Smckusick VOP_LOCK(vp); 23839588Smckusick return (error); 23939588Smckusick 24039588Smckusick case VBLK: 24139588Smckusick if (uio->uio_resid == 0) 24239588Smckusick return (0); 24339588Smckusick if (uio->uio_offset < 0) 24439588Smckusick return (EINVAL); 24539614Smckusick bsize = BLKDEV_IOSIZE; 24639614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 24739614Smckusick (caddr_t)&dpart, FREAD) == 0) { 24839614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 24939614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25039614Smckusick bsize = dpart.part->p_frag * 25139614Smckusick dpart.part->p_fsize; 25239614Smckusick } 25339614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 25439614Smckusick do { 25539614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 25639614Smckusick on = uio->uio_offset % bsize; 25739614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 25839614Smckusick count = howmany(bsize, CLBYTES); 25939614Smckusick for (i = 0; i < count; i++) 26039614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 26139614Smckusick if (n == bsize) 26239614Smckusick bp = getblk(vp, bn, bsize); 26339614Smckusick else 26439614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 26539614Smckusick n = MIN(n, bsize - bp->b_resid); 26639614Smckusick if (error) { 26739614Smckusick brelse(bp); 26839614Smckusick return (error); 26939614Smckusick } 27039614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27139614Smckusick if (n + on == bsize) { 27239614Smckusick bp->b_flags |= B_AGE; 27339614Smckusick bawrite(bp); 27439614Smckusick } else 27539614Smckusick bdwrite(bp); 27639614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 27739614Smckusick return (error); 27839588Smckusick 27939588Smckusick default: 28039588Smckusick panic("spec_write type"); 28139588Smckusick } 28239588Smckusick /* NOTREACHED */ 28337486Smckusick } 28437486Smckusick 28537486Smckusick /* 28637486Smckusick * Device ioctl operation. 28737486Smckusick */ 28837725Smckusick /* ARGSUSED */ 28939446Smckusick spec_ioctl(vp, com, data, fflag, cred) 29037486Smckusick struct vnode *vp; 29139666Smckusick int com; 29237486Smckusick caddr_t data; 29337486Smckusick int fflag; 29437486Smckusick struct ucred *cred; 29537486Smckusick { 29637725Smckusick dev_t dev = vp->v_rdev; 29737486Smckusick 29837486Smckusick switch (vp->v_type) { 29937486Smckusick 30037486Smckusick case VCHR: 30137486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 30237486Smckusick 30337486Smckusick case VBLK: 30439666Smckusick if (com == 0 && (int)data == B_TAPE) 30539666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 30639666Smckusick return (0); 30739666Smckusick else 30839666Smckusick return (1); 30937486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31037486Smckusick 31137486Smckusick default: 31239446Smckusick panic("spec_ioctl"); 31337486Smckusick /* NOTREACHED */ 31437486Smckusick } 31537486Smckusick } 31637486Smckusick 31737725Smckusick /* ARGSUSED */ 318*40189Smckusick spec_select(vp, which, fflags, cred) 31937486Smckusick struct vnode *vp; 320*40189Smckusick int which, fflags; 32137486Smckusick struct ucred *cred; 32237486Smckusick { 32337486Smckusick register dev_t dev; 32437486Smckusick 32537486Smckusick switch (vp->v_type) { 32637486Smckusick 32737486Smckusick default: 32837486Smckusick return (1); /* XXX */ 32937486Smckusick 33037486Smckusick case VCHR: 33137725Smckusick dev = vp->v_rdev; 33237486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 33337486Smckusick } 33437486Smckusick } 33537486Smckusick 33637486Smckusick /* 33737486Smckusick * Just call the device strategy routine 33837486Smckusick */ 33939446Smckusick spec_strategy(bp) 34037486Smckusick register struct buf *bp; 34137486Smckusick { 34239666Smckusick 34337486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 34437486Smckusick return (0); 34537486Smckusick } 34637486Smckusick 34739432Smckusick /* 34839666Smckusick * This is a noop, simply returning what one has been given. 34939666Smckusick */ 35039666Smckusick spec_bmap(vp, bn, vpp, bnp) 35139666Smckusick struct vnode *vp; 35239666Smckusick daddr_t bn; 35339666Smckusick struct vnode **vpp; 35439666Smckusick daddr_t *bnp; 35539666Smckusick { 35639666Smckusick 35739666Smckusick if (vpp != NULL) 35839666Smckusick *vpp = vp; 35939666Smckusick if (bnp != NULL) 36039666Smckusick *bnp = bn; 36139666Smckusick return (0); 36239666Smckusick } 36339666Smckusick 36439666Smckusick /* 36539432Smckusick * At the moment we do not do any locking. 36639432Smckusick */ 36739489Smckusick /* ARGSUSED */ 36839446Smckusick spec_lock(vp) 36937486Smckusick struct vnode *vp; 37037486Smckusick { 37137486Smckusick 37237486Smckusick return (0); 37337486Smckusick } 37437486Smckusick 37539489Smckusick /* ARGSUSED */ 37639446Smckusick spec_unlock(vp) 37737486Smckusick struct vnode *vp; 37837486Smckusick { 37937486Smckusick 38037486Smckusick return (0); 38137486Smckusick } 38237486Smckusick 38337486Smckusick /* 38437486Smckusick * Device close routine 38537486Smckusick */ 38637725Smckusick /* ARGSUSED */ 38739446Smckusick spec_close(vp, flag, cred) 38837725Smckusick register struct vnode *vp; 38937486Smckusick int flag; 39037486Smckusick struct ucred *cred; 39137486Smckusick { 39237486Smckusick dev_t dev = vp->v_rdev; 39337725Smckusick int (*cfunc)(); 39437725Smckusick int error, mode; 39537486Smckusick 39637725Smckusick switch (vp->v_type) { 39737725Smckusick 39837725Smckusick case VCHR: 39939485Smckusick /* 40039485Smckusick * If the vnode is locked, then we are in the midst 40139485Smckusick * of forcably closing the device, otherwise we only 40239485Smckusick * close on last reference. 40339485Smckusick */ 40439630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 40537725Smckusick return (0); 40637725Smckusick cfunc = cdevsw[major(dev)].d_close; 40739432Smckusick mode = S_IFCHR; 40837725Smckusick break; 40937725Smckusick 41037725Smckusick case VBLK: 41137725Smckusick /* 41237725Smckusick * On last close of a block device (that isn't mounted) 41337725Smckusick * we must invalidate any in core blocks, so that 41437725Smckusick * we can, for instance, change floppy disks. 41537725Smckusick */ 41639666Smckusick vflushbuf(vp, 0); 41739666Smckusick if (vinvalbuf(vp, 1)) 41838613Smckusick return (0); 41937725Smckusick /* 42039485Smckusick * We do not want to really close the device if it 42139485Smckusick * is still in use unless we are trying to close it 42239485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 42339630Smckusick * holds a reference to the vnode, and because we mark 42439630Smckusick * any other vnodes that alias this device, when the 42539630Smckusick * sum of the reference counts on all the aliased 42639630Smckusick * vnodes descends to one, we are on last close. 42737725Smckusick */ 42839630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 42937725Smckusick return (0); 43037725Smckusick cfunc = bdevsw[major(dev)].d_close; 43139432Smckusick mode = S_IFBLK; 43237725Smckusick break; 43337725Smckusick 43437725Smckusick default: 43539446Smckusick panic("spec_close: not special"); 43637725Smckusick } 43737725Smckusick 43837725Smckusick if (setjmp(&u.u_qsave)) { 43937725Smckusick /* 44037725Smckusick * If device close routine is interrupted, 44137725Smckusick * must return so closef can clean up. 44237725Smckusick */ 44337725Smckusick error = EINTR; 44437725Smckusick } else 44537725Smckusick error = (*cfunc)(dev, flag, mode); 44637725Smckusick return (error); 44737486Smckusick } 44837486Smckusick 44937486Smckusick /* 45039666Smckusick * Print out the contents of a special device vnode. 45139666Smckusick */ 45239666Smckusick spec_print(vp) 45339666Smckusick struct vnode *vp; 45439666Smckusick { 45539666Smckusick 45639666Smckusick printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev), 45739666Smckusick minor(vp->v_rdev)); 45839666Smckusick } 45939666Smckusick 46039666Smckusick /* 46139507Smckusick * Special device failed operation 46237486Smckusick */ 46339507Smckusick spec_ebadf() 46439507Smckusick { 46539507Smckusick 46639507Smckusick return (EBADF); 46739507Smckusick } 46839507Smckusick 46939507Smckusick /* 47039507Smckusick * Special device bad operation 47139507Smckusick */ 47239446Smckusick spec_badop() 47337486Smckusick { 47437486Smckusick 47539446Smckusick panic("spec_badop called"); 47639292Smckusick /* NOTREACHED */ 47737486Smckusick } 47837486Smckusick 47937486Smckusick /* 48039507Smckusick * Special device null operation 48137486Smckusick */ 48239446Smckusick spec_nullop() 48337486Smckusick { 48437486Smckusick 48537486Smckusick return (0); 48637486Smckusick } 487