137486Smckusick /* 263247Sbostic * Copyright (c) 1989, 1993 363247Sbostic * The Regents of the University of California. All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*68231Spendry * @(#)spec_vnops.c 8.10 (Berkeley) 02/06/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 */ 5160391Smckusick { &vop_mmap_desc, spec_mmap }, /* mmap */ 5253542Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 5360391Smckusick { &vop_seek_desc, spec_seek }, /* seek */ 5453542Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 5560391Smckusick { &vop_link_desc, spec_link }, /* link */ 5653542Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 5753542Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 5853542Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 5953542Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 6053542Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 6153542Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 6253542Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 6353542Sheideman { &vop_inactive_desc, spec_inactive }, /* inactive */ 6453542Sheideman { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ 6560391Smckusick { &vop_lock_desc, spec_lock }, /* lock */ 6653542Sheideman { &vop_unlock_desc, spec_unlock }, /* unlock */ 6760391Smckusick { &vop_bmap_desc, spec_bmap }, /* bmap */ 6853542Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 6953542Sheideman { &vop_print_desc, spec_print }, /* print */ 7053542Sheideman { &vop_islocked_desc, spec_islocked }, /* islocked */ 7160391Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 7253542Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 7353542Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 7453542Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 7553542Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 7653542Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 7753542Sheideman { &vop_update_desc, spec_update }, /* update */ 7853542Sheideman { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 7953542Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 8037486Smckusick }; 8153542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc = 8253542Sheideman { &spec_vnodeop_p, spec_vnodeop_entries }; 8337486Smckusick 8437486Smckusick /* 8539292Smckusick * Trivial lookup routine that always fails. 8639292Smckusick */ 8752320Sheideman int 8854439Smckusick spec_lookup(ap) 8954439Smckusick struct vop_lookup_args /* { 9054439Smckusick struct vnode *a_dvp; 9154439Smckusick struct vnode **a_vpp; 9254439Smckusick struct componentname *a_cnp; 9354439Smckusick } */ *ap; 9439292Smckusick { 9539292Smckusick 9653597Sheideman *ap->a_vpp = NULL; 9739292Smckusick return (ENOTDIR); 9839292Smckusick } 9939292Smckusick 10039292Smckusick /* 10159486Smckusick * Open a special file. 10237486Smckusick */ 10337725Smckusick /* ARGSUSED */ 10454439Smckusick spec_open(ap) 10554439Smckusick struct vop_open_args /* { 10654439Smckusick struct vnode *a_vp; 10754439Smckusick int a_mode; 10854439Smckusick struct ucred *a_cred; 10954439Smckusick struct proc *a_p; 11054439Smckusick } */ *ap; 11137486Smckusick { 11259486Smckusick struct vnode *bvp, *vp = ap->a_vp; 11359486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev; 11437486Smckusick register int maj = major(dev); 11540375Smckusick int error; 11637486Smckusick 11759486Smckusick /* 11859486Smckusick * Don't allow open if fs is mounted -nodev. 11959486Smckusick */ 12053863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12139365Smckusick return (ENXIO); 12239365Smckusick 12353863Sheideman switch (vp->v_type) { 12437486Smckusick 12537486Smckusick case VCHR: 12637486Smckusick if ((u_int)maj >= nchrdev) 12737486Smckusick return (ENXIO); 12859486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 12959486Smckusick /* 13059486Smckusick * When running in very secure mode, do not allow 13159486Smckusick * opens for writing of any disk character devices. 13259486Smckusick */ 13368129Smckusick if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) 13459486Smckusick return (EPERM); 13559486Smckusick /* 13659486Smckusick * When running in secure mode, do not allow opens 13759486Smckusick * for writing of /dev/mem, /dev/kmem, or character 13859486Smckusick * devices whose corresponding block devices are 13959486Smckusick * currently mounted. 14059486Smckusick */ 14159486Smckusick if (securelevel >= 1) { 14259486Smckusick if ((bdev = chrtoblk(dev)) != NODEV && 14359486Smckusick vfinddev(bdev, VBLK, &bvp) && 14459486Smckusick bvp->v_usecount > 0 && 14565671Shibler (error = vfs_mountedon(bvp))) 14659486Smckusick return (error); 14759486Smckusick if (iskmemdev(dev)) 14859486Smckusick return (EPERM); 14959486Smckusick } 15059486Smckusick } 15168129Smckusick if (cdevsw[maj].d_type == D_TTY) 15267951Smckusick vp->v_flag |= VISTTY; 15353863Sheideman VOP_UNLOCK(vp); 15453597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 15553863Sheideman VOP_LOCK(vp); 15649944Smckusick return (error); 15737486Smckusick 15837486Smckusick case VBLK: 15937486Smckusick if ((u_int)maj >= nblkdev) 16037486Smckusick return (ENXIO); 16159486Smckusick /* 16259486Smckusick * When running in very secure mode, do not allow 16359486Smckusick * opens for writing of any disk block devices. 16459486Smckusick */ 16559486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED && 16668129Smckusick (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) 16759486Smckusick return (EPERM); 16859486Smckusick /* 16959486Smckusick * Do not allow opens of block devices that are 17059486Smckusick * currently mounted. 17159486Smckusick */ 17265671Shibler if (error = vfs_mountedon(vp)) 17340375Smckusick return (error); 17453597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 17537486Smckusick } 17637486Smckusick return (0); 17737486Smckusick } 17837486Smckusick 17937486Smckusick /* 18037486Smckusick * Vnode op for read 18137486Smckusick */ 18241961Smckusick /* ARGSUSED */ 18354439Smckusick spec_read(ap) 18454439Smckusick struct vop_read_args /* { 18554439Smckusick struct vnode *a_vp; 18654439Smckusick struct uio *a_uio; 18754439Smckusick int a_ioflag; 18854439Smckusick struct ucred *a_cred; 18954439Smckusick } */ *ap; 19037486Smckusick { 19153863Sheideman register struct vnode *vp = ap->a_vp; 19253863Sheideman register struct uio *uio = ap->a_uio; 19353863Sheideman struct proc *p = uio->uio_procp; 19439614Smckusick struct buf *bp; 19552321Smckusick daddr_t bn, nextbn; 19639614Smckusick long bsize, bscale; 19739614Smckusick struct partinfo dpart; 19865532Smckusick int n, on, majordev, (*ioctl)(); 19939614Smckusick int error = 0; 20065532Smckusick dev_t dev; 20137486Smckusick 20248015Smckusick #ifdef DIAGNOSTIC 20353863Sheideman if (uio->uio_rw != UIO_READ) 20439588Smckusick panic("spec_read mode"); 20553863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20648015Smckusick panic("spec_read proc"); 20748015Smckusick #endif 20853863Sheideman if (uio->uio_resid == 0) 20939588Smckusick return (0); 21039588Smckusick 21153863Sheideman switch (vp->v_type) { 21239588Smckusick 21339588Smckusick case VCHR: 21453863Sheideman VOP_UNLOCK(vp); 21553863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21653863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 21753863Sheideman VOP_LOCK(vp); 21839588Smckusick return (error); 21939588Smckusick 22039588Smckusick case VBLK: 22153863Sheideman if (uio->uio_offset < 0) 22239588Smckusick return (EINVAL); 22339614Smckusick bsize = BLKDEV_IOSIZE; 22465532Smckusick dev = vp->v_rdev; 22565532Smckusick if ((majordev = major(dev)) < nblkdev && 22665532Smckusick (ioctl = bdevsw[majordev].d_ioctl) != NULL && 22765532Smckusick (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && 22865532Smckusick dpart.part->p_fstype == FS_BSDFFS && 22965532Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 23065532Smckusick bsize = dpart.part->p_frag * dpart.part->p_fsize; 23139614Smckusick bscale = bsize / DEV_BSIZE; 23239614Smckusick do { 23353863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 23453863Sheideman on = uio->uio_offset % bsize; 23555059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23653863Sheideman if (vp->v_lastr + bscale == bn) { 23752321Smckusick nextbn = bn + bscale; 23853863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 23952321Smckusick (int *)&bsize, 1, NOCRED, &bp); 24052321Smckusick } else 24153863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 24253863Sheideman vp->v_lastr = bn; 24355059Spendry n = min(n, bsize - bp->b_resid); 24439614Smckusick if (error) { 24539614Smckusick brelse(bp); 24639614Smckusick return (error); 24739614Smckusick } 24864551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 24939614Smckusick if (n + on == bsize) 25039614Smckusick bp->b_flags |= B_AGE; 25139614Smckusick brelse(bp); 25253863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 25339614Smckusick return (error); 25439588Smckusick 25539588Smckusick default: 25639588Smckusick panic("spec_read type"); 25739588Smckusick } 25839588Smckusick /* NOTREACHED */ 25937486Smckusick } 26037486Smckusick 26137486Smckusick /* 26237486Smckusick * Vnode op for write 26337486Smckusick */ 26441961Smckusick /* ARGSUSED */ 26554439Smckusick spec_write(ap) 26654439Smckusick struct vop_write_args /* { 26754439Smckusick struct vnode *a_vp; 26854439Smckusick struct uio *a_uio; 26954439Smckusick int a_ioflag; 27054439Smckusick struct ucred *a_cred; 27154439Smckusick } */ *ap; 27237486Smckusick { 27353863Sheideman register struct vnode *vp = ap->a_vp; 27453863Sheideman register struct uio *uio = ap->a_uio; 27553863Sheideman struct proc *p = uio->uio_procp; 27639614Smckusick struct buf *bp; 27739614Smckusick daddr_t bn; 27839614Smckusick int bsize, blkmask; 27939614Smckusick struct partinfo dpart; 28045731Smckusick register int n, on; 28145731Smckusick int error = 0; 28237486Smckusick 28348015Smckusick #ifdef DIAGNOSTIC 28453863Sheideman if (uio->uio_rw != UIO_WRITE) 28539588Smckusick panic("spec_write mode"); 28653863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28748015Smckusick panic("spec_write proc"); 28848015Smckusick #endif 28939588Smckusick 29053863Sheideman switch (vp->v_type) { 29139588Smckusick 29239588Smckusick case VCHR: 29353863Sheideman VOP_UNLOCK(vp); 29453863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29553863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 29653863Sheideman VOP_LOCK(vp); 29739588Smckusick return (error); 29839588Smckusick 29939588Smckusick case VBLK: 30053863Sheideman if (uio->uio_resid == 0) 30139588Smckusick return (0); 30253863Sheideman if (uio->uio_offset < 0) 30339588Smckusick return (EINVAL); 30439614Smckusick bsize = BLKDEV_IOSIZE; 30553863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30647540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30739614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 30839614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 30939614Smckusick bsize = dpart.part->p_frag * 31039614Smckusick dpart.part->p_fsize; 31139614Smckusick } 31239614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 31339614Smckusick do { 31453863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31553863Sheideman on = uio->uio_offset % bsize; 31655059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31739614Smckusick if (n == bsize) 31857798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 31939614Smckusick else 32053863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 32155059Spendry n = min(n, bsize - bp->b_resid); 32239614Smckusick if (error) { 32339614Smckusick brelse(bp); 32439614Smckusick return (error); 32539614Smckusick } 32664551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 32739614Smckusick if (n + on == bsize) { 32839614Smckusick bp->b_flags |= B_AGE; 32939614Smckusick bawrite(bp); 33039614Smckusick } else 33139614Smckusick bdwrite(bp); 33253863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 33339614Smckusick return (error); 33439588Smckusick 33539588Smckusick default: 33639588Smckusick panic("spec_write type"); 33739588Smckusick } 33839588Smckusick /* NOTREACHED */ 33937486Smckusick } 34037486Smckusick 34137486Smckusick /* 34237486Smckusick * Device ioctl operation. 34337486Smckusick */ 34437725Smckusick /* ARGSUSED */ 34554439Smckusick spec_ioctl(ap) 34654439Smckusick struct vop_ioctl_args /* { 34754439Smckusick struct vnode *a_vp; 34854439Smckusick int a_command; 34954439Smckusick caddr_t a_data; 35054439Smckusick int a_fflag; 35154439Smckusick struct ucred *a_cred; 35254439Smckusick struct proc *a_p; 35354439Smckusick } */ *ap; 35437486Smckusick { 35553597Sheideman dev_t dev = ap->a_vp->v_rdev; 35637486Smckusick 35753597Sheideman switch (ap->a_vp->v_type) { 35837486Smckusick 35937486Smckusick case VCHR: 36053597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36153597Sheideman ap->a_fflag, ap->a_p)); 36237486Smckusick 36337486Smckusick case VBLK: 36453597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36568129Smckusick if (bdevsw[major(dev)].d_type == D_TAPE) 36639666Smckusick return (0); 36739666Smckusick else 36839666Smckusick return (1); 36953597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 37053597Sheideman ap->a_fflag, ap->a_p)); 37137486Smckusick 37237486Smckusick default: 37339446Smckusick panic("spec_ioctl"); 37437486Smckusick /* NOTREACHED */ 37537486Smckusick } 37637486Smckusick } 37737486Smckusick 37837725Smckusick /* ARGSUSED */ 37954439Smckusick spec_select(ap) 38054439Smckusick struct vop_select_args /* { 38154439Smckusick struct vnode *a_vp; 38254439Smckusick int a_which; 38354439Smckusick int a_fflags; 38454439Smckusick struct ucred *a_cred; 38554439Smckusick struct proc *a_p; 38654439Smckusick } */ *ap; 38737486Smckusick { 38837486Smckusick register dev_t dev; 38937486Smckusick 39053597Sheideman switch (ap->a_vp->v_type) { 39137486Smckusick 39237486Smckusick default: 39337486Smckusick return (1); /* XXX */ 39437486Smckusick 39537486Smckusick case VCHR: 39653597Sheideman dev = ap->a_vp->v_rdev; 39753597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 39837486Smckusick } 39937486Smckusick } 40054439Smckusick /* 40154439Smckusick * Synch buffers associated with a block device 40254439Smckusick */ 40354439Smckusick /* ARGSUSED */ 40454439Smckusick int 40554439Smckusick spec_fsync(ap) 40654439Smckusick struct vop_fsync_args /* { 40754439Smckusick struct vnode *a_vp; 40854439Smckusick struct ucred *a_cred; 40954439Smckusick int a_waitfor; 41054439Smckusick struct proc *a_p; 41154439Smckusick } */ *ap; 41254439Smckusick { 41354439Smckusick register struct vnode *vp = ap->a_vp; 41454439Smckusick register struct buf *bp; 41554439Smckusick struct buf *nbp; 41656548Smckusick int s; 41737486Smckusick 41854439Smckusick if (vp->v_type == VCHR) 41954439Smckusick return (0); 42054439Smckusick /* 42154439Smckusick * Flush all dirty buffers associated with a block device. 42254439Smckusick */ 42354439Smckusick loop: 42454439Smckusick s = splbio(); 42565246Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 42665246Smckusick nbp = bp->b_vnbufs.le_next; 42754439Smckusick if ((bp->b_flags & B_BUSY)) 42854439Smckusick continue; 42954439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 43054439Smckusick panic("spec_fsync: not dirty"); 43154439Smckusick bremfree(bp); 43254439Smckusick bp->b_flags |= B_BUSY; 43354439Smckusick splx(s); 43456548Smckusick bawrite(bp); 43554439Smckusick goto loop; 43654439Smckusick } 43754439Smckusick if (ap->a_waitfor == MNT_WAIT) { 43854439Smckusick while (vp->v_numoutput) { 43954439Smckusick vp->v_flag |= VBWAIT; 44054439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 44154439Smckusick } 44254439Smckusick #ifdef DIAGNOSTIC 44365246Smckusick if (vp->v_dirtyblkhd.lh_first) { 44454439Smckusick vprint("spec_fsync: dirty", vp); 44554439Smckusick goto loop; 44654439Smckusick } 44754439Smckusick #endif 44854439Smckusick } 44954439Smckusick splx(s); 45056548Smckusick return (0); 45154439Smckusick } 45254439Smckusick 45337486Smckusick /* 45437486Smckusick * Just call the device strategy routine 45537486Smckusick */ 45654439Smckusick spec_strategy(ap) 45754439Smckusick struct vop_strategy_args /* { 45854439Smckusick struct buf *a_bp; 45954439Smckusick } */ *ap; 46037486Smckusick { 46139666Smckusick 46253597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 46337486Smckusick return (0); 46437486Smckusick } 46537486Smckusick 46639432Smckusick /* 46739666Smckusick * This is a noop, simply returning what one has been given. 46839666Smckusick */ 46954439Smckusick spec_bmap(ap) 47054439Smckusick struct vop_bmap_args /* { 47154439Smckusick struct vnode *a_vp; 47254439Smckusick daddr_t a_bn; 47354439Smckusick struct vnode **a_vpp; 47454439Smckusick daddr_t *a_bnp; 47554439Smckusick } */ *ap; 47639666Smckusick { 47739666Smckusick 47853597Sheideman if (ap->a_vpp != NULL) 47953597Sheideman *ap->a_vpp = ap->a_vp; 48053597Sheideman if (ap->a_bnp != NULL) 48153597Sheideman *ap->a_bnp = ap->a_bn; 482*68231Spendry if (ap->a_runp != NULL) 483*68231Spendry *ap->a_runp = 0; 48439666Smckusick return (0); 48539666Smckusick } 48639666Smckusick 48739666Smckusick /* 48839432Smckusick * At the moment we do not do any locking. 48939432Smckusick */ 49039489Smckusick /* ARGSUSED */ 49154439Smckusick spec_lock(ap) 49254439Smckusick struct vop_lock_args /* { 49354439Smckusick struct vnode *a_vp; 49454439Smckusick } */ *ap; 49537486Smckusick { 49637486Smckusick 49737486Smckusick return (0); 49837486Smckusick } 49937486Smckusick 50039489Smckusick /* ARGSUSED */ 50154439Smckusick spec_unlock(ap) 50254439Smckusick struct vop_unlock_args /* { 50354439Smckusick struct vnode *a_vp; 50454439Smckusick } */ *ap; 50537486Smckusick { 50637486Smckusick 50737486Smckusick return (0); 50837486Smckusick } 50937486Smckusick 51037486Smckusick /* 51137486Smckusick * Device close routine 51237486Smckusick */ 51337725Smckusick /* ARGSUSED */ 51454439Smckusick spec_close(ap) 51554439Smckusick struct vop_close_args /* { 51654439Smckusick struct vnode *a_vp; 51754439Smckusick int a_fflag; 51854439Smckusick struct ucred *a_cred; 51954439Smckusick struct proc *a_p; 52054439Smckusick } */ *ap; 52137486Smckusick { 52253863Sheideman register struct vnode *vp = ap->a_vp; 52353863Sheideman dev_t dev = vp->v_rdev; 52449273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 52554439Smckusick int mode, error; 52637486Smckusick 52753863Sheideman switch (vp->v_type) { 52837725Smckusick 52937725Smckusick case VCHR: 53039485Smckusick /* 53160498Smckusick * Hack: a tty device that is a controlling terminal 53260498Smckusick * has a reference from the session structure. 53360498Smckusick * We cannot easily tell that a character device is 53460498Smckusick * a controlling terminal, unless it is the closing 53560498Smckusick * process' controlling terminal. In that case, 53660498Smckusick * if the reference count is 2 (this last descriptor 53760498Smckusick * plus the session), release the reference from the session. 53860498Smckusick */ 53960527Smckusick if (vcount(vp) == 2 && ap->a_p && 54060527Smckusick vp == ap->a_p->p_session->s_ttyvp) { 54160498Smckusick vrele(vp); 54260498Smckusick ap->a_p->p_session->s_ttyvp = NULL; 54360498Smckusick } 54460498Smckusick /* 54539485Smckusick * If the vnode is locked, then we are in the midst 54639485Smckusick * of forcably closing the device, otherwise we only 54739485Smckusick * close on last reference. 54839485Smckusick */ 54953863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 55037725Smckusick return (0); 55149273Skarels devclose = cdevsw[major(dev)].d_close; 55239432Smckusick mode = S_IFCHR; 55337725Smckusick break; 55437725Smckusick 55537725Smckusick case VBLK: 55637725Smckusick /* 55737725Smckusick * On last close of a block device (that isn't mounted) 55837725Smckusick * we must invalidate any in core blocks, so that 55937725Smckusick * we can, for instance, change floppy disks. 56037725Smckusick */ 56166739Spendry if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0)) 56254439Smckusick return (error); 56337725Smckusick /* 56439485Smckusick * We do not want to really close the device if it 56539485Smckusick * is still in use unless we are trying to close it 56639485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 56739630Smckusick * holds a reference to the vnode, and because we mark 56839630Smckusick * any other vnodes that alias this device, when the 56939630Smckusick * sum of the reference counts on all the aliased 57039630Smckusick * vnodes descends to one, we are on last close. 57137725Smckusick */ 57253863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 57337725Smckusick return (0); 57449273Skarels devclose = bdevsw[major(dev)].d_close; 57539432Smckusick mode = S_IFBLK; 57637725Smckusick break; 57737725Smckusick 57837725Smckusick default: 57939446Smckusick panic("spec_close: not special"); 58037725Smckusick } 58137725Smckusick 58253597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 58337486Smckusick } 58437486Smckusick 58537486Smckusick /* 58639666Smckusick * Print out the contents of a special device vnode. 58739666Smckusick */ 58854439Smckusick spec_print(ap) 58954439Smckusick struct vop_print_args /* { 59054439Smckusick struct vnode *a_vp; 59154439Smckusick } */ *ap; 59239666Smckusick { 59339666Smckusick 59453597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 59553597Sheideman minor(ap->a_vp->v_rdev)); 59639666Smckusick } 59739666Smckusick 59839666Smckusick /* 59960391Smckusick * Return POSIX pathconf information applicable to special devices. 60060391Smckusick */ 60160391Smckusick spec_pathconf(ap) 60260391Smckusick struct vop_pathconf_args /* { 60360391Smckusick struct vnode *a_vp; 60460391Smckusick int a_name; 60560391Smckusick int *a_retval; 60660391Smckusick } */ *ap; 60760391Smckusick { 60860391Smckusick 60960391Smckusick switch (ap->a_name) { 61060391Smckusick case _PC_LINK_MAX: 61160391Smckusick *ap->a_retval = LINK_MAX; 61260391Smckusick return (0); 61360391Smckusick case _PC_MAX_CANON: 61460391Smckusick *ap->a_retval = MAX_CANON; 61560391Smckusick return (0); 61660391Smckusick case _PC_MAX_INPUT: 61760391Smckusick *ap->a_retval = MAX_INPUT; 61860391Smckusick return (0); 61960391Smckusick case _PC_PIPE_BUF: 62060391Smckusick *ap->a_retval = PIPE_BUF; 62160391Smckusick return (0); 62260391Smckusick case _PC_CHOWN_RESTRICTED: 62360391Smckusick *ap->a_retval = 1; 62460391Smckusick return (0); 62560391Smckusick case _PC_VDISABLE: 62660391Smckusick *ap->a_retval = _POSIX_VDISABLE; 62760391Smckusick return (0); 62860391Smckusick default: 62960391Smckusick return (EINVAL); 63060391Smckusick } 63160391Smckusick /* NOTREACHED */ 63260391Smckusick } 63360391Smckusick 63460391Smckusick /* 63546196Smckusick * Special device advisory byte-level locks. 63646196Smckusick */ 63748015Smckusick /* ARGSUSED */ 63854439Smckusick spec_advlock(ap) 63954439Smckusick struct vop_advlock_args /* { 64054439Smckusick struct vnode *a_vp; 64154439Smckusick caddr_t a_id; 64254439Smckusick int a_op; 64354439Smckusick struct flock *a_fl; 64454439Smckusick int a_flags; 64554439Smckusick } */ *ap; 64646196Smckusick { 64746196Smckusick 64846196Smckusick return (EOPNOTSUPP); 64946196Smckusick } 65046196Smckusick 65146196Smckusick /* 65239507Smckusick * Special device failed operation 65337486Smckusick */ 65439507Smckusick spec_ebadf() 65539507Smckusick { 65639507Smckusick 65739507Smckusick return (EBADF); 65839507Smckusick } 65939507Smckusick 66039507Smckusick /* 66139507Smckusick * Special device bad operation 66239507Smckusick */ 66339446Smckusick spec_badop() 66437486Smckusick { 66537486Smckusick 66639446Smckusick panic("spec_badop called"); 66739292Smckusick /* NOTREACHED */ 66837486Smckusick } 669