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*41961Smckusick * @(#)spec_vnops.c 7.27 (Berkeley) 05/15/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" 2840652Smckusick #include "specdev.h" 2939432Smckusick #include "stat.h" 3037486Smckusick #include "errno.h" 3139614Smckusick #include "ioctl.h" 3239614Smckusick #include "file.h" 3339614Smckusick #include "disklabel.h" 3437486Smckusick 3540707Skarels /* symbolic sleep message strings for devices */ 3640707Skarels char devopn[] = "devopn"; 3740707Skarels char devio[] = "devio"; 3840707Skarels char devwait[] = "devwait"; 3940707Skarels char devin[] = "devin"; 4040707Skarels char devout[] = "devout"; 4140707Skarels char devioc[] = "devioc"; 4240707Skarels char devcls[] = "devcls"; 4340707Skarels 4439446Smckusick int spec_lookup(), 4539446Smckusick spec_open(), 4639446Smckusick spec_read(), 4739446Smckusick spec_write(), 4839446Smckusick spec_strategy(), 4939666Smckusick spec_bmap(), 5039446Smckusick spec_ioctl(), 5139446Smckusick spec_select(), 5239446Smckusick spec_lock(), 5339446Smckusick spec_unlock(), 5439446Smckusick spec_close(), 5539666Smckusick spec_print(), 5639507Smckusick spec_ebadf(), 5739446Smckusick spec_badop(), 5839446Smckusick spec_nullop(); 5937486Smckusick 6039446Smckusick struct vnodeops spec_vnodeops = { 6139507Smckusick spec_lookup, /* lookup */ 6239507Smckusick spec_badop, /* create */ 6339507Smckusick spec_badop, /* mknod */ 6439507Smckusick spec_open, /* open */ 6539507Smckusick spec_close, /* close */ 6639507Smckusick spec_ebadf, /* access */ 6739507Smckusick spec_ebadf, /* getattr */ 6839507Smckusick spec_ebadf, /* setattr */ 6939507Smckusick spec_read, /* read */ 7039507Smckusick spec_write, /* write */ 7139507Smckusick spec_ioctl, /* ioctl */ 7239507Smckusick spec_select, /* select */ 7339507Smckusick spec_badop, /* mmap */ 7439507Smckusick spec_nullop, /* fsync */ 7539507Smckusick spec_badop, /* seek */ 7639507Smckusick spec_badop, /* remove */ 7739507Smckusick spec_badop, /* link */ 7839507Smckusick spec_badop, /* rename */ 7939507Smckusick spec_badop, /* mkdir */ 8039507Smckusick spec_badop, /* rmdir */ 8139507Smckusick spec_badop, /* symlink */ 8239507Smckusick spec_badop, /* readdir */ 8339507Smckusick spec_badop, /* readlink */ 8439507Smckusick spec_badop, /* abortop */ 8539507Smckusick spec_nullop, /* inactive */ 8639507Smckusick spec_nullop, /* reclaim */ 8739507Smckusick spec_lock, /* lock */ 8839507Smckusick spec_unlock, /* unlock */ 8939666Smckusick spec_bmap, /* bmap */ 9039507Smckusick spec_strategy, /* strategy */ 9139666Smckusick spec_print, /* print */ 9239912Smckusick spec_nullop, /* islocked */ 9337486Smckusick }; 9437486Smckusick 9537486Smckusick /* 9639292Smckusick * Trivial lookup routine that always fails. 9739292Smckusick */ 9839446Smckusick spec_lookup(vp, ndp) 9939292Smckusick struct vnode *vp; 10039292Smckusick struct nameidata *ndp; 10139292Smckusick { 10239292Smckusick 10339292Smckusick ndp->ni_dvp = vp; 10439292Smckusick ndp->ni_vp = NULL; 10539292Smckusick return (ENOTDIR); 10639292Smckusick } 10739292Smckusick 10839292Smckusick /* 10937486Smckusick * Open called to allow handler 11037486Smckusick * of special files to initialize and 11137486Smckusick * validate before actual IO. 11237486Smckusick */ 11337725Smckusick /* ARGSUSED */ 11439446Smckusick spec_open(vp, mode, cred) 11537486Smckusick register struct vnode *vp; 11637486Smckusick int mode; 11737486Smckusick struct ucred *cred; 11837486Smckusick { 11937486Smckusick dev_t dev = (dev_t)vp->v_rdev; 12037486Smckusick register int maj = major(dev); 12140375Smckusick int error; 12237486Smckusick 12341400Smckusick if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12439365Smckusick return (ENXIO); 12539365Smckusick 12637486Smckusick switch (vp->v_type) { 12737486Smckusick 12837486Smckusick case VCHR: 12937486Smckusick if ((u_int)maj >= nchrdev) 13037486Smckusick return (ENXIO); 13139432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 13237486Smckusick 13337486Smckusick case VBLK: 13437486Smckusick if ((u_int)maj >= nblkdev) 13537486Smckusick return (ENXIO); 13640375Smckusick if (error = mountedon(vp)) 13740375Smckusick return (error); 13839432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 13937486Smckusick } 14037486Smckusick return (0); 14137486Smckusick } 14237486Smckusick 14337486Smckusick /* 14437486Smckusick * Vnode op for read 14537486Smckusick */ 146*41961Smckusick /* ARGSUSED */ 14739588Smckusick spec_read(vp, uio, ioflag, cred) 14837486Smckusick register struct vnode *vp; 14939614Smckusick register struct uio *uio; 15037486Smckusick int ioflag; 15137486Smckusick struct ucred *cred; 15237486Smckusick { 15339614Smckusick struct buf *bp; 15439614Smckusick daddr_t bn; 15539614Smckusick long bsize, bscale; 15639614Smckusick struct partinfo dpart; 15739614Smckusick register int n, on; 15839614Smckusick int error = 0; 15939588Smckusick extern int mem_no; 16037486Smckusick 16139588Smckusick if (uio->uio_rw != UIO_READ) 16239588Smckusick panic("spec_read mode"); 16339588Smckusick if (uio->uio_resid == 0) 16439588Smckusick return (0); 16539588Smckusick 16639588Smckusick switch (vp->v_type) { 16739588Smckusick 16839588Smckusick case VCHR: 16939588Smckusick /* 17039588Smckusick * Negative offsets allowed only for /dev/kmem 17139588Smckusick */ 17239588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 17339588Smckusick return (EINVAL); 17439588Smckusick VOP_UNLOCK(vp); 17539588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 17639588Smckusick (vp->v_rdev, uio, ioflag); 17737725Smckusick VOP_LOCK(vp); 17839588Smckusick return (error); 17939588Smckusick 18039588Smckusick case VBLK: 18139588Smckusick if (uio->uio_offset < 0) 18239588Smckusick return (EINVAL); 18339614Smckusick bsize = BLKDEV_IOSIZE; 18439614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 18539614Smckusick (caddr_t)&dpart, FREAD) == 0) { 18639614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 18739614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 18839614Smckusick bsize = dpart.part->p_frag * 18939614Smckusick dpart.part->p_fsize; 19039614Smckusick } 19139614Smckusick bscale = bsize / DEV_BSIZE; 19239614Smckusick do { 19339614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 19439614Smckusick on = uio->uio_offset % bsize; 19539614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 19639614Smckusick if (vp->v_lastr + bscale == bn) 19739614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 19839614Smckusick (int)bsize, NOCRED, &bp); 19939614Smckusick else 20039614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 20139614Smckusick vp->v_lastr = bn; 20239614Smckusick n = MIN(n, bsize - bp->b_resid); 20339614Smckusick if (error) { 20439614Smckusick brelse(bp); 20539614Smckusick return (error); 20639614Smckusick } 20739614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 20839614Smckusick if (n + on == bsize) 20939614Smckusick bp->b_flags |= B_AGE; 21039614Smckusick brelse(bp); 21139614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 21239614Smckusick return (error); 21339588Smckusick 21439588Smckusick default: 21539588Smckusick panic("spec_read type"); 21639588Smckusick } 21739588Smckusick /* NOTREACHED */ 21837486Smckusick } 21937486Smckusick 22037486Smckusick /* 22137486Smckusick * Vnode op for write 22237486Smckusick */ 223*41961Smckusick /* ARGSUSED */ 22439588Smckusick spec_write(vp, uio, ioflag, cred) 22537486Smckusick register struct vnode *vp; 22639614Smckusick register struct uio *uio; 22737486Smckusick int ioflag; 22837486Smckusick struct ucred *cred; 22937486Smckusick { 23039614Smckusick struct buf *bp; 23139614Smckusick daddr_t bn; 23239614Smckusick int bsize, blkmask; 23339614Smckusick struct partinfo dpart; 23439614Smckusick register int n, on, i; 23539614Smckusick int count, error = 0; 23639588Smckusick extern int mem_no; 23737486Smckusick 23839588Smckusick if (uio->uio_rw != UIO_WRITE) 23939588Smckusick panic("spec_write mode"); 24039588Smckusick 24139588Smckusick switch (vp->v_type) { 24239588Smckusick 24339588Smckusick case VCHR: 24439588Smckusick /* 24539588Smckusick * Negative offsets allowed only for /dev/kmem 24639588Smckusick */ 24739588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 24839588Smckusick return (EINVAL); 24939588Smckusick VOP_UNLOCK(vp); 25039588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 25139588Smckusick (vp->v_rdev, uio, ioflag); 25237725Smckusick VOP_LOCK(vp); 25339588Smckusick return (error); 25439588Smckusick 25539588Smckusick case VBLK: 25639588Smckusick if (uio->uio_resid == 0) 25739588Smckusick return (0); 25839588Smckusick if (uio->uio_offset < 0) 25939588Smckusick return (EINVAL); 26039614Smckusick bsize = BLKDEV_IOSIZE; 26139614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 26239614Smckusick (caddr_t)&dpart, FREAD) == 0) { 26339614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 26439614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 26539614Smckusick bsize = dpart.part->p_frag * 26639614Smckusick dpart.part->p_fsize; 26739614Smckusick } 26839614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 26939614Smckusick do { 27039614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 27139614Smckusick on = uio->uio_offset % bsize; 27239614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 27339614Smckusick count = howmany(bsize, CLBYTES); 27439614Smckusick for (i = 0; i < count; i++) 27539614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 27639614Smckusick if (n == bsize) 27739614Smckusick bp = getblk(vp, bn, bsize); 27839614Smckusick else 27939614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 28039614Smckusick n = MIN(n, bsize - bp->b_resid); 28139614Smckusick if (error) { 28239614Smckusick brelse(bp); 28339614Smckusick return (error); 28439614Smckusick } 28539614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 28639614Smckusick if (n + on == bsize) { 28739614Smckusick bp->b_flags |= B_AGE; 28839614Smckusick bawrite(bp); 28939614Smckusick } else 29039614Smckusick bdwrite(bp); 29139614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 29239614Smckusick return (error); 29339588Smckusick 29439588Smckusick default: 29539588Smckusick panic("spec_write type"); 29639588Smckusick } 29739588Smckusick /* NOTREACHED */ 29837486Smckusick } 29937486Smckusick 30037486Smckusick /* 30137486Smckusick * Device ioctl operation. 30237486Smckusick */ 30337725Smckusick /* ARGSUSED */ 30439446Smckusick spec_ioctl(vp, com, data, fflag, cred) 30537486Smckusick struct vnode *vp; 30639666Smckusick int com; 30737486Smckusick caddr_t data; 30837486Smckusick int fflag; 30937486Smckusick struct ucred *cred; 31037486Smckusick { 31137725Smckusick dev_t dev = vp->v_rdev; 31237486Smckusick 31337486Smckusick switch (vp->v_type) { 31437486Smckusick 31537486Smckusick case VCHR: 31637486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31737486Smckusick 31837486Smckusick case VBLK: 31939666Smckusick if (com == 0 && (int)data == B_TAPE) 32039666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 32139666Smckusick return (0); 32239666Smckusick else 32339666Smckusick return (1); 32437486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 32537486Smckusick 32637486Smckusick default: 32739446Smckusick panic("spec_ioctl"); 32837486Smckusick /* NOTREACHED */ 32937486Smckusick } 33037486Smckusick } 33137486Smckusick 33237725Smckusick /* ARGSUSED */ 33340189Smckusick spec_select(vp, which, fflags, cred) 33437486Smckusick struct vnode *vp; 33540189Smckusick int which, fflags; 33637486Smckusick struct ucred *cred; 33737486Smckusick { 33837486Smckusick register dev_t dev; 33937486Smckusick 34037486Smckusick switch (vp->v_type) { 34137486Smckusick 34237486Smckusick default: 34337486Smckusick return (1); /* XXX */ 34437486Smckusick 34537486Smckusick case VCHR: 34637725Smckusick dev = vp->v_rdev; 34737486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 34837486Smckusick } 34937486Smckusick } 35037486Smckusick 35137486Smckusick /* 35237486Smckusick * Just call the device strategy routine 35337486Smckusick */ 35439446Smckusick spec_strategy(bp) 35537486Smckusick register struct buf *bp; 35637486Smckusick { 35739666Smckusick 35837486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 35937486Smckusick return (0); 36037486Smckusick } 36137486Smckusick 36239432Smckusick /* 36339666Smckusick * This is a noop, simply returning what one has been given. 36439666Smckusick */ 36539666Smckusick spec_bmap(vp, bn, vpp, bnp) 36639666Smckusick struct vnode *vp; 36739666Smckusick daddr_t bn; 36839666Smckusick struct vnode **vpp; 36939666Smckusick daddr_t *bnp; 37039666Smckusick { 37139666Smckusick 37239666Smckusick if (vpp != NULL) 37339666Smckusick *vpp = vp; 37439666Smckusick if (bnp != NULL) 37539666Smckusick *bnp = bn; 37639666Smckusick return (0); 37739666Smckusick } 37839666Smckusick 37939666Smckusick /* 38039432Smckusick * At the moment we do not do any locking. 38139432Smckusick */ 38239489Smckusick /* ARGSUSED */ 38339446Smckusick spec_lock(vp) 38437486Smckusick struct vnode *vp; 38537486Smckusick { 38637486Smckusick 38737486Smckusick return (0); 38837486Smckusick } 38937486Smckusick 39039489Smckusick /* ARGSUSED */ 39139446Smckusick spec_unlock(vp) 39237486Smckusick struct vnode *vp; 39337486Smckusick { 39437486Smckusick 39537486Smckusick return (0); 39637486Smckusick } 39737486Smckusick 39837486Smckusick /* 39937486Smckusick * Device close routine 40037486Smckusick */ 40137725Smckusick /* ARGSUSED */ 40239446Smckusick spec_close(vp, flag, cred) 40337725Smckusick register struct vnode *vp; 40437486Smckusick int flag; 40537486Smckusick struct ucred *cred; 40637486Smckusick { 40737486Smckusick dev_t dev = vp->v_rdev; 40837725Smckusick int (*cfunc)(); 40940707Skarels int mode; 41037486Smckusick 41137725Smckusick switch (vp->v_type) { 41237725Smckusick 41337725Smckusick case VCHR: 41439485Smckusick /* 41539485Smckusick * If the vnode is locked, then we are in the midst 41639485Smckusick * of forcably closing the device, otherwise we only 41739485Smckusick * close on last reference. 41839485Smckusick */ 41939630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 42037725Smckusick return (0); 42137725Smckusick cfunc = cdevsw[major(dev)].d_close; 42239432Smckusick mode = S_IFCHR; 42337725Smckusick break; 42437725Smckusick 42537725Smckusick case VBLK: 42637725Smckusick /* 42737725Smckusick * On last close of a block device (that isn't mounted) 42837725Smckusick * we must invalidate any in core blocks, so that 42937725Smckusick * we can, for instance, change floppy disks. 43037725Smckusick */ 43139666Smckusick vflushbuf(vp, 0); 43239666Smckusick if (vinvalbuf(vp, 1)) 43338613Smckusick return (0); 43437725Smckusick /* 43539485Smckusick * We do not want to really close the device if it 43639485Smckusick * is still in use unless we are trying to close it 43739485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 43839630Smckusick * holds a reference to the vnode, and because we mark 43939630Smckusick * any other vnodes that alias this device, when the 44039630Smckusick * sum of the reference counts on all the aliased 44139630Smckusick * vnodes descends to one, we are on last close. 44237725Smckusick */ 44339630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 44437725Smckusick return (0); 44537725Smckusick cfunc = bdevsw[major(dev)].d_close; 44639432Smckusick mode = S_IFBLK; 44737725Smckusick break; 44837725Smckusick 44937725Smckusick default: 45039446Smckusick panic("spec_close: not special"); 45137725Smckusick } 45237725Smckusick 45340707Skarels return ((*cfunc)(dev, flag, mode)); 45437486Smckusick } 45537486Smckusick 45637486Smckusick /* 45739666Smckusick * Print out the contents of a special device vnode. 45839666Smckusick */ 45939666Smckusick spec_print(vp) 46039666Smckusick struct vnode *vp; 46139666Smckusick { 46239666Smckusick 46339666Smckusick printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev), 46439666Smckusick minor(vp->v_rdev)); 46539666Smckusick } 46639666Smckusick 46739666Smckusick /* 46839507Smckusick * Special device failed operation 46937486Smckusick */ 47039507Smckusick spec_ebadf() 47139507Smckusick { 47239507Smckusick 47339507Smckusick return (EBADF); 47439507Smckusick } 47539507Smckusick 47639507Smckusick /* 47739507Smckusick * Special device bad operation 47839507Smckusick */ 47939446Smckusick spec_badop() 48037486Smckusick { 48137486Smckusick 48239446Smckusick panic("spec_badop called"); 48339292Smckusick /* NOTREACHED */ 48437486Smckusick } 48537486Smckusick 48637486Smckusick /* 48739507Smckusick * Special device null operation 48837486Smckusick */ 48939446Smckusick spec_nullop() 49037486Smckusick { 49137486Smckusick 49237486Smckusick return (0); 49337486Smckusick } 494