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*41400Smckusick * @(#)spec_vnops.c 7.26 (Berkeley) 05/04/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 123*41400Smckusick 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 */ 14639588Smckusick spec_read(vp, uio, ioflag, cred) 14737486Smckusick register struct vnode *vp; 14839614Smckusick register struct uio *uio; 14937486Smckusick int ioflag; 15037486Smckusick struct ucred *cred; 15137486Smckusick { 15239614Smckusick struct buf *bp; 15339614Smckusick daddr_t bn; 15439614Smckusick long bsize, bscale; 15539614Smckusick struct partinfo dpart; 15639614Smckusick register int n, on; 15739614Smckusick int error = 0; 15839588Smckusick extern int mem_no; 15937486Smckusick 16039588Smckusick if (uio->uio_rw != UIO_READ) 16139588Smckusick panic("spec_read mode"); 16239588Smckusick if (uio->uio_resid == 0) 16339588Smckusick return (0); 16439588Smckusick 16539588Smckusick switch (vp->v_type) { 16639588Smckusick 16739588Smckusick case VCHR: 16839588Smckusick /* 16939588Smckusick * Negative offsets allowed only for /dev/kmem 17039588Smckusick */ 17139588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 17239588Smckusick return (EINVAL); 17339588Smckusick VOP_UNLOCK(vp); 17439588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 17539588Smckusick (vp->v_rdev, uio, ioflag); 17637725Smckusick VOP_LOCK(vp); 17739588Smckusick return (error); 17839588Smckusick 17939588Smckusick case VBLK: 18039588Smckusick if (uio->uio_offset < 0) 18139588Smckusick return (EINVAL); 18239614Smckusick bsize = BLKDEV_IOSIZE; 18339614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 18439614Smckusick (caddr_t)&dpart, FREAD) == 0) { 18539614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 18639614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 18739614Smckusick bsize = dpart.part->p_frag * 18839614Smckusick dpart.part->p_fsize; 18939614Smckusick } 19039614Smckusick bscale = bsize / DEV_BSIZE; 19139614Smckusick do { 19239614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 19339614Smckusick on = uio->uio_offset % bsize; 19439614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 19539614Smckusick if (vp->v_lastr + bscale == bn) 19639614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 19739614Smckusick (int)bsize, NOCRED, &bp); 19839614Smckusick else 19939614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 20039614Smckusick vp->v_lastr = bn; 20139614Smckusick n = MIN(n, bsize - bp->b_resid); 20239614Smckusick if (error) { 20339614Smckusick brelse(bp); 20439614Smckusick return (error); 20539614Smckusick } 20639614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 20739614Smckusick if (n + on == bsize) 20839614Smckusick bp->b_flags |= B_AGE; 20939614Smckusick brelse(bp); 21039614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 21139614Smckusick return (error); 21239588Smckusick 21339588Smckusick default: 21439588Smckusick panic("spec_read type"); 21539588Smckusick } 21639588Smckusick /* NOTREACHED */ 21737486Smckusick } 21837486Smckusick 21937486Smckusick /* 22037486Smckusick * Vnode op for write 22137486Smckusick */ 22239588Smckusick spec_write(vp, uio, ioflag, cred) 22337486Smckusick register struct vnode *vp; 22439614Smckusick register struct uio *uio; 22537486Smckusick int ioflag; 22637486Smckusick struct ucred *cred; 22737486Smckusick { 22839614Smckusick struct buf *bp; 22939614Smckusick daddr_t bn; 23039614Smckusick int bsize, blkmask; 23139614Smckusick struct partinfo dpart; 23239614Smckusick register int n, on, i; 23339614Smckusick int count, error = 0; 23439588Smckusick extern int mem_no; 23537486Smckusick 23639588Smckusick if (uio->uio_rw != UIO_WRITE) 23739588Smckusick panic("spec_write mode"); 23839588Smckusick 23939588Smckusick switch (vp->v_type) { 24039588Smckusick 24139588Smckusick case VCHR: 24239588Smckusick /* 24339588Smckusick * Negative offsets allowed only for /dev/kmem 24439588Smckusick */ 24539588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 24639588Smckusick return (EINVAL); 24739588Smckusick VOP_UNLOCK(vp); 24839588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 24939588Smckusick (vp->v_rdev, uio, ioflag); 25037725Smckusick VOP_LOCK(vp); 25139588Smckusick return (error); 25239588Smckusick 25339588Smckusick case VBLK: 25439588Smckusick if (uio->uio_resid == 0) 25539588Smckusick return (0); 25639588Smckusick if (uio->uio_offset < 0) 25739588Smckusick return (EINVAL); 25839614Smckusick bsize = BLKDEV_IOSIZE; 25939614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 26039614Smckusick (caddr_t)&dpart, FREAD) == 0) { 26139614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 26239614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 26339614Smckusick bsize = dpart.part->p_frag * 26439614Smckusick dpart.part->p_fsize; 26539614Smckusick } 26639614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 26739614Smckusick do { 26839614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 26939614Smckusick on = uio->uio_offset % bsize; 27039614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 27139614Smckusick count = howmany(bsize, CLBYTES); 27239614Smckusick for (i = 0; i < count; i++) 27339614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 27439614Smckusick if (n == bsize) 27539614Smckusick bp = getblk(vp, bn, bsize); 27639614Smckusick else 27739614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 27839614Smckusick n = MIN(n, bsize - bp->b_resid); 27939614Smckusick if (error) { 28039614Smckusick brelse(bp); 28139614Smckusick return (error); 28239614Smckusick } 28339614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 28439614Smckusick if (n + on == bsize) { 28539614Smckusick bp->b_flags |= B_AGE; 28639614Smckusick bawrite(bp); 28739614Smckusick } else 28839614Smckusick bdwrite(bp); 28939614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 29039614Smckusick return (error); 29139588Smckusick 29239588Smckusick default: 29339588Smckusick panic("spec_write type"); 29439588Smckusick } 29539588Smckusick /* NOTREACHED */ 29637486Smckusick } 29737486Smckusick 29837486Smckusick /* 29937486Smckusick * Device ioctl operation. 30037486Smckusick */ 30137725Smckusick /* ARGSUSED */ 30239446Smckusick spec_ioctl(vp, com, data, fflag, cred) 30337486Smckusick struct vnode *vp; 30439666Smckusick int com; 30537486Smckusick caddr_t data; 30637486Smckusick int fflag; 30737486Smckusick struct ucred *cred; 30837486Smckusick { 30937725Smckusick dev_t dev = vp->v_rdev; 31037486Smckusick 31137486Smckusick switch (vp->v_type) { 31237486Smckusick 31337486Smckusick case VCHR: 31437486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31537486Smckusick 31637486Smckusick case VBLK: 31739666Smckusick if (com == 0 && (int)data == B_TAPE) 31839666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 31939666Smckusick return (0); 32039666Smckusick else 32139666Smckusick return (1); 32237486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 32337486Smckusick 32437486Smckusick default: 32539446Smckusick panic("spec_ioctl"); 32637486Smckusick /* NOTREACHED */ 32737486Smckusick } 32837486Smckusick } 32937486Smckusick 33037725Smckusick /* ARGSUSED */ 33140189Smckusick spec_select(vp, which, fflags, cred) 33237486Smckusick struct vnode *vp; 33340189Smckusick int which, fflags; 33437486Smckusick struct ucred *cred; 33537486Smckusick { 33637486Smckusick register dev_t dev; 33737486Smckusick 33837486Smckusick switch (vp->v_type) { 33937486Smckusick 34037486Smckusick default: 34137486Smckusick return (1); /* XXX */ 34237486Smckusick 34337486Smckusick case VCHR: 34437725Smckusick dev = vp->v_rdev; 34537486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 34637486Smckusick } 34737486Smckusick } 34837486Smckusick 34937486Smckusick /* 35037486Smckusick * Just call the device strategy routine 35137486Smckusick */ 35239446Smckusick spec_strategy(bp) 35337486Smckusick register struct buf *bp; 35437486Smckusick { 35539666Smckusick 35637486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 35737486Smckusick return (0); 35837486Smckusick } 35937486Smckusick 36039432Smckusick /* 36139666Smckusick * This is a noop, simply returning what one has been given. 36239666Smckusick */ 36339666Smckusick spec_bmap(vp, bn, vpp, bnp) 36439666Smckusick struct vnode *vp; 36539666Smckusick daddr_t bn; 36639666Smckusick struct vnode **vpp; 36739666Smckusick daddr_t *bnp; 36839666Smckusick { 36939666Smckusick 37039666Smckusick if (vpp != NULL) 37139666Smckusick *vpp = vp; 37239666Smckusick if (bnp != NULL) 37339666Smckusick *bnp = bn; 37439666Smckusick return (0); 37539666Smckusick } 37639666Smckusick 37739666Smckusick /* 37839432Smckusick * At the moment we do not do any locking. 37939432Smckusick */ 38039489Smckusick /* ARGSUSED */ 38139446Smckusick spec_lock(vp) 38237486Smckusick struct vnode *vp; 38337486Smckusick { 38437486Smckusick 38537486Smckusick return (0); 38637486Smckusick } 38737486Smckusick 38839489Smckusick /* ARGSUSED */ 38939446Smckusick spec_unlock(vp) 39037486Smckusick struct vnode *vp; 39137486Smckusick { 39237486Smckusick 39337486Smckusick return (0); 39437486Smckusick } 39537486Smckusick 39637486Smckusick /* 39737486Smckusick * Device close routine 39837486Smckusick */ 39937725Smckusick /* ARGSUSED */ 40039446Smckusick spec_close(vp, flag, cred) 40137725Smckusick register struct vnode *vp; 40237486Smckusick int flag; 40337486Smckusick struct ucred *cred; 40437486Smckusick { 40537486Smckusick dev_t dev = vp->v_rdev; 40637725Smckusick int (*cfunc)(); 40740707Skarels int mode; 40837486Smckusick 40937725Smckusick switch (vp->v_type) { 41037725Smckusick 41137725Smckusick case VCHR: 41239485Smckusick /* 41339485Smckusick * If the vnode is locked, then we are in the midst 41439485Smckusick * of forcably closing the device, otherwise we only 41539485Smckusick * close on last reference. 41639485Smckusick */ 41739630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 41837725Smckusick return (0); 41937725Smckusick cfunc = cdevsw[major(dev)].d_close; 42039432Smckusick mode = S_IFCHR; 42137725Smckusick break; 42237725Smckusick 42337725Smckusick case VBLK: 42437725Smckusick /* 42537725Smckusick * On last close of a block device (that isn't mounted) 42637725Smckusick * we must invalidate any in core blocks, so that 42737725Smckusick * we can, for instance, change floppy disks. 42837725Smckusick */ 42939666Smckusick vflushbuf(vp, 0); 43039666Smckusick if (vinvalbuf(vp, 1)) 43138613Smckusick return (0); 43237725Smckusick /* 43339485Smckusick * We do not want to really close the device if it 43439485Smckusick * is still in use unless we are trying to close it 43539485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 43639630Smckusick * holds a reference to the vnode, and because we mark 43739630Smckusick * any other vnodes that alias this device, when the 43839630Smckusick * sum of the reference counts on all the aliased 43939630Smckusick * vnodes descends to one, we are on last close. 44037725Smckusick */ 44139630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 44237725Smckusick return (0); 44337725Smckusick cfunc = bdevsw[major(dev)].d_close; 44439432Smckusick mode = S_IFBLK; 44537725Smckusick break; 44637725Smckusick 44737725Smckusick default: 44839446Smckusick panic("spec_close: not special"); 44937725Smckusick } 45037725Smckusick 45140707Skarels return ((*cfunc)(dev, flag, mode)); 45237486Smckusick } 45337486Smckusick 45437486Smckusick /* 45539666Smckusick * Print out the contents of a special device vnode. 45639666Smckusick */ 45739666Smckusick spec_print(vp) 45839666Smckusick struct vnode *vp; 45939666Smckusick { 46039666Smckusick 46139666Smckusick printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev), 46239666Smckusick minor(vp->v_rdev)); 46339666Smckusick } 46439666Smckusick 46539666Smckusick /* 46639507Smckusick * Special device failed operation 46737486Smckusick */ 46839507Smckusick spec_ebadf() 46939507Smckusick { 47039507Smckusick 47139507Smckusick return (EBADF); 47239507Smckusick } 47339507Smckusick 47439507Smckusick /* 47539507Smckusick * Special device bad operation 47639507Smckusick */ 47739446Smckusick spec_badop() 47837486Smckusick { 47937486Smckusick 48039446Smckusick panic("spec_badop called"); 48139292Smckusick /* NOTREACHED */ 48237486Smckusick } 48337486Smckusick 48437486Smckusick /* 48539507Smckusick * Special device null operation 48637486Smckusick */ 48739446Smckusick spec_nullop() 48837486Smckusick { 48937486Smckusick 49037486Smckusick return (0); 49137486Smckusick } 492