137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*46196Smckusick * @(#)spec_vnops.c 7.30 (Berkeley) 02/01/91 837486Smckusick */ 937486Smckusick 1037486Smckusick #include "param.h" 1137486Smckusick #include "systm.h" 1237725Smckusick #include "user.h" 1337725Smckusick #include "kernel.h" 1437486Smckusick #include "conf.h" 1537486Smckusick #include "buf.h" 1639365Smckusick #include "mount.h" 1737486Smckusick #include "vnode.h" 1840652Smckusick #include "specdev.h" 1939432Smckusick #include "stat.h" 2037486Smckusick #include "errno.h" 2139614Smckusick #include "ioctl.h" 2239614Smckusick #include "file.h" 2339614Smckusick #include "disklabel.h" 2437486Smckusick 2540707Skarels /* symbolic sleep message strings for devices */ 2640707Skarels char devopn[] = "devopn"; 2740707Skarels char devio[] = "devio"; 2840707Skarels char devwait[] = "devwait"; 2940707Skarels char devin[] = "devin"; 3040707Skarels char devout[] = "devout"; 3140707Skarels char devioc[] = "devioc"; 3240707Skarels char devcls[] = "devcls"; 3340707Skarels 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(), 46*46196Smckusick spec_advlock(), 4739507Smckusick spec_ebadf(), 4839446Smckusick spec_badop(), 4939446Smckusick spec_nullop(); 5037486Smckusick 5139446Smckusick struct vnodeops spec_vnodeops = { 5239507Smckusick spec_lookup, /* lookup */ 5339507Smckusick spec_badop, /* create */ 5439507Smckusick spec_badop, /* mknod */ 5539507Smckusick spec_open, /* open */ 5639507Smckusick spec_close, /* close */ 5739507Smckusick spec_ebadf, /* access */ 5839507Smckusick spec_ebadf, /* getattr */ 5939507Smckusick spec_ebadf, /* setattr */ 6039507Smckusick spec_read, /* read */ 6139507Smckusick spec_write, /* write */ 6239507Smckusick spec_ioctl, /* ioctl */ 6339507Smckusick spec_select, /* select */ 6439507Smckusick spec_badop, /* mmap */ 6539507Smckusick spec_nullop, /* fsync */ 6639507Smckusick spec_badop, /* seek */ 6739507Smckusick spec_badop, /* remove */ 6839507Smckusick spec_badop, /* link */ 6939507Smckusick spec_badop, /* rename */ 7039507Smckusick spec_badop, /* mkdir */ 7139507Smckusick spec_badop, /* rmdir */ 7239507Smckusick spec_badop, /* symlink */ 7339507Smckusick spec_badop, /* readdir */ 7439507Smckusick spec_badop, /* readlink */ 7539507Smckusick spec_badop, /* abortop */ 7639507Smckusick spec_nullop, /* inactive */ 7739507Smckusick spec_nullop, /* reclaim */ 7839507Smckusick spec_lock, /* lock */ 7939507Smckusick spec_unlock, /* unlock */ 8039666Smckusick spec_bmap, /* bmap */ 8139507Smckusick spec_strategy, /* strategy */ 8239666Smckusick spec_print, /* print */ 8339912Smckusick spec_nullop, /* islocked */ 84*46196Smckusick spec_advlock, /* advlock */ 8537486Smckusick }; 8637486Smckusick 8737486Smckusick /* 8839292Smckusick * Trivial lookup routine that always fails. 8939292Smckusick */ 9039446Smckusick spec_lookup(vp, ndp) 9139292Smckusick struct vnode *vp; 9239292Smckusick struct nameidata *ndp; 9339292Smckusick { 9439292Smckusick 9539292Smckusick ndp->ni_dvp = vp; 9639292Smckusick ndp->ni_vp = NULL; 9739292Smckusick return (ENOTDIR); 9839292Smckusick } 9939292Smckusick 10039292Smckusick /* 10137486Smckusick * Open called to allow handler 10237486Smckusick * of special files to initialize and 10337486Smckusick * validate before actual IO. 10437486Smckusick */ 10537725Smckusick /* ARGSUSED */ 10639446Smckusick spec_open(vp, mode, cred) 10737486Smckusick register struct vnode *vp; 10837486Smckusick int mode; 10937486Smckusick struct ucred *cred; 11037486Smckusick { 11137486Smckusick dev_t dev = (dev_t)vp->v_rdev; 11237486Smckusick register int maj = major(dev); 11340375Smckusick int error; 11437486Smckusick 11541400Smckusick if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 11639365Smckusick return (ENXIO); 11739365Smckusick 11837486Smckusick switch (vp->v_type) { 11937486Smckusick 12037486Smckusick case VCHR: 12137486Smckusick if ((u_int)maj >= nchrdev) 12237486Smckusick return (ENXIO); 12339432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 12437486Smckusick 12537486Smckusick case VBLK: 12637486Smckusick if ((u_int)maj >= nblkdev) 12737486Smckusick return (ENXIO); 12840375Smckusick if (error = mountedon(vp)) 12940375Smckusick return (error); 13039432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 13137486Smckusick } 13237486Smckusick return (0); 13337486Smckusick } 13437486Smckusick 13537486Smckusick /* 13637486Smckusick * Vnode op for read 13737486Smckusick */ 13841961Smckusick /* ARGSUSED */ 13939588Smckusick spec_read(vp, uio, ioflag, cred) 14037486Smckusick register struct vnode *vp; 14139614Smckusick register struct uio *uio; 14237486Smckusick int ioflag; 14337486Smckusick struct ucred *cred; 14437486Smckusick { 14539614Smckusick struct buf *bp; 14639614Smckusick daddr_t bn; 14739614Smckusick long bsize, bscale; 14839614Smckusick struct partinfo dpart; 14939614Smckusick register int n, on; 15039614Smckusick int error = 0; 15139588Smckusick extern int mem_no; 15237486Smckusick 15339588Smckusick if (uio->uio_rw != UIO_READ) 15439588Smckusick panic("spec_read mode"); 15539588Smckusick if (uio->uio_resid == 0) 15639588Smckusick return (0); 15739588Smckusick 15839588Smckusick switch (vp->v_type) { 15939588Smckusick 16039588Smckusick case VCHR: 16139588Smckusick /* 16239588Smckusick * Negative offsets allowed only for /dev/kmem 16339588Smckusick */ 16439588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 16539588Smckusick return (EINVAL); 16639588Smckusick VOP_UNLOCK(vp); 16739588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 16839588Smckusick (vp->v_rdev, uio, ioflag); 16937725Smckusick VOP_LOCK(vp); 17039588Smckusick return (error); 17139588Smckusick 17239588Smckusick case VBLK: 17339588Smckusick if (uio->uio_offset < 0) 17439588Smckusick return (EINVAL); 17539614Smckusick bsize = BLKDEV_IOSIZE; 17639614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17739614Smckusick (caddr_t)&dpart, FREAD) == 0) { 17839614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17939614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 18039614Smckusick bsize = dpart.part->p_frag * 18139614Smckusick dpart.part->p_fsize; 18239614Smckusick } 18339614Smckusick bscale = bsize / DEV_BSIZE; 18439614Smckusick do { 18539614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18639614Smckusick on = uio->uio_offset % bsize; 18739614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 18839614Smckusick if (vp->v_lastr + bscale == bn) 18939614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 19039614Smckusick (int)bsize, NOCRED, &bp); 19139614Smckusick else 19239614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 19339614Smckusick vp->v_lastr = bn; 19439614Smckusick n = MIN(n, bsize - bp->b_resid); 19539614Smckusick if (error) { 19639614Smckusick brelse(bp); 19739614Smckusick return (error); 19839614Smckusick } 19939614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 20039614Smckusick if (n + on == bsize) 20139614Smckusick bp->b_flags |= B_AGE; 20239614Smckusick brelse(bp); 20339614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 20439614Smckusick return (error); 20539588Smckusick 20639588Smckusick default: 20739588Smckusick panic("spec_read type"); 20839588Smckusick } 20939588Smckusick /* NOTREACHED */ 21037486Smckusick } 21137486Smckusick 21237486Smckusick /* 21337486Smckusick * Vnode op for write 21437486Smckusick */ 21541961Smckusick /* ARGSUSED */ 21639588Smckusick spec_write(vp, uio, ioflag, cred) 21737486Smckusick register struct vnode *vp; 21839614Smckusick register struct uio *uio; 21937486Smckusick int ioflag; 22037486Smckusick struct ucred *cred; 22137486Smckusick { 22239614Smckusick struct buf *bp; 22339614Smckusick daddr_t bn; 22439614Smckusick int bsize, blkmask; 22539614Smckusick struct partinfo dpart; 22645731Smckusick register int n, on; 22745731Smckusick int error = 0; 22839588Smckusick extern int mem_no; 22937486Smckusick 23039588Smckusick if (uio->uio_rw != UIO_WRITE) 23139588Smckusick panic("spec_write mode"); 23239588Smckusick 23339588Smckusick switch (vp->v_type) { 23439588Smckusick 23539588Smckusick case VCHR: 23639588Smckusick /* 23739588Smckusick * Negative offsets allowed only for /dev/kmem 23839588Smckusick */ 23939588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 24039588Smckusick return (EINVAL); 24139588Smckusick VOP_UNLOCK(vp); 24239588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 24339588Smckusick (vp->v_rdev, uio, ioflag); 24437725Smckusick VOP_LOCK(vp); 24539588Smckusick return (error); 24639588Smckusick 24739588Smckusick case VBLK: 24839588Smckusick if (uio->uio_resid == 0) 24939588Smckusick return (0); 25039588Smckusick if (uio->uio_offset < 0) 25139588Smckusick return (EINVAL); 25239614Smckusick bsize = BLKDEV_IOSIZE; 25339614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 25439614Smckusick (caddr_t)&dpart, FREAD) == 0) { 25539614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 25639614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25739614Smckusick bsize = dpart.part->p_frag * 25839614Smckusick dpart.part->p_fsize; 25939614Smckusick } 26039614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 26139614Smckusick do { 26239614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 26339614Smckusick on = uio->uio_offset % bsize; 26439614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 26539614Smckusick if (n == bsize) 26639614Smckusick bp = getblk(vp, bn, bsize); 26739614Smckusick else 26839614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 26939614Smckusick n = MIN(n, bsize - bp->b_resid); 27039614Smckusick if (error) { 27139614Smckusick brelse(bp); 27239614Smckusick return (error); 27339614Smckusick } 27439614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27539614Smckusick if (n + on == bsize) { 27639614Smckusick bp->b_flags |= B_AGE; 27739614Smckusick bawrite(bp); 27839614Smckusick } else 27939614Smckusick bdwrite(bp); 28039614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 28139614Smckusick return (error); 28239588Smckusick 28339588Smckusick default: 28439588Smckusick panic("spec_write type"); 28539588Smckusick } 28639588Smckusick /* NOTREACHED */ 28737486Smckusick } 28837486Smckusick 28937486Smckusick /* 29037486Smckusick * Device ioctl operation. 29137486Smckusick */ 29237725Smckusick /* ARGSUSED */ 29339446Smckusick spec_ioctl(vp, com, data, fflag, cred) 29437486Smckusick struct vnode *vp; 29539666Smckusick int com; 29637486Smckusick caddr_t data; 29737486Smckusick int fflag; 29837486Smckusick struct ucred *cred; 29937486Smckusick { 30037725Smckusick dev_t dev = vp->v_rdev; 30137486Smckusick 30237486Smckusick switch (vp->v_type) { 30337486Smckusick 30437486Smckusick case VCHR: 30537486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 30637486Smckusick 30737486Smckusick case VBLK: 30839666Smckusick if (com == 0 && (int)data == B_TAPE) 30939666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 31039666Smckusick return (0); 31139666Smckusick else 31239666Smckusick return (1); 31337486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31437486Smckusick 31537486Smckusick default: 31639446Smckusick panic("spec_ioctl"); 31737486Smckusick /* NOTREACHED */ 31837486Smckusick } 31937486Smckusick } 32037486Smckusick 32137725Smckusick /* ARGSUSED */ 32240189Smckusick spec_select(vp, which, fflags, cred) 32337486Smckusick struct vnode *vp; 32440189Smckusick int which, fflags; 32537486Smckusick struct ucred *cred; 32637486Smckusick { 32737486Smckusick register dev_t dev; 32837486Smckusick 32937486Smckusick switch (vp->v_type) { 33037486Smckusick 33137486Smckusick default: 33237486Smckusick return (1); /* XXX */ 33337486Smckusick 33437486Smckusick case VCHR: 33537725Smckusick dev = vp->v_rdev; 33637486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 33737486Smckusick } 33837486Smckusick } 33937486Smckusick 34037486Smckusick /* 34137486Smckusick * Just call the device strategy routine 34237486Smckusick */ 34339446Smckusick spec_strategy(bp) 34437486Smckusick register struct buf *bp; 34537486Smckusick { 34639666Smckusick 34737486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 34837486Smckusick return (0); 34937486Smckusick } 35037486Smckusick 35139432Smckusick /* 35239666Smckusick * This is a noop, simply returning what one has been given. 35339666Smckusick */ 35439666Smckusick spec_bmap(vp, bn, vpp, bnp) 35539666Smckusick struct vnode *vp; 35639666Smckusick daddr_t bn; 35739666Smckusick struct vnode **vpp; 35839666Smckusick daddr_t *bnp; 35939666Smckusick { 36039666Smckusick 36139666Smckusick if (vpp != NULL) 36239666Smckusick *vpp = vp; 36339666Smckusick if (bnp != NULL) 36439666Smckusick *bnp = bn; 36539666Smckusick return (0); 36639666Smckusick } 36739666Smckusick 36839666Smckusick /* 36939432Smckusick * At the moment we do not do any locking. 37039432Smckusick */ 37139489Smckusick /* ARGSUSED */ 37239446Smckusick spec_lock(vp) 37337486Smckusick struct vnode *vp; 37437486Smckusick { 37537486Smckusick 37637486Smckusick return (0); 37737486Smckusick } 37837486Smckusick 37939489Smckusick /* ARGSUSED */ 38039446Smckusick spec_unlock(vp) 38137486Smckusick struct vnode *vp; 38237486Smckusick { 38337486Smckusick 38437486Smckusick return (0); 38537486Smckusick } 38637486Smckusick 38737486Smckusick /* 38837486Smckusick * Device close routine 38937486Smckusick */ 39037725Smckusick /* ARGSUSED */ 39139446Smckusick spec_close(vp, flag, cred) 39237725Smckusick register struct vnode *vp; 39337486Smckusick int flag; 39437486Smckusick struct ucred *cred; 39537486Smckusick { 39637486Smckusick dev_t dev = vp->v_rdev; 39737725Smckusick int (*cfunc)(); 39840707Skarels int mode; 39937486Smckusick 40037725Smckusick switch (vp->v_type) { 40137725Smckusick 40237725Smckusick case VCHR: 40339485Smckusick /* 40439485Smckusick * If the vnode is locked, then we are in the midst 40539485Smckusick * of forcably closing the device, otherwise we only 40639485Smckusick * close on last reference. 40739485Smckusick */ 40839630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 40937725Smckusick return (0); 41037725Smckusick cfunc = cdevsw[major(dev)].d_close; 41139432Smckusick mode = S_IFCHR; 41237725Smckusick break; 41337725Smckusick 41437725Smckusick case VBLK: 41537725Smckusick /* 41637725Smckusick * On last close of a block device (that isn't mounted) 41737725Smckusick * we must invalidate any in core blocks, so that 41837725Smckusick * we can, for instance, change floppy disks. 41937725Smckusick */ 42039666Smckusick vflushbuf(vp, 0); 42139666Smckusick if (vinvalbuf(vp, 1)) 42238613Smckusick return (0); 42337725Smckusick /* 42439485Smckusick * We do not want to really close the device if it 42539485Smckusick * is still in use unless we are trying to close it 42639485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 42739630Smckusick * holds a reference to the vnode, and because we mark 42839630Smckusick * any other vnodes that alias this device, when the 42939630Smckusick * sum of the reference counts on all the aliased 43039630Smckusick * vnodes descends to one, we are on last close. 43137725Smckusick */ 43239630Smckusick if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 43337725Smckusick return (0); 43437725Smckusick cfunc = bdevsw[major(dev)].d_close; 43539432Smckusick mode = S_IFBLK; 43637725Smckusick break; 43737725Smckusick 43837725Smckusick default: 43939446Smckusick panic("spec_close: not special"); 44037725Smckusick } 44137725Smckusick 44240707Skarels return ((*cfunc)(dev, flag, mode)); 44337486Smckusick } 44437486Smckusick 44537486Smckusick /* 44639666Smckusick * Print out the contents of a special device vnode. 44739666Smckusick */ 44839666Smckusick spec_print(vp) 44939666Smckusick struct vnode *vp; 45039666Smckusick { 45139666Smckusick 45239666Smckusick printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev), 45339666Smckusick minor(vp->v_rdev)); 45439666Smckusick } 45539666Smckusick 45639666Smckusick /* 457*46196Smckusick * Special device advisory byte-level locks. 458*46196Smckusick */ 459*46196Smckusick spec_advlock(vp, id, op, fl, flags) 460*46196Smckusick struct vnode *vp; 461*46196Smckusick caddr_t id; 462*46196Smckusick int op; 463*46196Smckusick struct flock *fl; 464*46196Smckusick int flags; 465*46196Smckusick { 466*46196Smckusick 467*46196Smckusick return (EOPNOTSUPP); 468*46196Smckusick } 469*46196Smckusick 470*46196Smckusick /* 47139507Smckusick * Special device failed operation 47237486Smckusick */ 47339507Smckusick spec_ebadf() 47439507Smckusick { 47539507Smckusick 47639507Smckusick return (EBADF); 47739507Smckusick } 47839507Smckusick 47939507Smckusick /* 48039507Smckusick * Special device bad operation 48139507Smckusick */ 48239446Smckusick spec_badop() 48337486Smckusick { 48437486Smckusick 48539446Smckusick panic("spec_badop called"); 48639292Smckusick /* NOTREACHED */ 48737486Smckusick } 48837486Smckusick 48937486Smckusick /* 49039507Smckusick * Special device null operation 49137486Smckusick */ 49239446Smckusick spec_nullop() 49337486Smckusick { 49437486Smckusick 49537486Smckusick return (0); 49637486Smckusick } 497