137486Smckusick /* 2*63247Sbostic * Copyright (c) 1989, 1993 3*63247Sbostic * The Regents of the University of California. All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*63247Sbostic * @(#)spec_vnops.c 8.1 (Berkeley) 06/10/93 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 && 14459486Smckusick (error = ufs_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 */ 16953863Sheideman if (error = ufs_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; 19539614Smckusick register int n, on; 19639614Smckusick int error = 0; 19737486Smckusick 19848015Smckusick #ifdef DIAGNOSTIC 19953863Sheideman if (uio->uio_rw != UIO_READ) 20039588Smckusick panic("spec_read mode"); 20153863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20248015Smckusick panic("spec_read proc"); 20348015Smckusick #endif 20453863Sheideman if (uio->uio_resid == 0) 20539588Smckusick return (0); 20639588Smckusick 20753863Sheideman switch (vp->v_type) { 20839588Smckusick 20939588Smckusick case VCHR: 21053863Sheideman VOP_UNLOCK(vp); 21153863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21253863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 21353863Sheideman VOP_LOCK(vp); 21439588Smckusick return (error); 21539588Smckusick 21639588Smckusick case VBLK: 21753863Sheideman if (uio->uio_offset < 0) 21839588Smckusick return (EINVAL); 21939614Smckusick bsize = BLKDEV_IOSIZE; 22053863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 22147540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 22239614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 22339614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 22439614Smckusick bsize = dpart.part->p_frag * 22539614Smckusick dpart.part->p_fsize; 22639614Smckusick } 22739614Smckusick bscale = bsize / DEV_BSIZE; 22839614Smckusick do { 22953863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 23053863Sheideman on = uio->uio_offset % bsize; 23155059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23253863Sheideman if (vp->v_lastr + bscale == bn) { 23352321Smckusick nextbn = bn + bscale; 23453863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 23552321Smckusick (int *)&bsize, 1, NOCRED, &bp); 23652321Smckusick } else 23753863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 23853863Sheideman vp->v_lastr = bn; 23955059Spendry n = min(n, bsize - bp->b_resid); 24039614Smckusick if (error) { 24139614Smckusick brelse(bp); 24239614Smckusick return (error); 24339614Smckusick } 24453863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 24539614Smckusick if (n + on == bsize) 24639614Smckusick bp->b_flags |= B_AGE; 24739614Smckusick brelse(bp); 24853863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 24939614Smckusick return (error); 25039588Smckusick 25139588Smckusick default: 25239588Smckusick panic("spec_read type"); 25339588Smckusick } 25439588Smckusick /* NOTREACHED */ 25537486Smckusick } 25637486Smckusick 25737486Smckusick /* 25837486Smckusick * Vnode op for write 25937486Smckusick */ 26041961Smckusick /* ARGSUSED */ 26154439Smckusick spec_write(ap) 26254439Smckusick struct vop_write_args /* { 26354439Smckusick struct vnode *a_vp; 26454439Smckusick struct uio *a_uio; 26554439Smckusick int a_ioflag; 26654439Smckusick struct ucred *a_cred; 26754439Smckusick } */ *ap; 26837486Smckusick { 26953863Sheideman register struct vnode *vp = ap->a_vp; 27053863Sheideman register struct uio *uio = ap->a_uio; 27153863Sheideman struct proc *p = uio->uio_procp; 27239614Smckusick struct buf *bp; 27339614Smckusick daddr_t bn; 27439614Smckusick int bsize, blkmask; 27539614Smckusick struct partinfo dpart; 27645731Smckusick register int n, on; 27745731Smckusick int error = 0; 27837486Smckusick 27948015Smckusick #ifdef DIAGNOSTIC 28053863Sheideman if (uio->uio_rw != UIO_WRITE) 28139588Smckusick panic("spec_write mode"); 28253863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28348015Smckusick panic("spec_write proc"); 28448015Smckusick #endif 28539588Smckusick 28653863Sheideman switch (vp->v_type) { 28739588Smckusick 28839588Smckusick case VCHR: 28953863Sheideman VOP_UNLOCK(vp); 29053863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29153863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 29253863Sheideman VOP_LOCK(vp); 29339588Smckusick return (error); 29439588Smckusick 29539588Smckusick case VBLK: 29653863Sheideman if (uio->uio_resid == 0) 29739588Smckusick return (0); 29853863Sheideman if (uio->uio_offset < 0) 29939588Smckusick return (EINVAL); 30039614Smckusick bsize = BLKDEV_IOSIZE; 30153863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30247540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30339614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 30439614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 30539614Smckusick bsize = dpart.part->p_frag * 30639614Smckusick dpart.part->p_fsize; 30739614Smckusick } 30839614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 30939614Smckusick do { 31053863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31153863Sheideman on = uio->uio_offset % bsize; 31255059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31339614Smckusick if (n == bsize) 31457798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 31539614Smckusick else 31653863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 31755059Spendry n = min(n, bsize - bp->b_resid); 31839614Smckusick if (error) { 31939614Smckusick brelse(bp); 32039614Smckusick return (error); 32139614Smckusick } 32253863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 32339614Smckusick if (n + on == bsize) { 32439614Smckusick bp->b_flags |= B_AGE; 32539614Smckusick bawrite(bp); 32639614Smckusick } else 32739614Smckusick bdwrite(bp); 32853863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 32939614Smckusick return (error); 33039588Smckusick 33139588Smckusick default: 33239588Smckusick panic("spec_write type"); 33339588Smckusick } 33439588Smckusick /* NOTREACHED */ 33537486Smckusick } 33637486Smckusick 33737486Smckusick /* 33837486Smckusick * Device ioctl operation. 33937486Smckusick */ 34037725Smckusick /* ARGSUSED */ 34154439Smckusick spec_ioctl(ap) 34254439Smckusick struct vop_ioctl_args /* { 34354439Smckusick struct vnode *a_vp; 34454439Smckusick int a_command; 34554439Smckusick caddr_t a_data; 34654439Smckusick int a_fflag; 34754439Smckusick struct ucred *a_cred; 34854439Smckusick struct proc *a_p; 34954439Smckusick } */ *ap; 35037486Smckusick { 35153597Sheideman dev_t dev = ap->a_vp->v_rdev; 35237486Smckusick 35353597Sheideman switch (ap->a_vp->v_type) { 35437486Smckusick 35537486Smckusick case VCHR: 35653597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 35753597Sheideman ap->a_fflag, ap->a_p)); 35837486Smckusick 35937486Smckusick case VBLK: 36053597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36139666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 36239666Smckusick return (0); 36339666Smckusick else 36439666Smckusick return (1); 36553597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36653597Sheideman ap->a_fflag, ap->a_p)); 36737486Smckusick 36837486Smckusick default: 36939446Smckusick panic("spec_ioctl"); 37037486Smckusick /* NOTREACHED */ 37137486Smckusick } 37237486Smckusick } 37337486Smckusick 37437725Smckusick /* ARGSUSED */ 37554439Smckusick spec_select(ap) 37654439Smckusick struct vop_select_args /* { 37754439Smckusick struct vnode *a_vp; 37854439Smckusick int a_which; 37954439Smckusick int a_fflags; 38054439Smckusick struct ucred *a_cred; 38154439Smckusick struct proc *a_p; 38254439Smckusick } */ *ap; 38337486Smckusick { 38437486Smckusick register dev_t dev; 38537486Smckusick 38653597Sheideman switch (ap->a_vp->v_type) { 38737486Smckusick 38837486Smckusick default: 38937486Smckusick return (1); /* XXX */ 39037486Smckusick 39137486Smckusick case VCHR: 39253597Sheideman dev = ap->a_vp->v_rdev; 39353597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 39437486Smckusick } 39537486Smckusick } 39654439Smckusick /* 39754439Smckusick * Synch buffers associated with a block device 39854439Smckusick */ 39954439Smckusick /* ARGSUSED */ 40054439Smckusick int 40154439Smckusick spec_fsync(ap) 40254439Smckusick struct vop_fsync_args /* { 40354439Smckusick struct vnode *a_vp; 40454439Smckusick struct ucred *a_cred; 40554439Smckusick int a_waitfor; 40654439Smckusick struct proc *a_p; 40754439Smckusick } */ *ap; 40854439Smckusick { 40954439Smckusick register struct vnode *vp = ap->a_vp; 41054439Smckusick register struct buf *bp; 41154439Smckusick struct buf *nbp; 41256548Smckusick int s; 41337486Smckusick 41454439Smckusick if (vp->v_type == VCHR) 41554439Smckusick return (0); 41654439Smckusick /* 41754439Smckusick * Flush all dirty buffers associated with a block device. 41854439Smckusick */ 41954439Smckusick loop: 42054439Smckusick s = splbio(); 42156471Smckusick for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) { 42256471Smckusick nbp = bp->b_vnbufs.qe_next; 42354439Smckusick if ((bp->b_flags & B_BUSY)) 42454439Smckusick continue; 42554439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 42654439Smckusick panic("spec_fsync: not dirty"); 42754439Smckusick bremfree(bp); 42854439Smckusick bp->b_flags |= B_BUSY; 42954439Smckusick splx(s); 43056548Smckusick bawrite(bp); 43154439Smckusick goto loop; 43254439Smckusick } 43354439Smckusick if (ap->a_waitfor == MNT_WAIT) { 43454439Smckusick while (vp->v_numoutput) { 43554439Smckusick vp->v_flag |= VBWAIT; 43654439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 43754439Smckusick } 43854439Smckusick #ifdef DIAGNOSTIC 43956471Smckusick if (vp->v_dirtyblkhd.le_next) { 44054439Smckusick vprint("spec_fsync: dirty", vp); 44154439Smckusick goto loop; 44254439Smckusick } 44354439Smckusick #endif 44454439Smckusick } 44554439Smckusick splx(s); 44656548Smckusick return (0); 44754439Smckusick } 44854439Smckusick 44937486Smckusick /* 45037486Smckusick * Just call the device strategy routine 45137486Smckusick */ 45254439Smckusick spec_strategy(ap) 45354439Smckusick struct vop_strategy_args /* { 45454439Smckusick struct buf *a_bp; 45554439Smckusick } */ *ap; 45637486Smckusick { 45739666Smckusick 45853597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 45937486Smckusick return (0); 46037486Smckusick } 46137486Smckusick 46239432Smckusick /* 46339666Smckusick * This is a noop, simply returning what one has been given. 46439666Smckusick */ 46554439Smckusick spec_bmap(ap) 46654439Smckusick struct vop_bmap_args /* { 46754439Smckusick struct vnode *a_vp; 46854439Smckusick daddr_t a_bn; 46954439Smckusick struct vnode **a_vpp; 47054439Smckusick daddr_t *a_bnp; 47154439Smckusick } */ *ap; 47239666Smckusick { 47339666Smckusick 47453597Sheideman if (ap->a_vpp != NULL) 47553597Sheideman *ap->a_vpp = ap->a_vp; 47653597Sheideman if (ap->a_bnp != NULL) 47753597Sheideman *ap->a_bnp = ap->a_bn; 47839666Smckusick return (0); 47939666Smckusick } 48039666Smckusick 48139666Smckusick /* 48239432Smckusick * At the moment we do not do any locking. 48339432Smckusick */ 48439489Smckusick /* ARGSUSED */ 48554439Smckusick spec_lock(ap) 48654439Smckusick struct vop_lock_args /* { 48754439Smckusick struct vnode *a_vp; 48854439Smckusick } */ *ap; 48937486Smckusick { 49037486Smckusick 49137486Smckusick return (0); 49237486Smckusick } 49337486Smckusick 49439489Smckusick /* ARGSUSED */ 49554439Smckusick spec_unlock(ap) 49654439Smckusick struct vop_unlock_args /* { 49754439Smckusick struct vnode *a_vp; 49854439Smckusick } */ *ap; 49937486Smckusick { 50037486Smckusick 50137486Smckusick return (0); 50237486Smckusick } 50337486Smckusick 50437486Smckusick /* 50537486Smckusick * Device close routine 50637486Smckusick */ 50737725Smckusick /* ARGSUSED */ 50854439Smckusick spec_close(ap) 50954439Smckusick struct vop_close_args /* { 51054439Smckusick struct vnode *a_vp; 51154439Smckusick int a_fflag; 51254439Smckusick struct ucred *a_cred; 51354439Smckusick struct proc *a_p; 51454439Smckusick } */ *ap; 51537486Smckusick { 51653863Sheideman register struct vnode *vp = ap->a_vp; 51753863Sheideman dev_t dev = vp->v_rdev; 51849273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 51954439Smckusick int mode, error; 52037486Smckusick 52153863Sheideman switch (vp->v_type) { 52237725Smckusick 52337725Smckusick case VCHR: 52439485Smckusick /* 52560498Smckusick * Hack: a tty device that is a controlling terminal 52660498Smckusick * has a reference from the session structure. 52760498Smckusick * We cannot easily tell that a character device is 52860498Smckusick * a controlling terminal, unless it is the closing 52960498Smckusick * process' controlling terminal. In that case, 53060498Smckusick * if the reference count is 2 (this last descriptor 53160498Smckusick * plus the session), release the reference from the session. 53260498Smckusick */ 53360527Smckusick if (vcount(vp) == 2 && ap->a_p && 53460527Smckusick vp == ap->a_p->p_session->s_ttyvp) { 53560498Smckusick vrele(vp); 53660498Smckusick ap->a_p->p_session->s_ttyvp = NULL; 53760498Smckusick } 53860498Smckusick /* 53939485Smckusick * If the vnode is locked, then we are in the midst 54039485Smckusick * of forcably closing the device, otherwise we only 54139485Smckusick * close on last reference. 54239485Smckusick */ 54353863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 54437725Smckusick return (0); 54549273Skarels devclose = cdevsw[major(dev)].d_close; 54639432Smckusick mode = S_IFCHR; 54737725Smckusick break; 54837725Smckusick 54937725Smckusick case VBLK: 55037725Smckusick /* 55137725Smckusick * On last close of a block device (that isn't mounted) 55237725Smckusick * we must invalidate any in core blocks, so that 55337725Smckusick * we can, for instance, change floppy disks. 55437725Smckusick */ 55557798Smckusick if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0)) 55654439Smckusick return (error); 55737725Smckusick /* 55839485Smckusick * We do not want to really close the device if it 55939485Smckusick * is still in use unless we are trying to close it 56039485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 56139630Smckusick * holds a reference to the vnode, and because we mark 56239630Smckusick * any other vnodes that alias this device, when the 56339630Smckusick * sum of the reference counts on all the aliased 56439630Smckusick * vnodes descends to one, we are on last close. 56537725Smckusick */ 56653863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 56737725Smckusick return (0); 56849273Skarels devclose = bdevsw[major(dev)].d_close; 56939432Smckusick mode = S_IFBLK; 57037725Smckusick break; 57137725Smckusick 57237725Smckusick default: 57339446Smckusick panic("spec_close: not special"); 57437725Smckusick } 57537725Smckusick 57653597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 57737486Smckusick } 57837486Smckusick 57937486Smckusick /* 58039666Smckusick * Print out the contents of a special device vnode. 58139666Smckusick */ 58254439Smckusick spec_print(ap) 58354439Smckusick struct vop_print_args /* { 58454439Smckusick struct vnode *a_vp; 58554439Smckusick } */ *ap; 58639666Smckusick { 58739666Smckusick 58853597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 58953597Sheideman minor(ap->a_vp->v_rdev)); 59039666Smckusick } 59139666Smckusick 59239666Smckusick /* 59360391Smckusick * Return POSIX pathconf information applicable to special devices. 59460391Smckusick */ 59560391Smckusick spec_pathconf(ap) 59660391Smckusick struct vop_pathconf_args /* { 59760391Smckusick struct vnode *a_vp; 59860391Smckusick int a_name; 59960391Smckusick int *a_retval; 60060391Smckusick } */ *ap; 60160391Smckusick { 60260391Smckusick 60360391Smckusick switch (ap->a_name) { 60460391Smckusick case _PC_LINK_MAX: 60560391Smckusick *ap->a_retval = LINK_MAX; 60660391Smckusick return (0); 60760391Smckusick case _PC_MAX_CANON: 60860391Smckusick *ap->a_retval = MAX_CANON; 60960391Smckusick return (0); 61060391Smckusick case _PC_MAX_INPUT: 61160391Smckusick *ap->a_retval = MAX_INPUT; 61260391Smckusick return (0); 61360391Smckusick case _PC_PIPE_BUF: 61460391Smckusick *ap->a_retval = PIPE_BUF; 61560391Smckusick return (0); 61660391Smckusick case _PC_CHOWN_RESTRICTED: 61760391Smckusick *ap->a_retval = 1; 61860391Smckusick return (0); 61960391Smckusick case _PC_VDISABLE: 62060391Smckusick *ap->a_retval = _POSIX_VDISABLE; 62160391Smckusick return (0); 62260391Smckusick default: 62360391Smckusick return (EINVAL); 62460391Smckusick } 62560391Smckusick /* NOTREACHED */ 62660391Smckusick } 62760391Smckusick 62860391Smckusick /* 62946196Smckusick * Special device advisory byte-level locks. 63046196Smckusick */ 63148015Smckusick /* ARGSUSED */ 63254439Smckusick spec_advlock(ap) 63354439Smckusick struct vop_advlock_args /* { 63454439Smckusick struct vnode *a_vp; 63554439Smckusick caddr_t a_id; 63654439Smckusick int a_op; 63754439Smckusick struct flock *a_fl; 63854439Smckusick int a_flags; 63954439Smckusick } */ *ap; 64046196Smckusick { 64146196Smckusick 64246196Smckusick return (EOPNOTSUPP); 64346196Smckusick } 64446196Smckusick 64546196Smckusick /* 64639507Smckusick * Special device failed operation 64737486Smckusick */ 64839507Smckusick spec_ebadf() 64939507Smckusick { 65039507Smckusick 65139507Smckusick return (EBADF); 65239507Smckusick } 65339507Smckusick 65439507Smckusick /* 65539507Smckusick * Special device bad operation 65639507Smckusick */ 65739446Smckusick spec_badop() 65837486Smckusick { 65937486Smckusick 66039446Smckusick panic("spec_badop called"); 66139292Smckusick /* NOTREACHED */ 66237486Smckusick } 663