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*69444Smckusick * @(#)spec_vnops.c 8.13 (Berkeley) 05/14/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 */ 5168411Smckusick { &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 { 113*69444Smckusick struct proc *p = ap->a_p; 11459486Smckusick struct vnode *bvp, *vp = ap->a_vp; 11559486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev; 116*69444Smckusick int maj = major(dev); 11740375Smckusick int error; 11837486Smckusick 11959486Smckusick /* 12059486Smckusick * Don't allow open if fs is mounted -nodev. 12159486Smckusick */ 12253863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12339365Smckusick return (ENXIO); 12439365Smckusick 12553863Sheideman switch (vp->v_type) { 12637486Smckusick 12737486Smckusick case VCHR: 12837486Smckusick if ((u_int)maj >= nchrdev) 12937486Smckusick return (ENXIO); 13059486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 13159486Smckusick /* 13259486Smckusick * When running in very secure mode, do not allow 13359486Smckusick * opens for writing of any disk character devices. 13459486Smckusick */ 13568129Smckusick if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) 13659486Smckusick return (EPERM); 13759486Smckusick /* 13859486Smckusick * When running in secure mode, do not allow opens 13959486Smckusick * for writing of /dev/mem, /dev/kmem, or character 14059486Smckusick * devices whose corresponding block devices are 14159486Smckusick * currently mounted. 14259486Smckusick */ 14359486Smckusick if (securelevel >= 1) { 14459486Smckusick if ((bdev = chrtoblk(dev)) != NODEV && 14559486Smckusick vfinddev(bdev, VBLK, &bvp) && 14659486Smckusick bvp->v_usecount > 0 && 14765671Shibler (error = vfs_mountedon(bvp))) 14859486Smckusick return (error); 14959486Smckusick if (iskmemdev(dev)) 15059486Smckusick return (EPERM); 15159486Smckusick } 15259486Smckusick } 15368129Smckusick if (cdevsw[maj].d_type == D_TTY) 15467951Smckusick vp->v_flag |= VISTTY; 155*69444Smckusick VOP_UNLOCK(vp, 0, p); 156*69444Smckusick error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p); 157*69444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 15849944Smckusick return (error); 15937486Smckusick 16037486Smckusick case VBLK: 16137486Smckusick if ((u_int)maj >= nblkdev) 16237486Smckusick return (ENXIO); 16359486Smckusick /* 16459486Smckusick * When running in very secure mode, do not allow 16559486Smckusick * opens for writing of any disk block devices. 16659486Smckusick */ 16759486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED && 16868129Smckusick (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) 16959486Smckusick return (EPERM); 17059486Smckusick /* 17159486Smckusick * Do not allow opens of block devices that are 17259486Smckusick * currently mounted. 17359486Smckusick */ 17465671Shibler if (error = vfs_mountedon(vp)) 17540375Smckusick return (error); 176*69444Smckusick return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p)); 17737486Smckusick } 17837486Smckusick return (0); 17937486Smckusick } 18037486Smckusick 18137486Smckusick /* 18237486Smckusick * Vnode op for read 18337486Smckusick */ 18441961Smckusick /* ARGSUSED */ 18554439Smckusick spec_read(ap) 18654439Smckusick struct vop_read_args /* { 18754439Smckusick struct vnode *a_vp; 18854439Smckusick struct uio *a_uio; 18954439Smckusick int a_ioflag; 19054439Smckusick struct ucred *a_cred; 19154439Smckusick } */ *ap; 19237486Smckusick { 19353863Sheideman register struct vnode *vp = ap->a_vp; 19453863Sheideman register struct uio *uio = ap->a_uio; 19553863Sheideman struct proc *p = uio->uio_procp; 19639614Smckusick struct buf *bp; 19752321Smckusick daddr_t bn, nextbn; 19839614Smckusick long bsize, bscale; 19939614Smckusick struct partinfo dpart; 20065532Smckusick int n, on, majordev, (*ioctl)(); 20139614Smckusick int error = 0; 20265532Smckusick dev_t dev; 20337486Smckusick 20448015Smckusick #ifdef DIAGNOSTIC 20553863Sheideman if (uio->uio_rw != UIO_READ) 20639588Smckusick panic("spec_read mode"); 20753863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20848015Smckusick panic("spec_read proc"); 20948015Smckusick #endif 21053863Sheideman if (uio->uio_resid == 0) 21139588Smckusick return (0); 21239588Smckusick 21353863Sheideman switch (vp->v_type) { 21439588Smckusick 21539588Smckusick case VCHR: 216*69444Smckusick VOP_UNLOCK(vp, 0, p); 21753863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21853863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 219*69444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 22039588Smckusick return (error); 22139588Smckusick 22239588Smckusick case VBLK: 22353863Sheideman if (uio->uio_offset < 0) 22439588Smckusick return (EINVAL); 22539614Smckusick bsize = BLKDEV_IOSIZE; 22665532Smckusick dev = vp->v_rdev; 22765532Smckusick if ((majordev = major(dev)) < nblkdev && 22865532Smckusick (ioctl = bdevsw[majordev].d_ioctl) != NULL && 22965532Smckusick (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && 23065532Smckusick dpart.part->p_fstype == FS_BSDFFS && 23165532Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 23265532Smckusick bsize = dpart.part->p_frag * dpart.part->p_fsize; 23339614Smckusick bscale = bsize / DEV_BSIZE; 23439614Smckusick do { 23553863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 23653863Sheideman on = uio->uio_offset % bsize; 23755059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23853863Sheideman if (vp->v_lastr + bscale == bn) { 23952321Smckusick nextbn = bn + bscale; 24053863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 24152321Smckusick (int *)&bsize, 1, NOCRED, &bp); 24252321Smckusick } else 24353863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 24453863Sheideman vp->v_lastr = bn; 24555059Spendry n = min(n, bsize - bp->b_resid); 24639614Smckusick if (error) { 24739614Smckusick brelse(bp); 24839614Smckusick return (error); 24939614Smckusick } 25064551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 25139614Smckusick if (n + on == bsize) 25239614Smckusick bp->b_flags |= B_AGE; 25339614Smckusick brelse(bp); 25453863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 25539614Smckusick return (error); 25639588Smckusick 25739588Smckusick default: 25839588Smckusick panic("spec_read type"); 25939588Smckusick } 26039588Smckusick /* NOTREACHED */ 26137486Smckusick } 26237486Smckusick 26337486Smckusick /* 26437486Smckusick * Vnode op for write 26537486Smckusick */ 26641961Smckusick /* ARGSUSED */ 26754439Smckusick spec_write(ap) 26854439Smckusick struct vop_write_args /* { 26954439Smckusick struct vnode *a_vp; 27054439Smckusick struct uio *a_uio; 27154439Smckusick int a_ioflag; 27254439Smckusick struct ucred *a_cred; 27354439Smckusick } */ *ap; 27437486Smckusick { 27553863Sheideman register struct vnode *vp = ap->a_vp; 27653863Sheideman register struct uio *uio = ap->a_uio; 27753863Sheideman struct proc *p = uio->uio_procp; 27839614Smckusick struct buf *bp; 27939614Smckusick daddr_t bn; 28039614Smckusick int bsize, blkmask; 28139614Smckusick struct partinfo dpart; 28245731Smckusick register int n, on; 28345731Smckusick int error = 0; 28437486Smckusick 28548015Smckusick #ifdef DIAGNOSTIC 28653863Sheideman if (uio->uio_rw != UIO_WRITE) 28739588Smckusick panic("spec_write mode"); 28853863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28948015Smckusick panic("spec_write proc"); 29048015Smckusick #endif 29139588Smckusick 29253863Sheideman switch (vp->v_type) { 29339588Smckusick 29439588Smckusick case VCHR: 295*69444Smckusick VOP_UNLOCK(vp, 0, p); 29653863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29753863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 298*69444Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 29939588Smckusick return (error); 30039588Smckusick 30139588Smckusick case VBLK: 30253863Sheideman if (uio->uio_resid == 0) 30339588Smckusick return (0); 30453863Sheideman if (uio->uio_offset < 0) 30539588Smckusick return (EINVAL); 30639614Smckusick bsize = BLKDEV_IOSIZE; 30753863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30847540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30939614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 31039614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 31139614Smckusick bsize = dpart.part->p_frag * 31239614Smckusick dpart.part->p_fsize; 31339614Smckusick } 31439614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 31539614Smckusick do { 31653863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31753863Sheideman on = uio->uio_offset % bsize; 31855059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31939614Smckusick if (n == bsize) 32057798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 32139614Smckusick else 32253863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 32355059Spendry n = min(n, bsize - bp->b_resid); 32439614Smckusick if (error) { 32539614Smckusick brelse(bp); 32639614Smckusick return (error); 32739614Smckusick } 32864551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 32939614Smckusick if (n + on == bsize) { 33039614Smckusick bp->b_flags |= B_AGE; 33139614Smckusick bawrite(bp); 33239614Smckusick } else 33339614Smckusick bdwrite(bp); 33453863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 33539614Smckusick return (error); 33639588Smckusick 33739588Smckusick default: 33839588Smckusick panic("spec_write type"); 33939588Smckusick } 34039588Smckusick /* NOTREACHED */ 34137486Smckusick } 34237486Smckusick 34337486Smckusick /* 34437486Smckusick * Device ioctl operation. 34537486Smckusick */ 34637725Smckusick /* ARGSUSED */ 34754439Smckusick spec_ioctl(ap) 34854439Smckusick struct vop_ioctl_args /* { 34954439Smckusick struct vnode *a_vp; 35054439Smckusick int a_command; 35154439Smckusick caddr_t a_data; 35254439Smckusick int a_fflag; 35354439Smckusick struct ucred *a_cred; 35454439Smckusick struct proc *a_p; 35554439Smckusick } */ *ap; 35637486Smckusick { 35753597Sheideman dev_t dev = ap->a_vp->v_rdev; 35837486Smckusick 35953597Sheideman switch (ap->a_vp->v_type) { 36037486Smckusick 36137486Smckusick case VCHR: 36253597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36353597Sheideman ap->a_fflag, ap->a_p)); 36437486Smckusick 36537486Smckusick case VBLK: 36653597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36768129Smckusick if (bdevsw[major(dev)].d_type == D_TAPE) 36839666Smckusick return (0); 36939666Smckusick else 37039666Smckusick return (1); 37153597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 37253597Sheideman ap->a_fflag, ap->a_p)); 37337486Smckusick 37437486Smckusick default: 37539446Smckusick panic("spec_ioctl"); 37637486Smckusick /* NOTREACHED */ 37737486Smckusick } 37837486Smckusick } 37937486Smckusick 38037725Smckusick /* ARGSUSED */ 38154439Smckusick spec_select(ap) 38254439Smckusick struct vop_select_args /* { 38354439Smckusick struct vnode *a_vp; 38454439Smckusick int a_which; 38554439Smckusick int a_fflags; 38654439Smckusick struct ucred *a_cred; 38754439Smckusick struct proc *a_p; 38854439Smckusick } */ *ap; 38937486Smckusick { 39037486Smckusick register dev_t dev; 39137486Smckusick 39253597Sheideman switch (ap->a_vp->v_type) { 39337486Smckusick 39437486Smckusick default: 39537486Smckusick return (1); /* XXX */ 39637486Smckusick 39737486Smckusick case VCHR: 39853597Sheideman dev = ap->a_vp->v_rdev; 39953597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 40037486Smckusick } 40137486Smckusick } 40254439Smckusick /* 40354439Smckusick * Synch buffers associated with a block device 40454439Smckusick */ 40554439Smckusick /* ARGSUSED */ 40654439Smckusick int 40754439Smckusick spec_fsync(ap) 40854439Smckusick struct vop_fsync_args /* { 40954439Smckusick struct vnode *a_vp; 41054439Smckusick struct ucred *a_cred; 41154439Smckusick int a_waitfor; 41254439Smckusick struct proc *a_p; 41354439Smckusick } */ *ap; 41454439Smckusick { 41554439Smckusick register struct vnode *vp = ap->a_vp; 41654439Smckusick register struct buf *bp; 41754439Smckusick struct buf *nbp; 41856548Smckusick int s; 41937486Smckusick 42054439Smckusick if (vp->v_type == VCHR) 42154439Smckusick return (0); 42254439Smckusick /* 42354439Smckusick * Flush all dirty buffers associated with a block device. 42454439Smckusick */ 42554439Smckusick loop: 42654439Smckusick s = splbio(); 42765246Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 42865246Smckusick nbp = bp->b_vnbufs.le_next; 42954439Smckusick if ((bp->b_flags & B_BUSY)) 43054439Smckusick continue; 43154439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 43254439Smckusick panic("spec_fsync: not dirty"); 43354439Smckusick bremfree(bp); 43454439Smckusick bp->b_flags |= B_BUSY; 43554439Smckusick splx(s); 43656548Smckusick bawrite(bp); 43754439Smckusick goto loop; 43854439Smckusick } 43954439Smckusick if (ap->a_waitfor == MNT_WAIT) { 44054439Smckusick while (vp->v_numoutput) { 44154439Smckusick vp->v_flag |= VBWAIT; 44254439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 44354439Smckusick } 44454439Smckusick #ifdef DIAGNOSTIC 44565246Smckusick if (vp->v_dirtyblkhd.lh_first) { 44654439Smckusick vprint("spec_fsync: dirty", vp); 44754439Smckusick goto loop; 44854439Smckusick } 44954439Smckusick #endif 45054439Smckusick } 45154439Smckusick splx(s); 45256548Smckusick return (0); 45354439Smckusick } 45454439Smckusick 45537486Smckusick /* 45637486Smckusick * Just call the device strategy routine 45737486Smckusick */ 45854439Smckusick spec_strategy(ap) 45954439Smckusick struct vop_strategy_args /* { 46054439Smckusick struct buf *a_bp; 46154439Smckusick } */ *ap; 46237486Smckusick { 46339666Smckusick 46453597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 46537486Smckusick return (0); 46637486Smckusick } 46737486Smckusick 46839432Smckusick /* 46939666Smckusick * This is a noop, simply returning what one has been given. 47039666Smckusick */ 47154439Smckusick spec_bmap(ap) 47254439Smckusick struct vop_bmap_args /* { 47354439Smckusick struct vnode *a_vp; 47454439Smckusick daddr_t a_bn; 47554439Smckusick struct vnode **a_vpp; 47654439Smckusick daddr_t *a_bnp; 47768234Spendry int *a_runp; 47854439Smckusick } */ *ap; 47939666Smckusick { 48039666Smckusick 48153597Sheideman if (ap->a_vpp != NULL) 48253597Sheideman *ap->a_vpp = ap->a_vp; 48353597Sheideman if (ap->a_bnp != NULL) 48453597Sheideman *ap->a_bnp = ap->a_bn; 48568231Spendry if (ap->a_runp != NULL) 48668231Spendry *ap->a_runp = 0; 48739666Smckusick return (0); 48839666Smckusick } 48939666Smckusick 49039666Smckusick /* 49137486Smckusick * Device close routine 49237486Smckusick */ 49337725Smckusick /* ARGSUSED */ 49454439Smckusick spec_close(ap) 49554439Smckusick struct vop_close_args /* { 49654439Smckusick struct vnode *a_vp; 49754439Smckusick int a_fflag; 49854439Smckusick struct ucred *a_cred; 49954439Smckusick struct proc *a_p; 50054439Smckusick } */ *ap; 50137486Smckusick { 50253863Sheideman register struct vnode *vp = ap->a_vp; 50353863Sheideman dev_t dev = vp->v_rdev; 50449273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 50554439Smckusick int mode, error; 50637486Smckusick 50753863Sheideman switch (vp->v_type) { 50837725Smckusick 50937725Smckusick case VCHR: 51039485Smckusick /* 51160498Smckusick * Hack: a tty device that is a controlling terminal 51260498Smckusick * has a reference from the session structure. 51360498Smckusick * We cannot easily tell that a character device is 51460498Smckusick * a controlling terminal, unless it is the closing 51560498Smckusick * process' controlling terminal. In that case, 51660498Smckusick * if the reference count is 2 (this last descriptor 51760498Smckusick * plus the session), release the reference from the session. 51860498Smckusick */ 51960527Smckusick if (vcount(vp) == 2 && ap->a_p && 52060527Smckusick vp == ap->a_p->p_session->s_ttyvp) { 52160498Smckusick vrele(vp); 52260498Smckusick ap->a_p->p_session->s_ttyvp = NULL; 52360498Smckusick } 52460498Smckusick /* 52539485Smckusick * If the vnode is locked, then we are in the midst 52639485Smckusick * of forcably closing the device, otherwise we only 52739485Smckusick * close on last reference. 52839485Smckusick */ 52953863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 53037725Smckusick return (0); 53149273Skarels devclose = cdevsw[major(dev)].d_close; 53239432Smckusick mode = S_IFCHR; 53337725Smckusick break; 53437725Smckusick 53537725Smckusick case VBLK: 53637725Smckusick /* 53737725Smckusick * On last close of a block device (that isn't mounted) 53837725Smckusick * we must invalidate any in core blocks, so that 53937725Smckusick * we can, for instance, change floppy disks. 54037725Smckusick */ 54166739Spendry if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0)) 54254439Smckusick return (error); 54337725Smckusick /* 54439485Smckusick * We do not want to really close the device if it 54539485Smckusick * is still in use unless we are trying to close it 54639485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 54739630Smckusick * holds a reference to the vnode, and because we mark 54839630Smckusick * any other vnodes that alias this device, when the 54939630Smckusick * sum of the reference counts on all the aliased 55039630Smckusick * vnodes descends to one, we are on last close. 55137725Smckusick */ 55253863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 55337725Smckusick return (0); 55449273Skarels devclose = bdevsw[major(dev)].d_close; 55539432Smckusick mode = S_IFBLK; 55637725Smckusick break; 55737725Smckusick 55837725Smckusick default: 55939446Smckusick panic("spec_close: not special"); 56037725Smckusick } 56137725Smckusick 56253597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 56337486Smckusick } 56437486Smckusick 56537486Smckusick /* 56639666Smckusick * Print out the contents of a special device vnode. 56739666Smckusick */ 56854439Smckusick spec_print(ap) 56954439Smckusick struct vop_print_args /* { 57054439Smckusick struct vnode *a_vp; 57154439Smckusick } */ *ap; 57239666Smckusick { 57339666Smckusick 57453597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 57553597Sheideman minor(ap->a_vp->v_rdev)); 57639666Smckusick } 57739666Smckusick 57839666Smckusick /* 57960391Smckusick * Return POSIX pathconf information applicable to special devices. 58060391Smckusick */ 58160391Smckusick spec_pathconf(ap) 58260391Smckusick struct vop_pathconf_args /* { 58360391Smckusick struct vnode *a_vp; 58460391Smckusick int a_name; 58560391Smckusick int *a_retval; 58660391Smckusick } */ *ap; 58760391Smckusick { 58860391Smckusick 58960391Smckusick switch (ap->a_name) { 59060391Smckusick case _PC_LINK_MAX: 59160391Smckusick *ap->a_retval = LINK_MAX; 59260391Smckusick return (0); 59360391Smckusick case _PC_MAX_CANON: 59460391Smckusick *ap->a_retval = MAX_CANON; 59560391Smckusick return (0); 59660391Smckusick case _PC_MAX_INPUT: 59760391Smckusick *ap->a_retval = MAX_INPUT; 59860391Smckusick return (0); 59960391Smckusick case _PC_PIPE_BUF: 60060391Smckusick *ap->a_retval = PIPE_BUF; 60160391Smckusick return (0); 60260391Smckusick case _PC_CHOWN_RESTRICTED: 60360391Smckusick *ap->a_retval = 1; 60460391Smckusick return (0); 60560391Smckusick case _PC_VDISABLE: 60660391Smckusick *ap->a_retval = _POSIX_VDISABLE; 60760391Smckusick return (0); 60860391Smckusick default: 60960391Smckusick return (EINVAL); 61060391Smckusick } 61160391Smckusick /* NOTREACHED */ 61260391Smckusick } 61360391Smckusick 61460391Smckusick /* 61546196Smckusick * Special device advisory byte-level locks. 61646196Smckusick */ 61748015Smckusick /* ARGSUSED */ 61854439Smckusick spec_advlock(ap) 61954439Smckusick struct vop_advlock_args /* { 62054439Smckusick struct vnode *a_vp; 62154439Smckusick caddr_t a_id; 62254439Smckusick int a_op; 62354439Smckusick struct flock *a_fl; 62454439Smckusick int a_flags; 62554439Smckusick } */ *ap; 62646196Smckusick { 62746196Smckusick 62846196Smckusick return (EOPNOTSUPP); 62946196Smckusick } 63046196Smckusick 63146196Smckusick /* 63239507Smckusick * Special device failed operation 63337486Smckusick */ 63439507Smckusick spec_ebadf() 63539507Smckusick { 63639507Smckusick 63739507Smckusick return (EBADF); 63839507Smckusick } 63939507Smckusick 64039507Smckusick /* 64139507Smckusick * Special device bad operation 64239507Smckusick */ 64339446Smckusick spec_badop() 64437486Smckusick { 64537486Smckusick 64639446Smckusick panic("spec_badop called"); 64739292Smckusick /* NOTREACHED */ 64837486Smckusick } 649