137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*47732Skarels * @(#)spec_vnops.c 7.33 (Berkeley) 04/02/91 837486Smckusick */ 937486Smckusick 1037486Smckusick #include "param.h" 1147649Skarels #include "proc.h" 1237486Smckusick #include "systm.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(), 4646196Smckusick spec_advlock(), 4739507Smckusick spec_ebadf(), 4847540Skarels spec_badop(); 4937486Smckusick 5047540Skarels int nullop(); 5147540Skarels 5239446Smckusick struct vnodeops spec_vnodeops = { 5339507Smckusick spec_lookup, /* lookup */ 5439507Smckusick spec_badop, /* create */ 5539507Smckusick spec_badop, /* mknod */ 5639507Smckusick spec_open, /* open */ 5739507Smckusick spec_close, /* close */ 5839507Smckusick spec_ebadf, /* access */ 5939507Smckusick spec_ebadf, /* getattr */ 6039507Smckusick spec_ebadf, /* setattr */ 6139507Smckusick spec_read, /* read */ 6239507Smckusick spec_write, /* write */ 6339507Smckusick spec_ioctl, /* ioctl */ 6439507Smckusick spec_select, /* select */ 6539507Smckusick spec_badop, /* mmap */ 6647540Skarels nullop, /* fsync */ 6739507Smckusick spec_badop, /* seek */ 6839507Smckusick spec_badop, /* remove */ 6939507Smckusick spec_badop, /* link */ 7039507Smckusick spec_badop, /* rename */ 7139507Smckusick spec_badop, /* mkdir */ 7239507Smckusick spec_badop, /* rmdir */ 7339507Smckusick spec_badop, /* symlink */ 7439507Smckusick spec_badop, /* readdir */ 7539507Smckusick spec_badop, /* readlink */ 7639507Smckusick spec_badop, /* abortop */ 7747540Skarels nullop, /* inactive */ 7847540Skarels nullop, /* reclaim */ 7939507Smckusick spec_lock, /* lock */ 8039507Smckusick spec_unlock, /* unlock */ 8139666Smckusick spec_bmap, /* bmap */ 8239507Smckusick spec_strategy, /* strategy */ 8339666Smckusick spec_print, /* print */ 8447540Skarels nullop, /* islocked */ 8546196Smckusick spec_advlock, /* advlock */ 8637486Smckusick }; 8737486Smckusick 8837486Smckusick /* 8939292Smckusick * Trivial lookup routine that always fails. 9039292Smckusick */ 9139446Smckusick spec_lookup(vp, ndp) 9239292Smckusick struct vnode *vp; 9339292Smckusick struct nameidata *ndp; 9439292Smckusick { 9539292Smckusick 9639292Smckusick ndp->ni_dvp = vp; 9739292Smckusick ndp->ni_vp = NULL; 9839292Smckusick return (ENOTDIR); 9939292Smckusick } 10039292Smckusick 10139292Smckusick /* 10237486Smckusick * Open called to allow handler 10337486Smckusick * of special files to initialize and 10437486Smckusick * validate before actual IO. 10537486Smckusick */ 10637725Smckusick /* ARGSUSED */ 10739446Smckusick spec_open(vp, mode, cred) 10837486Smckusick register struct vnode *vp; 10937486Smckusick int mode; 11037486Smckusick struct ucred *cred; 11137486Smckusick { 11247540Skarels struct proc *p = curproc; /* XXX */ 11337486Smckusick dev_t dev = (dev_t)vp->v_rdev; 11437486Smckusick register int maj = major(dev); 11540375Smckusick int error; 11637486Smckusick 11741400Smckusick if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 11839365Smckusick return (ENXIO); 11939365Smckusick 12037486Smckusick switch (vp->v_type) { 12137486Smckusick 12237486Smckusick case VCHR: 12337486Smckusick if ((u_int)maj >= nchrdev) 12437486Smckusick return (ENXIO); 12547540Skarels return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p)); 12637486Smckusick 12737486Smckusick case VBLK: 12837486Smckusick if ((u_int)maj >= nblkdev) 12937486Smckusick return (ENXIO); 13040375Smckusick if (error = mountedon(vp)) 13140375Smckusick return (error); 13247540Skarels return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p)); 13337486Smckusick } 13437486Smckusick return (0); 13537486Smckusick } 13637486Smckusick 13737486Smckusick /* 13837486Smckusick * Vnode op for read 13937486Smckusick */ 14041961Smckusick /* ARGSUSED */ 14139588Smckusick spec_read(vp, uio, ioflag, cred) 14237486Smckusick register struct vnode *vp; 14339614Smckusick register struct uio *uio; 14437486Smckusick int ioflag; 14537486Smckusick struct ucred *cred; 14637486Smckusick { 14747540Skarels struct proc *p = curproc; /* XXX */ 14839614Smckusick struct buf *bp; 14939614Smckusick daddr_t bn; 15039614Smckusick long bsize, bscale; 15139614Smckusick struct partinfo dpart; 15239614Smckusick register int n, on; 15339614Smckusick int error = 0; 15439588Smckusick extern int mem_no; 15537486Smckusick 15639588Smckusick if (uio->uio_rw != UIO_READ) 15739588Smckusick panic("spec_read mode"); 15839588Smckusick if (uio->uio_resid == 0) 15939588Smckusick return (0); 16039588Smckusick 16139588Smckusick switch (vp->v_type) { 16239588Smckusick 16339588Smckusick case VCHR: 16439588Smckusick /* 16539588Smckusick * Negative offsets allowed only for /dev/kmem 16639588Smckusick */ 16739588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 16839588Smckusick return (EINVAL); 16939588Smckusick VOP_UNLOCK(vp); 17039588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 17147540Skarels (vp->v_rdev, uio, ioflag, p); 17237725Smckusick VOP_LOCK(vp); 17339588Smckusick return (error); 17439588Smckusick 17539588Smckusick case VBLK: 17639588Smckusick if (uio->uio_offset < 0) 17739588Smckusick return (EINVAL); 17839614Smckusick bsize = BLKDEV_IOSIZE; 17939614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 18047540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 18139614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 18239614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 18339614Smckusick bsize = dpart.part->p_frag * 18439614Smckusick dpart.part->p_fsize; 18539614Smckusick } 18639614Smckusick bscale = bsize / DEV_BSIZE; 18739614Smckusick do { 18839614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18939614Smckusick on = uio->uio_offset % bsize; 19039614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 19139614Smckusick if (vp->v_lastr + bscale == bn) 19239614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 19339614Smckusick (int)bsize, NOCRED, &bp); 19439614Smckusick else 19539614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 19639614Smckusick vp->v_lastr = bn; 19739614Smckusick n = MIN(n, bsize - bp->b_resid); 19839614Smckusick if (error) { 19939614Smckusick brelse(bp); 20039614Smckusick return (error); 20139614Smckusick } 20239614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 20339614Smckusick if (n + on == bsize) 20439614Smckusick bp->b_flags |= B_AGE; 20539614Smckusick brelse(bp); 20639614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 20739614Smckusick return (error); 20839588Smckusick 20939588Smckusick default: 21039588Smckusick panic("spec_read type"); 21139588Smckusick } 21239588Smckusick /* NOTREACHED */ 21337486Smckusick } 21437486Smckusick 21537486Smckusick /* 21637486Smckusick * Vnode op for write 21737486Smckusick */ 21841961Smckusick /* ARGSUSED */ 21939588Smckusick spec_write(vp, uio, ioflag, cred) 22037486Smckusick register struct vnode *vp; 22139614Smckusick register struct uio *uio; 22237486Smckusick int ioflag; 22337486Smckusick struct ucred *cred; 22437486Smckusick { 22547540Skarels struct proc *p = curproc; /* XXX */ 22639614Smckusick struct buf *bp; 22739614Smckusick daddr_t bn; 22839614Smckusick int bsize, blkmask; 22939614Smckusick struct partinfo dpart; 23045731Smckusick register int n, on; 23145731Smckusick int error = 0; 23239588Smckusick extern int mem_no; 23337486Smckusick 23439588Smckusick if (uio->uio_rw != UIO_WRITE) 23539588Smckusick panic("spec_write mode"); 23639588Smckusick 23739588Smckusick switch (vp->v_type) { 23839588Smckusick 23939588Smckusick case VCHR: 24039588Smckusick /* 24139588Smckusick * Negative offsets allowed only for /dev/kmem 24239588Smckusick */ 24339588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 24439588Smckusick return (EINVAL); 24539588Smckusick VOP_UNLOCK(vp); 24639588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 24747540Skarels (vp->v_rdev, uio, ioflag, p); 24837725Smckusick VOP_LOCK(vp); 24939588Smckusick return (error); 25039588Smckusick 25139588Smckusick case VBLK: 25239588Smckusick if (uio->uio_resid == 0) 25339588Smckusick return (0); 25439588Smckusick if (uio->uio_offset < 0) 25539588Smckusick return (EINVAL); 25639614Smckusick bsize = BLKDEV_IOSIZE; 25739614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 25847540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 25939614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 26039614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 26139614Smckusick bsize = dpart.part->p_frag * 26239614Smckusick dpart.part->p_fsize; 26339614Smckusick } 26439614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 26539614Smckusick do { 26639614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 26739614Smckusick on = uio->uio_offset % bsize; 26839614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 26939614Smckusick if (n == bsize) 27039614Smckusick bp = getblk(vp, bn, bsize); 27139614Smckusick else 27239614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 27339614Smckusick n = MIN(n, bsize - bp->b_resid); 27439614Smckusick if (error) { 27539614Smckusick brelse(bp); 27639614Smckusick return (error); 27739614Smckusick } 27839614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27939614Smckusick if (n + on == bsize) { 28039614Smckusick bp->b_flags |= B_AGE; 28139614Smckusick bawrite(bp); 28239614Smckusick } else 28339614Smckusick bdwrite(bp); 28439614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 28539614Smckusick return (error); 28639588Smckusick 28739588Smckusick default: 28839588Smckusick panic("spec_write type"); 28939588Smckusick } 29039588Smckusick /* NOTREACHED */ 29137486Smckusick } 29237486Smckusick 29337486Smckusick /* 29437486Smckusick * Device ioctl operation. 29537486Smckusick */ 29637725Smckusick /* ARGSUSED */ 29739446Smckusick spec_ioctl(vp, com, data, fflag, cred) 29837486Smckusick struct vnode *vp; 29939666Smckusick int com; 30037486Smckusick caddr_t data; 30137486Smckusick int fflag; 30237486Smckusick struct ucred *cred; 30337486Smckusick { 30447540Skarels struct proc *p = curproc; /* XXX */ 30537725Smckusick dev_t dev = vp->v_rdev; 30637486Smckusick 30737486Smckusick switch (vp->v_type) { 30837486Smckusick 30937486Smckusick case VCHR: 31047540Skarels return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, 31147540Skarels fflag, p)); 31237486Smckusick 31337486Smckusick case VBLK: 31439666Smckusick if (com == 0 && (int)data == B_TAPE) 31539666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 31639666Smckusick return (0); 31739666Smckusick else 31839666Smckusick return (1); 31947540Skarels return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, 32047540Skarels fflag, p)); 32137486Smckusick 32237486Smckusick default: 32339446Smckusick panic("spec_ioctl"); 32437486Smckusick /* NOTREACHED */ 32537486Smckusick } 32637486Smckusick } 32737486Smckusick 32837725Smckusick /* ARGSUSED */ 32940189Smckusick spec_select(vp, which, fflags, cred) 33037486Smckusick struct vnode *vp; 33140189Smckusick int which, fflags; 33237486Smckusick struct ucred *cred; 33337486Smckusick { 33447540Skarels struct proc *p = curproc; /* XXX */ 33537486Smckusick register dev_t dev; 33637486Smckusick 33737486Smckusick switch (vp->v_type) { 33837486Smckusick 33937486Smckusick default: 34037486Smckusick return (1); /* XXX */ 34137486Smckusick 34237486Smckusick case VCHR: 34337725Smckusick dev = vp->v_rdev; 34447540Skarels return (*cdevsw[major(dev)].d_select)(dev, which, p); 34537486Smckusick } 34637486Smckusick } 34737486Smckusick 34837486Smckusick /* 34937486Smckusick * Just call the device strategy routine 35037486Smckusick */ 35139446Smckusick spec_strategy(bp) 35237486Smckusick register struct buf *bp; 35337486Smckusick { 35439666Smckusick 35537486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 35637486Smckusick return (0); 35737486Smckusick } 35837486Smckusick 35939432Smckusick /* 36039666Smckusick * This is a noop, simply returning what one has been given. 36139666Smckusick */ 36239666Smckusick spec_bmap(vp, bn, vpp, bnp) 36339666Smckusick struct vnode *vp; 36439666Smckusick daddr_t bn; 36539666Smckusick struct vnode **vpp; 36639666Smckusick daddr_t *bnp; 36739666Smckusick { 36839666Smckusick 36939666Smckusick if (vpp != NULL) 37039666Smckusick *vpp = vp; 37139666Smckusick if (bnp != NULL) 37239666Smckusick *bnp = bn; 37339666Smckusick return (0); 37439666Smckusick } 37539666Smckusick 37639666Smckusick /* 37739432Smckusick * At the moment we do not do any locking. 37839432Smckusick */ 37939489Smckusick /* ARGSUSED */ 38039446Smckusick spec_lock(vp) 38137486Smckusick struct vnode *vp; 38237486Smckusick { 38337486Smckusick 38437486Smckusick return (0); 38537486Smckusick } 38637486Smckusick 38739489Smckusick /* ARGSUSED */ 38839446Smckusick spec_unlock(vp) 38937486Smckusick struct vnode *vp; 39037486Smckusick { 39137486Smckusick 39237486Smckusick return (0); 39337486Smckusick } 39437486Smckusick 39537486Smckusick /* 39637486Smckusick * Device close routine 39737486Smckusick */ 39837725Smckusick /* ARGSUSED */ 39939446Smckusick spec_close(vp, flag, cred) 40037725Smckusick register struct vnode *vp; 40137486Smckusick int flag; 40237486Smckusick struct ucred *cred; 40337486Smckusick { 40447540Skarels struct proc *p = curproc; /* XXX */ 40537486Smckusick dev_t dev = vp->v_rdev; 406*47732Skarels int (*cfunc) __P((dev_t, int, int, struct proc *)); 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 45147540Skarels return ((*cfunc)(dev, flag, mode, p)); 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 /* 46646196Smckusick * Special device advisory byte-level locks. 46746196Smckusick */ 46846196Smckusick spec_advlock(vp, id, op, fl, flags) 46946196Smckusick struct vnode *vp; 47046196Smckusick caddr_t id; 47146196Smckusick int op; 47246196Smckusick struct flock *fl; 47346196Smckusick int flags; 47446196Smckusick { 47546196Smckusick 47646196Smckusick return (EOPNOTSUPP); 47746196Smckusick } 47846196Smckusick 47946196Smckusick /* 48039507Smckusick * Special device failed operation 48137486Smckusick */ 48239507Smckusick spec_ebadf() 48339507Smckusick { 48439507Smckusick 48539507Smckusick return (EBADF); 48639507Smckusick } 48739507Smckusick 48839507Smckusick /* 48939507Smckusick * Special device bad operation 49039507Smckusick */ 49139446Smckusick spec_badop() 49237486Smckusick { 49337486Smckusick 49439446Smckusick panic("spec_badop called"); 49539292Smckusick /* NOTREACHED */ 49637486Smckusick } 497