137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*52321Smckusick * @(#)spec_vnops.c 7.42 (Berkeley) 02/04/92 837486Smckusick */ 937486Smckusick 1051457Sbostic #include <sys/param.h> 1151457Sbostic #include <sys/proc.h> 1251457Sbostic #include <sys/systm.h> 1351457Sbostic #include <sys/kernel.h> 1451457Sbostic #include <sys/conf.h> 1551457Sbostic #include <sys/buf.h> 1651457Sbostic #include <sys/mount.h> 1751457Sbostic #include <sys/namei.h> 1851457Sbostic #include <sys/vnode.h> 1951457Sbostic #include <sys/specdev.h> 2051457Sbostic #include <sys/stat.h> 2151457Sbostic #include <sys/errno.h> 2251457Sbostic #include <sys/ioctl.h> 2351457Sbostic #include <sys/file.h> 2451457Sbostic #include <sys/disklabel.h> 2537486Smckusick 2640707Skarels /* symbolic sleep message strings for devices */ 2740707Skarels char devopn[] = "devopn"; 2840707Skarels char devio[] = "devio"; 2940707Skarels char devwait[] = "devwait"; 3040707Skarels char devin[] = "devin"; 3140707Skarels char devout[] = "devout"; 3240707Skarels char devioc[] = "devioc"; 3340707Skarels char devcls[] = "devcls"; 3440707Skarels 3539446Smckusick struct vnodeops spec_vnodeops = { 3639507Smckusick spec_lookup, /* lookup */ 3748015Smckusick spec_create, /* create */ 3848015Smckusick spec_mknod, /* mknod */ 3939507Smckusick spec_open, /* open */ 4039507Smckusick spec_close, /* close */ 4148015Smckusick spec_access, /* access */ 4248015Smckusick spec_getattr, /* getattr */ 4348015Smckusick spec_setattr, /* setattr */ 4439507Smckusick spec_read, /* read */ 4539507Smckusick spec_write, /* write */ 4639507Smckusick spec_ioctl, /* ioctl */ 4739507Smckusick spec_select, /* select */ 4848015Smckusick spec_mmap, /* mmap */ 4948015Smckusick spec_fsync, /* fsync */ 5048015Smckusick spec_seek, /* seek */ 5148015Smckusick spec_remove, /* remove */ 5248015Smckusick spec_link, /* link */ 5348015Smckusick spec_rename, /* rename */ 5448015Smckusick spec_mkdir, /* mkdir */ 5548015Smckusick spec_rmdir, /* rmdir */ 5648015Smckusick spec_symlink, /* symlink */ 5748015Smckusick spec_readdir, /* readdir */ 5848015Smckusick spec_readlink, /* readlink */ 5948015Smckusick spec_abortop, /* abortop */ 6048015Smckusick spec_inactive, /* inactive */ 6148015Smckusick spec_reclaim, /* reclaim */ 6239507Smckusick spec_lock, /* lock */ 6339507Smckusick spec_unlock, /* unlock */ 6439666Smckusick spec_bmap, /* bmap */ 6539507Smckusick spec_strategy, /* strategy */ 6639666Smckusick spec_print, /* print */ 6748015Smckusick spec_islocked, /* islocked */ 6846196Smckusick spec_advlock, /* advlock */ 6951567Smckusick spec_blkatoff, /* blkatoff */ 7051567Smckusick spec_vget, /* vget */ 7151567Smckusick spec_valloc, /* valloc */ 7251567Smckusick spec_vfree, /* vfree */ 7351567Smckusick spec_truncate, /* truncate */ 7451567Smckusick spec_update, /* update */ 7551567Smckusick spec_bwrite, /* bwrite */ 7637486Smckusick }; 7737486Smckusick 7837486Smckusick /* 7939292Smckusick * Trivial lookup routine that always fails. 8039292Smckusick */ 8152320Sheideman int 8252320Sheideman spec_lookup(dvp, vpp, cnp) 8352320Sheideman struct vnode *dvp; 8452320Sheideman struct vnode **vpp; 8552320Sheideman struct componentname *cnp; 8639292Smckusick { 8739292Smckusick 8852320Sheideman *vpp = NULL; 8939292Smckusick return (ENOTDIR); 9039292Smckusick } 9139292Smckusick 9239292Smckusick /* 9349273Skarels * Open a special file: Don't allow open if fs is mounted -nodev, 9449273Skarels * and don't allow opens of block devices that are currently mounted. 9549273Skarels * Otherwise, call device driver open function. 9637486Smckusick */ 9737725Smckusick /* ARGSUSED */ 9848015Smckusick spec_open(vp, mode, cred, p) 9937486Smckusick register struct vnode *vp; 10037486Smckusick int mode; 10137486Smckusick struct ucred *cred; 10248015Smckusick struct proc *p; 10337486Smckusick { 10437486Smckusick dev_t dev = (dev_t)vp->v_rdev; 10537486Smckusick register int maj = major(dev); 10640375Smckusick int error; 10737486Smckusick 10841400Smckusick if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 10939365Smckusick return (ENXIO); 11039365Smckusick 11137486Smckusick switch (vp->v_type) { 11237486Smckusick 11337486Smckusick case VCHR: 11437486Smckusick if ((u_int)maj >= nchrdev) 11537486Smckusick return (ENXIO); 11649944Smckusick VOP_UNLOCK(vp); 11749944Smckusick error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p); 11849944Smckusick VOP_LOCK(vp); 11949944Smckusick return (error); 12037486Smckusick 12137486Smckusick case VBLK: 12237486Smckusick if ((u_int)maj >= nblkdev) 12337486Smckusick return (ENXIO); 12451457Sbostic if (error = ufs_mountedon(vp)) 12540375Smckusick return (error); 12647540Skarels return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p)); 12737486Smckusick } 12837486Smckusick return (0); 12937486Smckusick } 13037486Smckusick 13137486Smckusick /* 13237486Smckusick * Vnode op for read 13337486Smckusick */ 13441961Smckusick /* ARGSUSED */ 13539588Smckusick spec_read(vp, uio, ioflag, cred) 13637486Smckusick register struct vnode *vp; 13739614Smckusick register struct uio *uio; 13837486Smckusick int ioflag; 13937486Smckusick struct ucred *cred; 14037486Smckusick { 14148015Smckusick struct proc *p = uio->uio_procp; 14239614Smckusick struct buf *bp; 143*52321Smckusick daddr_t bn, nextbn; 14439614Smckusick long bsize, bscale; 14539614Smckusick struct partinfo dpart; 14639614Smckusick register int n, on; 14739614Smckusick int error = 0; 14837486Smckusick 14948015Smckusick #ifdef DIAGNOSTIC 15039588Smckusick if (uio->uio_rw != UIO_READ) 15139588Smckusick panic("spec_read mode"); 15248015Smckusick if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 15348015Smckusick panic("spec_read proc"); 15448015Smckusick #endif 15539588Smckusick if (uio->uio_resid == 0) 15639588Smckusick return (0); 15739588Smckusick 15839588Smckusick switch (vp->v_type) { 15939588Smckusick 16039588Smckusick case VCHR: 16139588Smckusick VOP_UNLOCK(vp); 16239588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 16349121Skarels (vp->v_rdev, uio, ioflag); 16437725Smckusick VOP_LOCK(vp); 16539588Smckusick return (error); 16639588Smckusick 16739588Smckusick case VBLK: 16839588Smckusick if (uio->uio_offset < 0) 16939588Smckusick return (EINVAL); 17039614Smckusick bsize = BLKDEV_IOSIZE; 17139614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17247540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 17339614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17439614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17539614Smckusick bsize = dpart.part->p_frag * 17639614Smckusick dpart.part->p_fsize; 17739614Smckusick } 17839614Smckusick bscale = bsize / DEV_BSIZE; 17939614Smckusick do { 18039614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18139614Smckusick on = uio->uio_offset % bsize; 18239614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 183*52321Smckusick if (vp->v_lastr + bscale == bn) { 184*52321Smckusick nextbn = bn + bscale; 185*52321Smckusick error = breadn(vp, bn, (int)bsize, &nextbn, 186*52321Smckusick (int *)&bsize, 1, NOCRED, &bp); 187*52321Smckusick } else 18839614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 18939614Smckusick vp->v_lastr = bn; 19039614Smckusick n = MIN(n, bsize - bp->b_resid); 19139614Smckusick if (error) { 19239614Smckusick brelse(bp); 19339614Smckusick return (error); 19439614Smckusick } 19539614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 19639614Smckusick if (n + on == bsize) 19739614Smckusick bp->b_flags |= B_AGE; 19839614Smckusick brelse(bp); 19939614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 20039614Smckusick return (error); 20139588Smckusick 20239588Smckusick default: 20339588Smckusick panic("spec_read type"); 20439588Smckusick } 20539588Smckusick /* NOTREACHED */ 20637486Smckusick } 20737486Smckusick 20837486Smckusick /* 20937486Smckusick * Vnode op for write 21037486Smckusick */ 21141961Smckusick /* ARGSUSED */ 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 { 21848015Smckusick struct proc *p = uio->uio_procp; 21939614Smckusick struct buf *bp; 22039614Smckusick daddr_t bn; 22139614Smckusick int bsize, blkmask; 22239614Smckusick struct partinfo dpart; 22345731Smckusick register int n, on; 22445731Smckusick int error = 0; 22537486Smckusick 22648015Smckusick #ifdef DIAGNOSTIC 22739588Smckusick if (uio->uio_rw != UIO_WRITE) 22839588Smckusick panic("spec_write mode"); 22948015Smckusick if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 23048015Smckusick panic("spec_write proc"); 23148015Smckusick #endif 23239588Smckusick 23339588Smckusick switch (vp->v_type) { 23439588Smckusick 23539588Smckusick case VCHR: 23639588Smckusick VOP_UNLOCK(vp); 23739588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 23849121Skarels (vp->v_rdev, uio, ioflag); 23937725Smckusick VOP_LOCK(vp); 24039588Smckusick return (error); 24139588Smckusick 24239588Smckusick case VBLK: 24339588Smckusick if (uio->uio_resid == 0) 24439588Smckusick return (0); 24539588Smckusick if (uio->uio_offset < 0) 24639588Smckusick return (EINVAL); 24739614Smckusick bsize = BLKDEV_IOSIZE; 24839614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 24947540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 25039614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 25139614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25239614Smckusick bsize = dpart.part->p_frag * 25339614Smckusick dpart.part->p_fsize; 25439614Smckusick } 25539614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 25639614Smckusick do { 25739614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 25839614Smckusick on = uio->uio_offset % bsize; 25939614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 26039614Smckusick if (n == bsize) 26139614Smckusick bp = getblk(vp, bn, bsize); 26239614Smckusick else 26339614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 26439614Smckusick n = MIN(n, bsize - bp->b_resid); 26539614Smckusick if (error) { 26639614Smckusick brelse(bp); 26739614Smckusick return (error); 26839614Smckusick } 26939614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27039614Smckusick if (n + on == bsize) { 27139614Smckusick bp->b_flags |= B_AGE; 27239614Smckusick bawrite(bp); 27339614Smckusick } else 27439614Smckusick bdwrite(bp); 27539614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 27639614Smckusick return (error); 27739588Smckusick 27839588Smckusick default: 27939588Smckusick panic("spec_write type"); 28039588Smckusick } 28139588Smckusick /* NOTREACHED */ 28237486Smckusick } 28337486Smckusick 28437486Smckusick /* 28537486Smckusick * Device ioctl operation. 28637486Smckusick */ 28737725Smckusick /* ARGSUSED */ 28848015Smckusick spec_ioctl(vp, com, data, fflag, cred, p) 28937486Smckusick struct vnode *vp; 29039666Smckusick int com; 29137486Smckusick caddr_t data; 29237486Smckusick int fflag; 29337486Smckusick struct ucred *cred; 29448015Smckusick struct proc *p; 29537486Smckusick { 29637725Smckusick dev_t dev = vp->v_rdev; 29737486Smckusick 29837486Smckusick switch (vp->v_type) { 29937486Smckusick 30037486Smckusick case VCHR: 30147540Skarels return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, 30247540Skarels fflag, p)); 30337486Smckusick 30437486Smckusick case VBLK: 30539666Smckusick if (com == 0 && (int)data == B_TAPE) 30639666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 30739666Smckusick return (0); 30839666Smckusick else 30939666Smckusick return (1); 31047540Skarels return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, 31147540Skarels fflag, p)); 31237486Smckusick 31337486Smckusick default: 31439446Smckusick panic("spec_ioctl"); 31537486Smckusick /* NOTREACHED */ 31637486Smckusick } 31737486Smckusick } 31837486Smckusick 31937725Smckusick /* ARGSUSED */ 32048015Smckusick spec_select(vp, which, fflags, cred, p) 32137486Smckusick struct vnode *vp; 32240189Smckusick int which, fflags; 32337486Smckusick struct ucred *cred; 32448015Smckusick struct proc *p; 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; 33547540Skarels return (*cdevsw[major(dev)].d_select)(dev, which, p); 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 */ 39048015Smckusick spec_close(vp, flag, cred, p) 39137725Smckusick register struct vnode *vp; 39237486Smckusick int flag; 39337486Smckusick struct ucred *cred; 39448015Smckusick struct proc *p; 39537486Smckusick { 39637486Smckusick dev_t dev = vp->v_rdev; 39749273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 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); 41049273Skarels devclose = 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); 43449273Skarels devclose = bdevsw[major(dev)].d_close; 43539432Smckusick mode = S_IFBLK; 43637725Smckusick break; 43737725Smckusick 43837725Smckusick default: 43939446Smckusick panic("spec_close: not special"); 44037725Smckusick } 44137725Smckusick 44249273Skarels return ((*devclose)(dev, flag, mode, p)); 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 /* 45746196Smckusick * Special device advisory byte-level locks. 45846196Smckusick */ 45948015Smckusick /* ARGSUSED */ 46046196Smckusick spec_advlock(vp, id, op, fl, flags) 46146196Smckusick struct vnode *vp; 46246196Smckusick caddr_t id; 46346196Smckusick int op; 46446196Smckusick struct flock *fl; 46546196Smckusick int flags; 46646196Smckusick { 46746196Smckusick 46846196Smckusick return (EOPNOTSUPP); 46946196Smckusick } 47046196Smckusick 47146196Smckusick /* 47239507Smckusick * Special device failed operation 47337486Smckusick */ 47439507Smckusick spec_ebadf() 47539507Smckusick { 47639507Smckusick 47739507Smckusick return (EBADF); 47839507Smckusick } 47939507Smckusick 48039507Smckusick /* 48139507Smckusick * Special device bad operation 48239507Smckusick */ 48339446Smckusick spec_badop() 48437486Smckusick { 48537486Smckusick 48639446Smckusick panic("spec_badop called"); 48739292Smckusick /* NOTREACHED */ 48837486Smckusick } 489