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*65671Shibler * @(#)spec_vnops.c 8.5 (Berkeley) 01/12/94 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 */ 4853542Sheideman { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 4953542Sheideman { &vop_select_desc, spec_select }, /* select */ 5060391Smckusick { &vop_mmap_desc, spec_mmap }, /* mmap */ 5153542Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 5260391Smckusick { &vop_seek_desc, spec_seek }, /* seek */ 5353542Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 5460391Smckusick { &vop_link_desc, spec_link }, /* link */ 5553542Sheideman { &vop_rename_desc, spec_rename }, /* rename */ 5653542Sheideman { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 5753542Sheideman { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 5853542Sheideman { &vop_symlink_desc, spec_symlink }, /* symlink */ 5953542Sheideman { &vop_readdir_desc, spec_readdir }, /* readdir */ 6053542Sheideman { &vop_readlink_desc, spec_readlink }, /* readlink */ 6153542Sheideman { &vop_abortop_desc, spec_abortop }, /* abortop */ 6253542Sheideman { &vop_inactive_desc, spec_inactive }, /* inactive */ 6353542Sheideman { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ 6460391Smckusick { &vop_lock_desc, spec_lock }, /* lock */ 6553542Sheideman { &vop_unlock_desc, spec_unlock }, /* unlock */ 6660391Smckusick { &vop_bmap_desc, spec_bmap }, /* bmap */ 6753542Sheideman { &vop_strategy_desc, spec_strategy }, /* strategy */ 6853542Sheideman { &vop_print_desc, spec_print }, /* print */ 6953542Sheideman { &vop_islocked_desc, spec_islocked }, /* islocked */ 7060391Smckusick { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 7153542Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 7253542Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 7353542Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 7453542Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 7553542Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 7653542Sheideman { &vop_update_desc, spec_update }, /* update */ 7753542Sheideman { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 7853542Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 7937486Smckusick }; 8053542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc = 8153542Sheideman { &spec_vnodeop_p, spec_vnodeop_entries }; 8237486Smckusick 8337486Smckusick /* 8439292Smckusick * Trivial lookup routine that always fails. 8539292Smckusick */ 8652320Sheideman int 8754439Smckusick spec_lookup(ap) 8854439Smckusick struct vop_lookup_args /* { 8954439Smckusick struct vnode *a_dvp; 9054439Smckusick struct vnode **a_vpp; 9154439Smckusick struct componentname *a_cnp; 9254439Smckusick } */ *ap; 9339292Smckusick { 9439292Smckusick 9553597Sheideman *ap->a_vpp = NULL; 9639292Smckusick return (ENOTDIR); 9739292Smckusick } 9839292Smckusick 9939292Smckusick /* 10059486Smckusick * Open a special file. 10137486Smckusick */ 10237725Smckusick /* ARGSUSED */ 10354439Smckusick spec_open(ap) 10454439Smckusick struct vop_open_args /* { 10554439Smckusick struct vnode *a_vp; 10654439Smckusick int a_mode; 10754439Smckusick struct ucred *a_cred; 10854439Smckusick struct proc *a_p; 10954439Smckusick } */ *ap; 11037486Smckusick { 11159486Smckusick struct vnode *bvp, *vp = ap->a_vp; 11259486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev; 11337486Smckusick register int maj = major(dev); 11440375Smckusick int error; 11537486Smckusick 11659486Smckusick /* 11759486Smckusick * Don't allow open if fs is mounted -nodev. 11859486Smckusick */ 11953863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12039365Smckusick return (ENXIO); 12139365Smckusick 12253863Sheideman switch (vp->v_type) { 12337486Smckusick 12437486Smckusick case VCHR: 12537486Smckusick if ((u_int)maj >= nchrdev) 12637486Smckusick return (ENXIO); 12759486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 12859486Smckusick /* 12959486Smckusick * When running in very secure mode, do not allow 13059486Smckusick * opens for writing of any disk character devices. 13159486Smckusick */ 13259486Smckusick if (securelevel >= 2 && isdisk(dev, VCHR)) 13359486Smckusick return (EPERM); 13459486Smckusick /* 13559486Smckusick * When running in secure mode, do not allow opens 13659486Smckusick * for writing of /dev/mem, /dev/kmem, or character 13759486Smckusick * devices whose corresponding block devices are 13859486Smckusick * currently mounted. 13959486Smckusick */ 14059486Smckusick if (securelevel >= 1) { 14159486Smckusick if ((bdev = chrtoblk(dev)) != NODEV && 14259486Smckusick vfinddev(bdev, VBLK, &bvp) && 14359486Smckusick bvp->v_usecount > 0 && 144*65671Shibler (error = vfs_mountedon(bvp))) 14559486Smckusick return (error); 14659486Smckusick if (iskmemdev(dev)) 14759486Smckusick return (EPERM); 14859486Smckusick } 14959486Smckusick } 15053863Sheideman VOP_UNLOCK(vp); 15153597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 15253863Sheideman VOP_LOCK(vp); 15349944Smckusick return (error); 15437486Smckusick 15537486Smckusick case VBLK: 15637486Smckusick if ((u_int)maj >= nblkdev) 15737486Smckusick return (ENXIO); 15859486Smckusick /* 15959486Smckusick * When running in very secure mode, do not allow 16059486Smckusick * opens for writing of any disk block devices. 16159486Smckusick */ 16259486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED && 16359486Smckusick (ap->a_mode & FWRITE) && isdisk(dev, VBLK)) 16459486Smckusick return (EPERM); 16559486Smckusick /* 16659486Smckusick * Do not allow opens of block devices that are 16759486Smckusick * currently mounted. 16859486Smckusick */ 169*65671Shibler if (error = vfs_mountedon(vp)) 17040375Smckusick return (error); 17153597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 17237486Smckusick } 17337486Smckusick return (0); 17437486Smckusick } 17537486Smckusick 17637486Smckusick /* 17737486Smckusick * Vnode op for read 17837486Smckusick */ 17941961Smckusick /* ARGSUSED */ 18054439Smckusick spec_read(ap) 18154439Smckusick struct vop_read_args /* { 18254439Smckusick struct vnode *a_vp; 18354439Smckusick struct uio *a_uio; 18454439Smckusick int a_ioflag; 18554439Smckusick struct ucred *a_cred; 18654439Smckusick } */ *ap; 18737486Smckusick { 18853863Sheideman register struct vnode *vp = ap->a_vp; 18953863Sheideman register struct uio *uio = ap->a_uio; 19053863Sheideman struct proc *p = uio->uio_procp; 19139614Smckusick struct buf *bp; 19252321Smckusick daddr_t bn, nextbn; 19339614Smckusick long bsize, bscale; 19439614Smckusick struct partinfo dpart; 19565532Smckusick int n, on, majordev, (*ioctl)(); 19639614Smckusick int error = 0; 19765532Smckusick dev_t dev; 19837486Smckusick 19948015Smckusick #ifdef DIAGNOSTIC 20053863Sheideman if (uio->uio_rw != UIO_READ) 20139588Smckusick panic("spec_read mode"); 20253863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20348015Smckusick panic("spec_read proc"); 20448015Smckusick #endif 20553863Sheideman if (uio->uio_resid == 0) 20639588Smckusick return (0); 20739588Smckusick 20853863Sheideman switch (vp->v_type) { 20939588Smckusick 21039588Smckusick case VCHR: 21153863Sheideman VOP_UNLOCK(vp); 21253863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21353863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 21453863Sheideman VOP_LOCK(vp); 21539588Smckusick return (error); 21639588Smckusick 21739588Smckusick case VBLK: 21853863Sheideman if (uio->uio_offset < 0) 21939588Smckusick return (EINVAL); 22039614Smckusick bsize = BLKDEV_IOSIZE; 22165532Smckusick dev = vp->v_rdev; 22265532Smckusick if ((majordev = major(dev)) < nblkdev && 22365532Smckusick (ioctl = bdevsw[majordev].d_ioctl) != NULL && 22465532Smckusick (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && 22565532Smckusick dpart.part->p_fstype == FS_BSDFFS && 22665532Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 22765532Smckusick bsize = dpart.part->p_frag * dpart.part->p_fsize; 22839614Smckusick bscale = bsize / DEV_BSIZE; 22939614Smckusick do { 23053863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 23153863Sheideman on = uio->uio_offset % bsize; 23255059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23353863Sheideman if (vp->v_lastr + bscale == bn) { 23452321Smckusick nextbn = bn + bscale; 23553863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 23652321Smckusick (int *)&bsize, 1, NOCRED, &bp); 23752321Smckusick } else 23853863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 23953863Sheideman vp->v_lastr = bn; 24055059Spendry n = min(n, bsize - bp->b_resid); 24139614Smckusick if (error) { 24239614Smckusick brelse(bp); 24339614Smckusick return (error); 24439614Smckusick } 24564551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 24639614Smckusick if (n + on == bsize) 24739614Smckusick bp->b_flags |= B_AGE; 24839614Smckusick brelse(bp); 24953863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 25039614Smckusick return (error); 25139588Smckusick 25239588Smckusick default: 25339588Smckusick panic("spec_read type"); 25439588Smckusick } 25539588Smckusick /* NOTREACHED */ 25637486Smckusick } 25737486Smckusick 25837486Smckusick /* 25937486Smckusick * Vnode op for write 26037486Smckusick */ 26141961Smckusick /* ARGSUSED */ 26254439Smckusick spec_write(ap) 26354439Smckusick struct vop_write_args /* { 26454439Smckusick struct vnode *a_vp; 26554439Smckusick struct uio *a_uio; 26654439Smckusick int a_ioflag; 26754439Smckusick struct ucred *a_cred; 26854439Smckusick } */ *ap; 26937486Smckusick { 27053863Sheideman register struct vnode *vp = ap->a_vp; 27153863Sheideman register struct uio *uio = ap->a_uio; 27253863Sheideman struct proc *p = uio->uio_procp; 27339614Smckusick struct buf *bp; 27439614Smckusick daddr_t bn; 27539614Smckusick int bsize, blkmask; 27639614Smckusick struct partinfo dpart; 27745731Smckusick register int n, on; 27845731Smckusick int error = 0; 27937486Smckusick 28048015Smckusick #ifdef DIAGNOSTIC 28153863Sheideman if (uio->uio_rw != UIO_WRITE) 28239588Smckusick panic("spec_write mode"); 28353863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28448015Smckusick panic("spec_write proc"); 28548015Smckusick #endif 28639588Smckusick 28753863Sheideman switch (vp->v_type) { 28839588Smckusick 28939588Smckusick case VCHR: 29053863Sheideman VOP_UNLOCK(vp); 29153863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29253863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 29353863Sheideman VOP_LOCK(vp); 29439588Smckusick return (error); 29539588Smckusick 29639588Smckusick case VBLK: 29753863Sheideman if (uio->uio_resid == 0) 29839588Smckusick return (0); 29953863Sheideman if (uio->uio_offset < 0) 30039588Smckusick return (EINVAL); 30139614Smckusick bsize = BLKDEV_IOSIZE; 30253863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30347540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30439614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 30539614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 30639614Smckusick bsize = dpart.part->p_frag * 30739614Smckusick dpart.part->p_fsize; 30839614Smckusick } 30939614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 31039614Smckusick do { 31153863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31253863Sheideman on = uio->uio_offset % bsize; 31355059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31439614Smckusick if (n == bsize) 31557798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 31639614Smckusick else 31753863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 31855059Spendry n = min(n, bsize - bp->b_resid); 31939614Smckusick if (error) { 32039614Smckusick brelse(bp); 32139614Smckusick return (error); 32239614Smckusick } 32364551Sbostic error = uiomove((char *)bp->b_data + on, n, uio); 32439614Smckusick if (n + on == bsize) { 32539614Smckusick bp->b_flags |= B_AGE; 32639614Smckusick bawrite(bp); 32739614Smckusick } else 32839614Smckusick bdwrite(bp); 32953863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 33039614Smckusick return (error); 33139588Smckusick 33239588Smckusick default: 33339588Smckusick panic("spec_write type"); 33439588Smckusick } 33539588Smckusick /* NOTREACHED */ 33637486Smckusick } 33737486Smckusick 33837486Smckusick /* 33937486Smckusick * Device ioctl operation. 34037486Smckusick */ 34137725Smckusick /* ARGSUSED */ 34254439Smckusick spec_ioctl(ap) 34354439Smckusick struct vop_ioctl_args /* { 34454439Smckusick struct vnode *a_vp; 34554439Smckusick int a_command; 34654439Smckusick caddr_t a_data; 34754439Smckusick int a_fflag; 34854439Smckusick struct ucred *a_cred; 34954439Smckusick struct proc *a_p; 35054439Smckusick } */ *ap; 35137486Smckusick { 35253597Sheideman dev_t dev = ap->a_vp->v_rdev; 35337486Smckusick 35453597Sheideman switch (ap->a_vp->v_type) { 35537486Smckusick 35637486Smckusick case VCHR: 35753597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 35853597Sheideman ap->a_fflag, ap->a_p)); 35937486Smckusick 36037486Smckusick case VBLK: 36153597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36239666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 36339666Smckusick return (0); 36439666Smckusick else 36539666Smckusick return (1); 36653597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36753597Sheideman ap->a_fflag, ap->a_p)); 36837486Smckusick 36937486Smckusick default: 37039446Smckusick panic("spec_ioctl"); 37137486Smckusick /* NOTREACHED */ 37237486Smckusick } 37337486Smckusick } 37437486Smckusick 37537725Smckusick /* ARGSUSED */ 37654439Smckusick spec_select(ap) 37754439Smckusick struct vop_select_args /* { 37854439Smckusick struct vnode *a_vp; 37954439Smckusick int a_which; 38054439Smckusick int a_fflags; 38154439Smckusick struct ucred *a_cred; 38254439Smckusick struct proc *a_p; 38354439Smckusick } */ *ap; 38437486Smckusick { 38537486Smckusick register dev_t dev; 38637486Smckusick 38753597Sheideman switch (ap->a_vp->v_type) { 38837486Smckusick 38937486Smckusick default: 39037486Smckusick return (1); /* XXX */ 39137486Smckusick 39237486Smckusick case VCHR: 39353597Sheideman dev = ap->a_vp->v_rdev; 39453597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 39537486Smckusick } 39637486Smckusick } 39754439Smckusick /* 39854439Smckusick * Synch buffers associated with a block device 39954439Smckusick */ 40054439Smckusick /* ARGSUSED */ 40154439Smckusick int 40254439Smckusick spec_fsync(ap) 40354439Smckusick struct vop_fsync_args /* { 40454439Smckusick struct vnode *a_vp; 40554439Smckusick struct ucred *a_cred; 40654439Smckusick int a_waitfor; 40754439Smckusick struct proc *a_p; 40854439Smckusick } */ *ap; 40954439Smckusick { 41054439Smckusick register struct vnode *vp = ap->a_vp; 41154439Smckusick register struct buf *bp; 41254439Smckusick struct buf *nbp; 41356548Smckusick int s; 41437486Smckusick 41554439Smckusick if (vp->v_type == VCHR) 41654439Smckusick return (0); 41754439Smckusick /* 41854439Smckusick * Flush all dirty buffers associated with a block device. 41954439Smckusick */ 42054439Smckusick loop: 42154439Smckusick s = splbio(); 42265246Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 42365246Smckusick nbp = bp->b_vnbufs.le_next; 42454439Smckusick if ((bp->b_flags & B_BUSY)) 42554439Smckusick continue; 42654439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 42754439Smckusick panic("spec_fsync: not dirty"); 42854439Smckusick bremfree(bp); 42954439Smckusick bp->b_flags |= B_BUSY; 43054439Smckusick splx(s); 43156548Smckusick bawrite(bp); 43254439Smckusick goto loop; 43354439Smckusick } 43454439Smckusick if (ap->a_waitfor == MNT_WAIT) { 43554439Smckusick while (vp->v_numoutput) { 43654439Smckusick vp->v_flag |= VBWAIT; 43754439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 43854439Smckusick } 43954439Smckusick #ifdef DIAGNOSTIC 44065246Smckusick if (vp->v_dirtyblkhd.lh_first) { 44154439Smckusick vprint("spec_fsync: dirty", vp); 44254439Smckusick goto loop; 44354439Smckusick } 44454439Smckusick #endif 44554439Smckusick } 44654439Smckusick splx(s); 44756548Smckusick return (0); 44854439Smckusick } 44954439Smckusick 45037486Smckusick /* 45137486Smckusick * Just call the device strategy routine 45237486Smckusick */ 45354439Smckusick spec_strategy(ap) 45454439Smckusick struct vop_strategy_args /* { 45554439Smckusick struct buf *a_bp; 45654439Smckusick } */ *ap; 45737486Smckusick { 45839666Smckusick 45953597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 46037486Smckusick return (0); 46137486Smckusick } 46237486Smckusick 46339432Smckusick /* 46439666Smckusick * This is a noop, simply returning what one has been given. 46539666Smckusick */ 46654439Smckusick spec_bmap(ap) 46754439Smckusick struct vop_bmap_args /* { 46854439Smckusick struct vnode *a_vp; 46954439Smckusick daddr_t a_bn; 47054439Smckusick struct vnode **a_vpp; 47154439Smckusick daddr_t *a_bnp; 47254439Smckusick } */ *ap; 47339666Smckusick { 47439666Smckusick 47553597Sheideman if (ap->a_vpp != NULL) 47653597Sheideman *ap->a_vpp = ap->a_vp; 47753597Sheideman if (ap->a_bnp != NULL) 47853597Sheideman *ap->a_bnp = ap->a_bn; 47939666Smckusick return (0); 48039666Smckusick } 48139666Smckusick 48239666Smckusick /* 48339432Smckusick * At the moment we do not do any locking. 48439432Smckusick */ 48539489Smckusick /* ARGSUSED */ 48654439Smckusick spec_lock(ap) 48754439Smckusick struct vop_lock_args /* { 48854439Smckusick struct vnode *a_vp; 48954439Smckusick } */ *ap; 49037486Smckusick { 49137486Smckusick 49237486Smckusick return (0); 49337486Smckusick } 49437486Smckusick 49539489Smckusick /* ARGSUSED */ 49654439Smckusick spec_unlock(ap) 49754439Smckusick struct vop_unlock_args /* { 49854439Smckusick struct vnode *a_vp; 49954439Smckusick } */ *ap; 50037486Smckusick { 50137486Smckusick 50237486Smckusick return (0); 50337486Smckusick } 50437486Smckusick 50537486Smckusick /* 50637486Smckusick * Device close routine 50737486Smckusick */ 50837725Smckusick /* ARGSUSED */ 50954439Smckusick spec_close(ap) 51054439Smckusick struct vop_close_args /* { 51154439Smckusick struct vnode *a_vp; 51254439Smckusick int a_fflag; 51354439Smckusick struct ucred *a_cred; 51454439Smckusick struct proc *a_p; 51554439Smckusick } */ *ap; 51637486Smckusick { 51753863Sheideman register struct vnode *vp = ap->a_vp; 51853863Sheideman dev_t dev = vp->v_rdev; 51949273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 52054439Smckusick int mode, error; 52137486Smckusick 52253863Sheideman switch (vp->v_type) { 52337725Smckusick 52437725Smckusick case VCHR: 52539485Smckusick /* 52660498Smckusick * Hack: a tty device that is a controlling terminal 52760498Smckusick * has a reference from the session structure. 52860498Smckusick * We cannot easily tell that a character device is 52960498Smckusick * a controlling terminal, unless it is the closing 53060498Smckusick * process' controlling terminal. In that case, 53160498Smckusick * if the reference count is 2 (this last descriptor 53260498Smckusick * plus the session), release the reference from the session. 53360498Smckusick */ 53460527Smckusick if (vcount(vp) == 2 && ap->a_p && 53560527Smckusick vp == ap->a_p->p_session->s_ttyvp) { 53660498Smckusick vrele(vp); 53760498Smckusick ap->a_p->p_session->s_ttyvp = NULL; 53860498Smckusick } 53960498Smckusick /* 54039485Smckusick * If the vnode is locked, then we are in the midst 54139485Smckusick * of forcably closing the device, otherwise we only 54239485Smckusick * close on last reference. 54339485Smckusick */ 54453863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 54537725Smckusick return (0); 54649273Skarels devclose = cdevsw[major(dev)].d_close; 54739432Smckusick mode = S_IFCHR; 54837725Smckusick break; 54937725Smckusick 55037725Smckusick case VBLK: 55137725Smckusick /* 55237725Smckusick * On last close of a block device (that isn't mounted) 55337725Smckusick * we must invalidate any in core blocks, so that 55437725Smckusick * we can, for instance, change floppy disks. 55537725Smckusick */ 55657798Smckusick if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0)) 55754439Smckusick return (error); 55837725Smckusick /* 55939485Smckusick * We do not want to really close the device if it 56039485Smckusick * is still in use unless we are trying to close it 56139485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 56239630Smckusick * holds a reference to the vnode, and because we mark 56339630Smckusick * any other vnodes that alias this device, when the 56439630Smckusick * sum of the reference counts on all the aliased 56539630Smckusick * vnodes descends to one, we are on last close. 56637725Smckusick */ 56753863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 56837725Smckusick return (0); 56949273Skarels devclose = bdevsw[major(dev)].d_close; 57039432Smckusick mode = S_IFBLK; 57137725Smckusick break; 57237725Smckusick 57337725Smckusick default: 57439446Smckusick panic("spec_close: not special"); 57537725Smckusick } 57637725Smckusick 57753597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 57837486Smckusick } 57937486Smckusick 58037486Smckusick /* 58139666Smckusick * Print out the contents of a special device vnode. 58239666Smckusick */ 58354439Smckusick spec_print(ap) 58454439Smckusick struct vop_print_args /* { 58554439Smckusick struct vnode *a_vp; 58654439Smckusick } */ *ap; 58739666Smckusick { 58839666Smckusick 58953597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 59053597Sheideman minor(ap->a_vp->v_rdev)); 59139666Smckusick } 59239666Smckusick 59339666Smckusick /* 59460391Smckusick * Return POSIX pathconf information applicable to special devices. 59560391Smckusick */ 59660391Smckusick spec_pathconf(ap) 59760391Smckusick struct vop_pathconf_args /* { 59860391Smckusick struct vnode *a_vp; 59960391Smckusick int a_name; 60060391Smckusick int *a_retval; 60160391Smckusick } */ *ap; 60260391Smckusick { 60360391Smckusick 60460391Smckusick switch (ap->a_name) { 60560391Smckusick case _PC_LINK_MAX: 60660391Smckusick *ap->a_retval = LINK_MAX; 60760391Smckusick return (0); 60860391Smckusick case _PC_MAX_CANON: 60960391Smckusick *ap->a_retval = MAX_CANON; 61060391Smckusick return (0); 61160391Smckusick case _PC_MAX_INPUT: 61260391Smckusick *ap->a_retval = MAX_INPUT; 61360391Smckusick return (0); 61460391Smckusick case _PC_PIPE_BUF: 61560391Smckusick *ap->a_retval = PIPE_BUF; 61660391Smckusick return (0); 61760391Smckusick case _PC_CHOWN_RESTRICTED: 61860391Smckusick *ap->a_retval = 1; 61960391Smckusick return (0); 62060391Smckusick case _PC_VDISABLE: 62160391Smckusick *ap->a_retval = _POSIX_VDISABLE; 62260391Smckusick return (0); 62360391Smckusick default: 62460391Smckusick return (EINVAL); 62560391Smckusick } 62660391Smckusick /* NOTREACHED */ 62760391Smckusick } 62860391Smckusick 62960391Smckusick /* 63046196Smckusick * Special device advisory byte-level locks. 63146196Smckusick */ 63248015Smckusick /* ARGSUSED */ 63354439Smckusick spec_advlock(ap) 63454439Smckusick struct vop_advlock_args /* { 63554439Smckusick struct vnode *a_vp; 63654439Smckusick caddr_t a_id; 63754439Smckusick int a_op; 63854439Smckusick struct flock *a_fl; 63954439Smckusick int a_flags; 64054439Smckusick } */ *ap; 64146196Smckusick { 64246196Smckusick 64346196Smckusick return (EOPNOTSUPP); 64446196Smckusick } 64546196Smckusick 64646196Smckusick /* 64739507Smckusick * Special device failed operation 64837486Smckusick */ 64939507Smckusick spec_ebadf() 65039507Smckusick { 65139507Smckusick 65239507Smckusick return (EBADF); 65339507Smckusick } 65439507Smckusick 65539507Smckusick /* 65639507Smckusick * Special device bad operation 65739507Smckusick */ 65839446Smckusick spec_badop() 65937486Smckusick { 66037486Smckusick 66139446Smckusick panic("spec_badop called"); 66239292Smckusick /* NOTREACHED */ 66337486Smckusick } 664