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*40375Smckusick * @(#)spec_vnops.c 7.23 (Berkeley) 03/09/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); 111*40375Smckusick int error; 11237486Smckusick 11339365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 11439365Smckusick return (ENXIO); 11539365Smckusick 11637486Smckusick switch (vp->v_type) { 11737486Smckusick 11837486Smckusick case VCHR: 11937486Smckusick if ((u_int)maj >= nchrdev) 12037486Smckusick return (ENXIO); 12139432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 12237486Smckusick 12337486Smckusick case VBLK: 12437486Smckusick if ((u_int)maj >= nblkdev) 12537486Smckusick return (ENXIO); 126*40375Smckusick if (error = mountedon(vp)) 127*40375Smckusick return (error); 12839432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 12937486Smckusick } 13037486Smckusick return (0); 13137486Smckusick } 13237486Smckusick 13337486Smckusick /* 13437486Smckusick * Vnode op for read 13537486Smckusick */ 13639588Smckusick spec_read(vp, uio, ioflag, cred) 13737486Smckusick register struct vnode *vp; 13839614Smckusick register struct uio *uio; 13937486Smckusick int ioflag; 14037486Smckusick struct ucred *cred; 14137486Smckusick { 14239614Smckusick struct buf *bp; 14339614Smckusick daddr_t bn; 14439614Smckusick long bsize, bscale; 14539614Smckusick struct partinfo dpart; 14639614Smckusick register int n, on; 14739614Smckusick int error = 0; 14839588Smckusick extern int mem_no; 14937486Smckusick 15039588Smckusick if (uio->uio_rw != UIO_READ) 15139588Smckusick panic("spec_read mode"); 15239588Smckusick if (uio->uio_resid == 0) 15339588Smckusick return (0); 15439588Smckusick 15539588Smckusick switch (vp->v_type) { 15639588Smckusick 15739588Smckusick case VCHR: 15839588Smckusick /* 15939588Smckusick * Negative offsets allowed only for /dev/kmem 16039588Smckusick */ 16139588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 16239588Smckusick return (EINVAL); 16339588Smckusick VOP_UNLOCK(vp); 16439588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 16539588Smckusick (vp->v_rdev, uio, ioflag); 16637725Smckusick VOP_LOCK(vp); 16739588Smckusick return (error); 16839588Smckusick 16939588Smckusick case VBLK: 17039588Smckusick if (uio->uio_offset < 0) 17139588Smckusick return (EINVAL); 17239614Smckusick bsize = BLKDEV_IOSIZE; 17339614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17439614Smckusick (caddr_t)&dpart, FREAD) == 0) { 17539614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17639614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17739614Smckusick bsize = dpart.part->p_frag * 17839614Smckusick dpart.part->p_fsize; 17939614Smckusick } 18039614Smckusick bscale = bsize / DEV_BSIZE; 18139614Smckusick do { 18239614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18339614Smckusick on = uio->uio_offset % bsize; 18439614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 18539614Smckusick if (vp->v_lastr + bscale == bn) 18639614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 18739614Smckusick (int)bsize, NOCRED, &bp); 18839614Smckusick else 18939614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 19039614Smckusick vp->v_lastr = bn; 19139614Smckusick n = MIN(n, bsize - bp->b_resid); 19239614Smckusick if (error) { 19339614Smckusick brelse(bp); 19439614Smckusick return (error); 19539614Smckusick } 19639614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 19739614Smckusick if (n + on == bsize) 19839614Smckusick bp->b_flags |= B_AGE; 19939614Smckusick brelse(bp); 20039614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 20139614Smckusick return (error); 20239588Smckusick 20339588Smckusick default: 20439588Smckusick panic("spec_read type"); 20539588Smckusick } 20639588Smckusick /* NOTREACHED */ 20737486Smckusick } 20837486Smckusick 20937486Smckusick /* 21037486Smckusick * Vnode op for write 21137486Smckusick */ 21239588Smckusick spec_write(vp, uio, ioflag, cred) 21337486Smckusick register struct vnode *vp; 21439614Smckusick register struct uio *uio; 21537486Smckusick int ioflag; 21637486Smckusick struct ucred *cred; 21737486Smckusick { 21839614Smckusick struct buf *bp; 21939614Smckusick daddr_t bn; 22039614Smckusick int bsize, blkmask; 22139614Smckusick struct partinfo dpart; 22239614Smckusick register int n, on, i; 22339614Smckusick int count, error = 0; 22439588Smckusick extern int mem_no; 22537486Smckusick 22639588Smckusick if (uio->uio_rw != UIO_WRITE) 22739588Smckusick panic("spec_write mode"); 22839588Smckusick 22939588Smckusick switch (vp->v_type) { 23039588Smckusick 23139588Smckusick case VCHR: 23239588Smckusick /* 23339588Smckusick * Negative offsets allowed only for /dev/kmem 23439588Smckusick */ 23539588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 23639588Smckusick return (EINVAL); 23739588Smckusick VOP_UNLOCK(vp); 23839588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 23939588Smckusick (vp->v_rdev, uio, ioflag); 24037725Smckusick VOP_LOCK(vp); 24139588Smckusick return (error); 24239588Smckusick 24339588Smckusick case VBLK: 24439588Smckusick if (uio->uio_resid == 0) 24539588Smckusick return (0); 24639588Smckusick if (uio->uio_offset < 0) 24739588Smckusick return (EINVAL); 24839614Smckusick bsize = BLKDEV_IOSIZE; 24939614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 25039614Smckusick (caddr_t)&dpart, FREAD) == 0) { 25139614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 25239614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25339614Smckusick bsize = dpart.part->p_frag * 25439614Smckusick dpart.part->p_fsize; 25539614Smckusick } 25639614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 25739614Smckusick do { 25839614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 25939614Smckusick on = uio->uio_offset % bsize; 26039614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 26139614Smckusick count = howmany(bsize, CLBYTES); 26239614Smckusick for (i = 0; i < count; i++) 26339614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 26439614Smckusick if (n == bsize) 26539614Smckusick bp = getblk(vp, bn, bsize); 26639614Smckusick else 26739614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 26839614Smckusick n = MIN(n, bsize - bp->b_resid); 26939614Smckusick if (error) { 27039614Smckusick brelse(bp); 27139614Smckusick return (error); 27239614Smckusick } 27339614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27439614Smckusick if (n + on == bsize) { 27539614Smckusick bp->b_flags |= B_AGE; 27639614Smckusick bawrite(bp); 27739614Smckusick } else 27839614Smckusick bdwrite(bp); 27939614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 28039614Smckusick return (error); 28139588Smckusick 28239588Smckusick default: 28339588Smckusick panic("spec_write type"); 28439588Smckusick } 28539588Smckusick /* NOTREACHED */ 28637486Smckusick } 28737486Smckusick 28837486Smckusick /* 28937486Smckusick * Device ioctl operation. 29037486Smckusick */ 29137725Smckusick /* ARGSUSED */ 29239446Smckusick spec_ioctl(vp, com, data, fflag, cred) 29337486Smckusick struct vnode *vp; 29439666Smckusick int com; 29537486Smckusick caddr_t data; 29637486Smckusick int fflag; 29737486Smckusick struct ucred *cred; 29837486Smckusick { 29937725Smckusick dev_t dev = vp->v_rdev; 30037486Smckusick 30137486Smckusick switch (vp->v_type) { 30237486Smckusick 30337486Smckusick case VCHR: 30437486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 30537486Smckusick 30637486Smckusick case VBLK: 30739666Smckusick if (com == 0 && (int)data == B_TAPE) 30839666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 30939666Smckusick return (0); 31039666Smckusick else 31139666Smckusick return (1); 31237486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31337486Smckusick 31437486Smckusick default: 31539446Smckusick panic("spec_ioctl"); 31637486Smckusick /* NOTREACHED */ 31737486Smckusick } 31837486Smckusick } 31937486Smckusick 32037725Smckusick /* ARGSUSED */ 32140189Smckusick spec_select(vp, which, fflags, cred) 32237486Smckusick struct vnode *vp; 32340189Smckusick int which, fflags; 32437486Smckusick struct ucred *cred; 32537486Smckusick { 32637486Smckusick register dev_t dev; 32737486Smckusick 32837486Smckusick switch (vp->v_type) { 32937486Smckusick 33037486Smckusick default: 33137486Smckusick return (1); /* XXX */ 33237486Smckusick 33337486Smckusick case VCHR: 33437725Smckusick dev = vp->v_rdev; 33537486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 33637486Smckusick } 33737486Smckusick } 33837486Smckusick 33937486Smckusick /* 34037486Smckusick * Just call the device strategy routine 34137486Smckusick */ 34239446Smckusick spec_strategy(bp) 34337486Smckusick register struct buf *bp; 34437486Smckusick { 34539666Smckusick 34637486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 34737486Smckusick return (0); 34837486Smckusick } 34937486Smckusick 35039432Smckusick /* 35139666Smckusick * This is a noop, simply returning what one has been given. 35239666Smckusick */ 35339666Smckusick spec_bmap(vp, bn, vpp, bnp) 35439666Smckusick struct vnode *vp; 35539666Smckusick daddr_t bn; 35639666Smckusick struct vnode **vpp; 35739666Smckusick daddr_t *bnp; 35839666Smckusick { 35939666Smckusick 36039666Smckusick if (vpp != NULL) 36139666Smckusick *vpp = vp; 36239666Smckusick if (bnp != NULL) 36339666Smckusick *bnp = bn; 36439666Smckusick return (0); 36539666Smckusick } 36639666Smckusick 36739666Smckusick /* 36839432Smckusick * At the moment we do not do any locking. 36939432Smckusick */ 37039489Smckusick /* ARGSUSED */ 37139446Smckusick spec_lock(vp) 37237486Smckusick struct vnode *vp; 37337486Smckusick { 37437486Smckusick 37537486Smckusick return (0); 37637486Smckusick } 37737486Smckusick 37839489Smckusick /* ARGSUSED */ 37939446Smckusick spec_unlock(vp) 38037486Smckusick struct vnode *vp; 38137486Smckusick { 38237486Smckusick 38337486Smckusick return (0); 38437486Smckusick } 38537486Smckusick 38637486Smckusick /* 38737486Smckusick * Device close routine 38837486Smckusick */ 38937725Smckusick /* ARGSUSED */ 39039446Smckusick spec_close(vp, flag, cred) 39137725Smckusick register struct vnode *vp; 39237486Smckusick int flag; 39337486Smckusick struct ucred *cred; 39437486Smckusick { 39537486Smckusick dev_t dev = vp->v_rdev; 39637725Smckusick int (*cfunc)(); 39737725Smckusick int error, mode; 39837486Smckusick 39937725Smckusick switch (vp->v_type) { 40037725Smckusick 40137725Smckusick case VCHR: 40239485Smckusick /* 40339485Smckusick * If the vnode is locked, then we are in the midst 40439485Smckusick * of forcably closing the device, otherwise we only 40539485Smckusick * close on last reference. 40639485Smckusick */ 40739630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 40837725Smckusick return (0); 40937725Smckusick cfunc = cdevsw[major(dev)].d_close; 41039432Smckusick mode = S_IFCHR; 41137725Smckusick break; 41237725Smckusick 41337725Smckusick case VBLK: 41437725Smckusick /* 41537725Smckusick * On last close of a block device (that isn't mounted) 41637725Smckusick * we must invalidate any in core blocks, so that 41737725Smckusick * we can, for instance, change floppy disks. 41837725Smckusick */ 41939666Smckusick vflushbuf(vp, 0); 42039666Smckusick if (vinvalbuf(vp, 1)) 42138613Smckusick return (0); 42237725Smckusick /* 42339485Smckusick * We do not want to really close the device if it 42439485Smckusick * is still in use unless we are trying to close it 42539485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 42639630Smckusick * holds a reference to the vnode, and because we mark 42739630Smckusick * any other vnodes that alias this device, when the 42839630Smckusick * sum of the reference counts on all the aliased 42939630Smckusick * vnodes descends to one, we are on last close. 43037725Smckusick */ 43139630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 43237725Smckusick return (0); 43337725Smckusick cfunc = bdevsw[major(dev)].d_close; 43439432Smckusick mode = S_IFBLK; 43537725Smckusick break; 43637725Smckusick 43737725Smckusick default: 43839446Smckusick panic("spec_close: not special"); 43937725Smckusick } 44037725Smckusick 44137725Smckusick if (setjmp(&u.u_qsave)) { 44237725Smckusick /* 44337725Smckusick * If device close routine is interrupted, 44437725Smckusick * must return so closef can clean up. 44537725Smckusick */ 44637725Smckusick error = EINTR; 44737725Smckusick } else 44837725Smckusick error = (*cfunc)(dev, flag, mode); 44937725Smckusick return (error); 45037486Smckusick } 45137486Smckusick 45237486Smckusick /* 45339666Smckusick * Print out the contents of a special device vnode. 45439666Smckusick */ 45539666Smckusick spec_print(vp) 45639666Smckusick struct vnode *vp; 45739666Smckusick { 45839666Smckusick 45939666Smckusick printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev), 46039666Smckusick minor(vp->v_rdev)); 46139666Smckusick } 46239666Smckusick 46339666Smckusick /* 46439507Smckusick * Special device failed operation 46537486Smckusick */ 46639507Smckusick spec_ebadf() 46739507Smckusick { 46839507Smckusick 46939507Smckusick return (EBADF); 47039507Smckusick } 47139507Smckusick 47239507Smckusick /* 47339507Smckusick * Special device bad operation 47439507Smckusick */ 47539446Smckusick spec_badop() 47637486Smckusick { 47737486Smckusick 47839446Smckusick panic("spec_badop called"); 47939292Smckusick /* NOTREACHED */ 48037486Smckusick } 48137486Smckusick 48237486Smckusick /* 48339507Smckusick * Special device null operation 48437486Smckusick */ 48539446Smckusick spec_nullop() 48637486Smckusick { 48737486Smckusick 48837486Smckusick return (0); 48937486Smckusick } 490