137486Smckusick /* 268234Spendry * Copyright (c) 1989, 1993, 1995 363247Sbostic * The Regents of the University of California. All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*68411Smckusick * @(#)spec_vnops.c 8.12 (Berkeley) 02/22/95 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/stat.h> 2051457Sbostic #include <sys/errno.h> 2151457Sbostic #include <sys/ioctl.h> 2251457Sbostic #include <sys/file.h> 2351457Sbostic #include <sys/disklabel.h> 2455028Smckusick #include <miscfs/specfs/specdev.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 3553542Sheideman int (**spec_vnodeop_p)(); 3653542Sheideman struct vnodeopv_entry_desc spec_vnodeop_entries[] = { 3753542Sheideman { &vop_default_desc, vn_default_error }, 3853542Sheideman { &vop_lookup_desc, spec_lookup }, /* lookup */ 3953542Sheideman { &vop_create_desc, spec_create }, /* create */ 4053542Sheideman { &vop_mknod_desc, spec_mknod }, /* mknod */ 4160391Smckusick { &vop_open_desc, spec_open }, /* open */ 4253542Sheideman { &vop_close_desc, spec_close }, /* close */ 4353542Sheideman { &vop_access_desc, spec_access }, /* access */ 4453542Sheideman { &vop_getattr_desc, spec_getattr }, /* getattr */ 4553542Sheideman { &vop_setattr_desc, spec_setattr }, /* setattr */ 4660391Smckusick { &vop_read_desc, spec_read }, /* read */ 4753542Sheideman { &vop_write_desc, spec_write }, /* write */ 4867650Smckusick { &vop_lease_desc, spec_lease_check }, /* lease */ 4953542Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 5053542Sheideman { &vop_select_desc, spec_select }, /* select */ 51*68411Smckusick { &vop_revoke_desc, spec_revoke }, /* revoke */ 5260391Smckusick { &vop_mmap_desc, spec_mmap }, /* mmap */ 5353542Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 5460391Smckusick { &vop_seek_desc, spec_seek }, /* seek */ 5553542Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 5660391Smckusick { &vop_link_desc, spec_link }, /* link */ 5753542Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 5853542Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 5953542Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 6053542Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 6153542Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 6253542Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 6353542Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 6453542Sheideman { &vop_inactive_desc, spec_inactive }, /* inactive */ 6553542Sheideman { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ 6660391Smckusick { &vop_lock_desc, spec_lock }, /* lock */ 6753542Sheideman { &vop_unlock_desc, spec_unlock }, /* unlock */ 6860391Smckusick { &vop_bmap_desc, spec_bmap }, /* bmap */ 6953542Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 7053542Sheideman { &vop_print_desc, spec_print }, /* print */ 7153542Sheideman { &vop_islocked_desc, spec_islocked }, /* islocked */ 7260391Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 7353542Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 7453542Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 7553542Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 7653542Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 7753542Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 7853542Sheideman { &vop_update_desc, spec_update }, /* update */ 7953542Sheideman { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 8053542Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 8137486Smckusick }; 8253542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc = 8353542Sheideman { &spec_vnodeop_p, spec_vnodeop_entries }; 8437486Smckusick 8537486Smckusick /* 8639292Smckusick * Trivial lookup routine that always fails. 8739292Smckusick */ 8852320Sheideman int 8954439Smckusick spec_lookup(ap) 9054439Smckusick struct vop_lookup_args /* { 9154439Smckusick struct vnode *a_dvp; 9254439Smckusick struct vnode **a_vpp; 9354439Smckusick struct componentname *a_cnp; 9454439Smckusick } */ *ap; 9539292Smckusick { 9639292Smckusick 9753597Sheideman *ap->a_vpp = NULL; 9839292Smckusick return (ENOTDIR); 9939292Smckusick } 10039292Smckusick 10139292Smckusick /* 10259486Smckusick * Open a special file. 10337486Smckusick */ 10437725Smckusick /* ARGSUSED */ 10554439Smckusick spec_open(ap) 10654439Smckusick struct vop_open_args /* { 10754439Smckusick struct vnode *a_vp; 10854439Smckusick int a_mode; 10954439Smckusick struct ucred *a_cred; 11054439Smckusick struct proc *a_p; 11154439Smckusick } */ *ap; 11237486Smckusick { 11359486Smckusick struct vnode *bvp, *vp = ap->a_vp; 11459486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev; 11537486Smckusick register int maj = major(dev); 11640375Smckusick int error; 11737486Smckusick 11859486Smckusick /* 11959486Smckusick * Don't allow open if fs is mounted -nodev. 12059486Smckusick */ 12153863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12239365Smckusick return (ENXIO); 12339365Smckusick 12453863Sheideman switch (vp->v_type) { 12537486Smckusick 12637486Smckusick case VCHR: 12737486Smckusick if ((u_int)maj >= nchrdev) 12837486Smckusick return (ENXIO); 12959486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 13059486Smckusick /* 13159486Smckusick * When running in very secure mode, do not allow 13259486Smckusick * opens for writing of any disk character devices. 13359486Smckusick */ 13468129Smckusick if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) 13559486Smckusick return (EPERM); 13659486Smckusick /* 13759486Smckusick * When running in secure mode, do not allow opens 13859486Smckusick * for writing of /dev/mem, /dev/kmem, or character 13959486Smckusick * devices whose corresponding block devices are 14059486Smckusick * currently mounted. 14159486Smckusick */ 14259486Smckusick if (securelevel >= 1) { 14359486Smckusick if ((bdev = chrtoblk(dev)) != NODEV && 14459486Smckusick vfinddev(bdev, VBLK, &bvp) && 14559486Smckusick bvp->v_usecount > 0 && 14665671Shibler (error = vfs_mountedon(bvp))) 14759486Smckusick return (error); 14859486Smckusick if (iskmemdev(dev)) 14959486Smckusick return (EPERM); 15059486Smckusick } 15159486Smckusick } 15268129Smckusick if (cdevsw[maj].d_type == D_TTY) 15367951Smckusick vp->v_flag |= VISTTY; 15453863Sheideman VOP_UNLOCK(vp); 15553597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 15653863Sheideman VOP_LOCK(vp); 15749944Smckusick return (error); 15837486Smckusick 15937486Smckusick case VBLK: 16037486Smckusick if ((u_int)maj >= nblkdev) 16137486Smckusick return (ENXIO); 16259486Smckusick /* 16359486Smckusick * When running in very secure mode, do not allow 16459486Smckusick * opens for writing of any disk block devices. 16559486Smckusick */ 16659486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED && 16768129Smckusick (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) 16859486Smckusick return (EPERM); 16959486Smckusick /* 17059486Smckusick * Do not allow opens of block devices that are 17159486Smckusick * currently mounted. 17259486Smckusick */ 17365671Shibler if (error = vfs_mountedon(vp)) 17440375Smckusick return (error); 17553597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 17637486Smckusick } 17737486Smckusick return (0); 17837486Smckusick } 17937486Smckusick 18037486Smckusick /* 18137486Smckusick * Vnode op for read 18237486Smckusick */ 18341961Smckusick /* ARGSUSED */ 18454439Smckusick spec_read(ap) 18554439Smckusick struct vop_read_args /* { 18654439Smckusick struct vnode *a_vp; 18754439Smckusick struct uio *a_uio; 18854439Smckusick int a_ioflag; 18954439Smckusick struct ucred *a_cred; 19054439Smckusick } */ *ap; 19137486Smckusick { 19253863Sheideman register struct vnode *vp = ap->a_vp; 19353863Sheideman register struct uio *uio = ap->a_uio; 19453863Sheideman struct proc *p = uio->uio_procp; 19539614Smckusick struct buf *bp; 19652321Smckusick daddr_t bn, nextbn; 19739614Smckusick long bsize, bscale; 19839614Smckusick struct partinfo dpart; 19965532Smckusick int n, on, majordev, (*ioctl)(); 20039614Smckusick int error = 0; 20165532Smckusick dev_t dev; 20237486Smckusick 20348015Smckusick #ifdef DIAGNOSTIC 20453863Sheideman if (uio->uio_rw != UIO_READ) 20539588Smckusick panic("spec_read mode"); 20653863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20748015Smckusick panic("spec_read proc"); 20848015Smckusick #endif 20953863Sheideman if (uio->uio_resid == 0) 21039588Smckusick return (0); 21139588Smckusick 21253863Sheideman switch (vp->v_type) { 21339588Smckusick 21439588Smckusick case VCHR: 21553863Sheideman VOP_UNLOCK(vp); 21653863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21753863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 21853863Sheideman VOP_LOCK(vp); 21939588Smckusick return (error); 22039588Smckusick 22139588Smckusick case VBLK: 22253863Sheideman if (uio->uio_offset < 0) 22339588Smckusick return (EINVAL); 22439614Smckusick bsize = BLKDEV_IOSIZE; 22565532Smckusick dev = vp->v_rdev; 22665532Smckusick if ((majordev = major(dev)) < nblkdev && 22765532Smckusick (ioctl = bdevsw[majordev].d_ioctl) != NULL && 22865532Smckusick (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && 22965532Smckusick dpart.part->p_fstype == FS_BSDFFS && 23065532Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 23165532Smckusick bsize = dpart.part->p_frag * dpart.part->p_fsize; 23239614Smckusick bscale = bsize / DEV_BSIZE; 23339614Smckusick do { 23453863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 23553863Sheideman on = uio->uio_offset % bsize; 23655059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23753863Sheideman if (vp->v_lastr + bscale == bn) { 23852321Smckusick nextbn = bn + bscale; 23953863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 24052321Smckusick (int *)&bsize, 1, NOCRED, &bp); 24152321Smckusick } else 24253863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 24353863Sheideman vp->v_lastr = bn; 24455059Spendry n = min(n, bsize - bp->b_resid); 24539614Smckusick if (error) { 24639614Smckusick brelse(bp); 24739614Smckusick return (error); 24839614Smckusick } 24964551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 25039614Smckusick if (n + on == bsize) 25139614Smckusick bp->b_flags |= B_AGE; 25239614Smckusick brelse(bp); 25353863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 25439614Smckusick return (error); 25539588Smckusick 25639588Smckusick default: 25739588Smckusick panic("spec_read type"); 25839588Smckusick } 25939588Smckusick /* NOTREACHED */ 26037486Smckusick } 26137486Smckusick 26237486Smckusick /* 26337486Smckusick * Vnode op for write 26437486Smckusick */ 26541961Smckusick /* ARGSUSED */ 26654439Smckusick spec_write(ap) 26754439Smckusick struct vop_write_args /* { 26854439Smckusick struct vnode *a_vp; 26954439Smckusick struct uio *a_uio; 27054439Smckusick int a_ioflag; 27154439Smckusick struct ucred *a_cred; 27254439Smckusick } */ *ap; 27337486Smckusick { 27453863Sheideman register struct vnode *vp = ap->a_vp; 27553863Sheideman register struct uio *uio = ap->a_uio; 27653863Sheideman struct proc *p = uio->uio_procp; 27739614Smckusick struct buf *bp; 27839614Smckusick daddr_t bn; 27939614Smckusick int bsize, blkmask; 28039614Smckusick struct partinfo dpart; 28145731Smckusick register int n, on; 28245731Smckusick int error = 0; 28337486Smckusick 28448015Smckusick #ifdef DIAGNOSTIC 28553863Sheideman if (uio->uio_rw != UIO_WRITE) 28639588Smckusick panic("spec_write mode"); 28753863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28848015Smckusick panic("spec_write proc"); 28948015Smckusick #endif 29039588Smckusick 29153863Sheideman switch (vp->v_type) { 29239588Smckusick 29339588Smckusick case VCHR: 29453863Sheideman VOP_UNLOCK(vp); 29553863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29653863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 29753863Sheideman VOP_LOCK(vp); 29839588Smckusick return (error); 29939588Smckusick 30039588Smckusick case VBLK: 30153863Sheideman if (uio->uio_resid == 0) 30239588Smckusick return (0); 30353863Sheideman if (uio->uio_offset < 0) 30439588Smckusick return (EINVAL); 30539614Smckusick bsize = BLKDEV_IOSIZE; 30653863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30747540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30839614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 30939614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 31039614Smckusick bsize = dpart.part->p_frag * 31139614Smckusick dpart.part->p_fsize; 31239614Smckusick } 31339614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 31439614Smckusick do { 31553863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31653863Sheideman on = uio->uio_offset % bsize; 31755059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31839614Smckusick if (n == bsize) 31957798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 32039614Smckusick else 32153863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 32255059Spendry n = min(n, bsize - bp->b_resid); 32339614Smckusick if (error) { 32439614Smckusick brelse(bp); 32539614Smckusick return (error); 32639614Smckusick } 32764551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 32839614Smckusick if (n + on == bsize) { 32939614Smckusick bp->b_flags |= B_AGE; 33039614Smckusick bawrite(bp); 33139614Smckusick } else 33239614Smckusick bdwrite(bp); 33353863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 33439614Smckusick return (error); 33539588Smckusick 33639588Smckusick default: 33739588Smckusick panic("spec_write type"); 33839588Smckusick } 33939588Smckusick /* NOTREACHED */ 34037486Smckusick } 34137486Smckusick 34237486Smckusick /* 34337486Smckusick * Device ioctl operation. 34437486Smckusick */ 34537725Smckusick /* ARGSUSED */ 34654439Smckusick spec_ioctl(ap) 34754439Smckusick struct vop_ioctl_args /* { 34854439Smckusick struct vnode *a_vp; 34954439Smckusick int a_command; 35054439Smckusick caddr_t a_data; 35154439Smckusick int a_fflag; 35254439Smckusick struct ucred *a_cred; 35354439Smckusick struct proc *a_p; 35454439Smckusick } */ *ap; 35537486Smckusick { 35653597Sheideman dev_t dev = ap->a_vp->v_rdev; 35737486Smckusick 35853597Sheideman switch (ap->a_vp->v_type) { 35937486Smckusick 36037486Smckusick case VCHR: 36153597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36253597Sheideman ap->a_fflag, ap->a_p)); 36337486Smckusick 36437486Smckusick case VBLK: 36553597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36668129Smckusick if (bdevsw[major(dev)].d_type == D_TAPE) 36739666Smckusick return (0); 36839666Smckusick else 36939666Smckusick return (1); 37053597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 37153597Sheideman ap->a_fflag, ap->a_p)); 37237486Smckusick 37337486Smckusick default: 37439446Smckusick panic("spec_ioctl"); 37537486Smckusick /* NOTREACHED */ 37637486Smckusick } 37737486Smckusick } 37837486Smckusick 37937725Smckusick /* ARGSUSED */ 38054439Smckusick spec_select(ap) 38154439Smckusick struct vop_select_args /* { 38254439Smckusick struct vnode *a_vp; 38354439Smckusick int a_which; 38454439Smckusick int a_fflags; 38554439Smckusick struct ucred *a_cred; 38654439Smckusick struct proc *a_p; 38754439Smckusick } */ *ap; 38837486Smckusick { 38937486Smckusick register dev_t dev; 39037486Smckusick 39153597Sheideman switch (ap->a_vp->v_type) { 39237486Smckusick 39337486Smckusick default: 39437486Smckusick return (1); /* XXX */ 39537486Smckusick 39637486Smckusick case VCHR: 39753597Sheideman dev = ap->a_vp->v_rdev; 39853597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 39937486Smckusick } 40037486Smckusick } 40154439Smckusick /* 40254439Smckusick * Synch buffers associated with a block device 40354439Smckusick */ 40454439Smckusick /* ARGSUSED */ 40554439Smckusick int 40654439Smckusick spec_fsync(ap) 40754439Smckusick struct vop_fsync_args /* { 40854439Smckusick struct vnode *a_vp; 40954439Smckusick struct ucred *a_cred; 41054439Smckusick int a_waitfor; 41154439Smckusick struct proc *a_p; 41254439Smckusick } */ *ap; 41354439Smckusick { 41454439Smckusick register struct vnode *vp = ap->a_vp; 41554439Smckusick register struct buf *bp; 41654439Smckusick struct buf *nbp; 41756548Smckusick int s; 41837486Smckusick 41954439Smckusick if (vp->v_type == VCHR) 42054439Smckusick return (0); 42154439Smckusick /* 42254439Smckusick * Flush all dirty buffers associated with a block device. 42354439Smckusick */ 42454439Smckusick loop: 42554439Smckusick s = splbio(); 42665246Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 42765246Smckusick nbp = bp->b_vnbufs.le_next; 42854439Smckusick if ((bp->b_flags & B_BUSY)) 42954439Smckusick continue; 43054439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 43154439Smckusick panic("spec_fsync: not dirty"); 43254439Smckusick bremfree(bp); 43354439Smckusick bp->b_flags |= B_BUSY; 43454439Smckusick splx(s); 43556548Smckusick bawrite(bp); 43654439Smckusick goto loop; 43754439Smckusick } 43854439Smckusick if (ap->a_waitfor == MNT_WAIT) { 43954439Smckusick while (vp->v_numoutput) { 44054439Smckusick vp->v_flag |= VBWAIT; 44154439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 44254439Smckusick } 44354439Smckusick #ifdef DIAGNOSTIC 44465246Smckusick if (vp->v_dirtyblkhd.lh_first) { 44554439Smckusick vprint("spec_fsync: dirty", vp); 44654439Smckusick goto loop; 44754439Smckusick } 44854439Smckusick #endif 44954439Smckusick } 45054439Smckusick splx(s); 45156548Smckusick return (0); 45254439Smckusick } 45354439Smckusick 45437486Smckusick /* 45537486Smckusick * Just call the device strategy routine 45637486Smckusick */ 45754439Smckusick spec_strategy(ap) 45854439Smckusick struct vop_strategy_args /* { 45954439Smckusick struct buf *a_bp; 46054439Smckusick } */ *ap; 46137486Smckusick { 46239666Smckusick 46353597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 46437486Smckusick return (0); 46537486Smckusick } 46637486Smckusick 46739432Smckusick /* 46839666Smckusick * This is a noop, simply returning what one has been given. 46939666Smckusick */ 47054439Smckusick spec_bmap(ap) 47154439Smckusick struct vop_bmap_args /* { 47254439Smckusick struct vnode *a_vp; 47354439Smckusick daddr_t a_bn; 47454439Smckusick struct vnode **a_vpp; 47554439Smckusick daddr_t *a_bnp; 47668234Spendry int *a_runp; 47754439Smckusick } */ *ap; 47839666Smckusick { 47939666Smckusick 48053597Sheideman if (ap->a_vpp != NULL) 48153597Sheideman *ap->a_vpp = ap->a_vp; 48253597Sheideman if (ap->a_bnp != NULL) 48353597Sheideman *ap->a_bnp = ap->a_bn; 48468231Spendry if (ap->a_runp != NULL) 48568231Spendry *ap->a_runp = 0; 48639666Smckusick return (0); 48739666Smckusick } 48839666Smckusick 48939666Smckusick /* 49039432Smckusick * At the moment we do not do any locking. 49139432Smckusick */ 49239489Smckusick /* ARGSUSED */ 49354439Smckusick spec_lock(ap) 49454439Smckusick struct vop_lock_args /* { 49554439Smckusick struct vnode *a_vp; 49654439Smckusick } */ *ap; 49737486Smckusick { 49837486Smckusick 49937486Smckusick return (0); 50037486Smckusick } 50137486Smckusick 50239489Smckusick /* ARGSUSED */ 50354439Smckusick spec_unlock(ap) 50454439Smckusick struct vop_unlock_args /* { 50554439Smckusick struct vnode *a_vp; 50654439Smckusick } */ *ap; 50737486Smckusick { 50837486Smckusick 50937486Smckusick return (0); 51037486Smckusick } 51137486Smckusick 51237486Smckusick /* 51337486Smckusick * Device close routine 51437486Smckusick */ 51537725Smckusick /* ARGSUSED */ 51654439Smckusick spec_close(ap) 51754439Smckusick struct vop_close_args /* { 51854439Smckusick struct vnode *a_vp; 51954439Smckusick int a_fflag; 52054439Smckusick struct ucred *a_cred; 52154439Smckusick struct proc *a_p; 52254439Smckusick } */ *ap; 52337486Smckusick { 52453863Sheideman register struct vnode *vp = ap->a_vp; 52553863Sheideman dev_t dev = vp->v_rdev; 52649273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 52754439Smckusick int mode, error; 52837486Smckusick 52953863Sheideman switch (vp->v_type) { 53037725Smckusick 53137725Smckusick case VCHR: 53239485Smckusick /* 53360498Smckusick * Hack: a tty device that is a controlling terminal 53460498Smckusick * has a reference from the session structure. 53560498Smckusick * We cannot easily tell that a character device is 53660498Smckusick * a controlling terminal, unless it is the closing 53760498Smckusick * process' controlling terminal. In that case, 53860498Smckusick * if the reference count is 2 (this last descriptor 53960498Smckusick * plus the session), release the reference from the session. 54060498Smckusick */ 54160527Smckusick if (vcount(vp) == 2 && ap->a_p && 54260527Smckusick vp == ap->a_p->p_session->s_ttyvp) { 54360498Smckusick vrele(vp); 54460498Smckusick ap->a_p->p_session->s_ttyvp = NULL; 54560498Smckusick } 54660498Smckusick /* 54739485Smckusick * If the vnode is locked, then we are in the midst 54839485Smckusick * of forcably closing the device, otherwise we only 54939485Smckusick * close on last reference. 55039485Smckusick */ 55153863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 55237725Smckusick return (0); 55349273Skarels devclose = cdevsw[major(dev)].d_close; 55439432Smckusick mode = S_IFCHR; 55537725Smckusick break; 55637725Smckusick 55737725Smckusick case VBLK: 55837725Smckusick /* 55937725Smckusick * On last close of a block device (that isn't mounted) 56037725Smckusick * we must invalidate any in core blocks, so that 56137725Smckusick * we can, for instance, change floppy disks. 56237725Smckusick */ 56366739Spendry if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0)) 56454439Smckusick return (error); 56537725Smckusick /* 56639485Smckusick * We do not want to really close the device if it 56739485Smckusick * is still in use unless we are trying to close it 56839485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 56939630Smckusick * holds a reference to the vnode, and because we mark 57039630Smckusick * any other vnodes that alias this device, when the 57139630Smckusick * sum of the reference counts on all the aliased 57239630Smckusick * vnodes descends to one, we are on last close. 57337725Smckusick */ 57453863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 57537725Smckusick return (0); 57649273Skarels devclose = bdevsw[major(dev)].d_close; 57739432Smckusick mode = S_IFBLK; 57837725Smckusick break; 57937725Smckusick 58037725Smckusick default: 58139446Smckusick panic("spec_close: not special"); 58237725Smckusick } 58337725Smckusick 58453597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 58537486Smckusick } 58637486Smckusick 58737486Smckusick /* 58839666Smckusick * Print out the contents of a special device vnode. 58939666Smckusick */ 59054439Smckusick spec_print(ap) 59154439Smckusick struct vop_print_args /* { 59254439Smckusick struct vnode *a_vp; 59354439Smckusick } */ *ap; 59439666Smckusick { 59539666Smckusick 59653597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 59753597Sheideman minor(ap->a_vp->v_rdev)); 59839666Smckusick } 59939666Smckusick 60039666Smckusick /* 60160391Smckusick * Return POSIX pathconf information applicable to special devices. 60260391Smckusick */ 60360391Smckusick spec_pathconf(ap) 60460391Smckusick struct vop_pathconf_args /* { 60560391Smckusick struct vnode *a_vp; 60660391Smckusick int a_name; 60760391Smckusick int *a_retval; 60860391Smckusick } */ *ap; 60960391Smckusick { 61060391Smckusick 61160391Smckusick switch (ap->a_name) { 61260391Smckusick case _PC_LINK_MAX: 61360391Smckusick *ap->a_retval = LINK_MAX; 61460391Smckusick return (0); 61560391Smckusick case _PC_MAX_CANON: 61660391Smckusick *ap->a_retval = MAX_CANON; 61760391Smckusick return (0); 61860391Smckusick case _PC_MAX_INPUT: 61960391Smckusick *ap->a_retval = MAX_INPUT; 62060391Smckusick return (0); 62160391Smckusick case _PC_PIPE_BUF: 62260391Smckusick *ap->a_retval = PIPE_BUF; 62360391Smckusick return (0); 62460391Smckusick case _PC_CHOWN_RESTRICTED: 62560391Smckusick *ap->a_retval = 1; 62660391Smckusick return (0); 62760391Smckusick case _PC_VDISABLE: 62860391Smckusick *ap->a_retval = _POSIX_VDISABLE; 62960391Smckusick return (0); 63060391Smckusick default: 63160391Smckusick return (EINVAL); 63260391Smckusick } 63360391Smckusick /* NOTREACHED */ 63460391Smckusick } 63560391Smckusick 63660391Smckusick /* 63746196Smckusick * Special device advisory byte-level locks. 63846196Smckusick */ 63948015Smckusick /* ARGSUSED */ 64054439Smckusick spec_advlock(ap) 64154439Smckusick struct vop_advlock_args /* { 64254439Smckusick struct vnode *a_vp; 64354439Smckusick caddr_t a_id; 64454439Smckusick int a_op; 64554439Smckusick struct flock *a_fl; 64654439Smckusick int a_flags; 64754439Smckusick } */ *ap; 64846196Smckusick { 64946196Smckusick 65046196Smckusick return (EOPNOTSUPP); 65146196Smckusick } 65246196Smckusick 65346196Smckusick /* 65439507Smckusick * Special device failed operation 65537486Smckusick */ 65639507Smckusick spec_ebadf() 65739507Smckusick { 65839507Smckusick 65939507Smckusick return (EBADF); 66039507Smckusick } 66139507Smckusick 66239507Smckusick /* 66339507Smckusick * Special device bad operation 66439507Smckusick */ 66539446Smckusick spec_badop() 66637486Smckusick { 66737486Smckusick 66839446Smckusick panic("spec_badop called"); 66939292Smckusick /* NOTREACHED */ 67037486Smckusick } 671