137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*59486Smckusick * @(#)spec_vnops.c 7.53 (Berkeley) 04/28/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 */ 4153542Sheideman { &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 */ 4653542Sheideman { &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 */ 5053542Sheideman { &vop_mmap_desc, spec_mmap }, /* mmap */ 5153542Sheideman { &vop_fsync_desc, spec_fsync }, /* fsync */ 5253542Sheideman { &vop_seek_desc, spec_seek }, /* seek */ 5353542Sheideman { &vop_remove_desc, spec_remove }, /* remove */ 5453542Sheideman { &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 */ 6453542Sheideman { &vop_lock_desc, spec_lock }, /* lock */ 6553542Sheideman { &vop_unlock_desc, spec_unlock }, /* unlock */ 6653542Sheideman { &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 */ 7053542Sheideman { &vop_advlock_desc, spec_advlock }, /* advlock */ 7153542Sheideman { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 7253542Sheideman { &vop_valloc_desc, spec_valloc }, /* valloc */ 7353542Sheideman { &vop_vfree_desc, spec_vfree }, /* vfree */ 7453542Sheideman { &vop_truncate_desc, spec_truncate }, /* truncate */ 7553542Sheideman { &vop_update_desc, spec_update }, /* update */ 7653542Sheideman { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 7753542Sheideman { (struct vnodeop_desc*)NULL, (int(*)())NULL } 7837486Smckusick }; 7953542Sheideman struct vnodeopv_desc spec_vnodeop_opv_desc = 8053542Sheideman { &spec_vnodeop_p, spec_vnodeop_entries }; 8137486Smckusick 8237486Smckusick /* 8339292Smckusick * Trivial lookup routine that always fails. 8439292Smckusick */ 8552320Sheideman int 8654439Smckusick spec_lookup(ap) 8754439Smckusick struct vop_lookup_args /* { 8854439Smckusick struct vnode *a_dvp; 8954439Smckusick struct vnode **a_vpp; 9054439Smckusick struct componentname *a_cnp; 9154439Smckusick } */ *ap; 9239292Smckusick { 9339292Smckusick 9453597Sheideman *ap->a_vpp = NULL; 9539292Smckusick return (ENOTDIR); 9639292Smckusick } 9739292Smckusick 9839292Smckusick /* 99*59486Smckusick * Open a special file. 10037486Smckusick */ 10137725Smckusick /* ARGSUSED */ 10254439Smckusick spec_open(ap) 10354439Smckusick struct vop_open_args /* { 10454439Smckusick struct vnode *a_vp; 10554439Smckusick int a_mode; 10654439Smckusick struct ucred *a_cred; 10754439Smckusick struct proc *a_p; 10854439Smckusick } */ *ap; 10937486Smckusick { 110*59486Smckusick struct vnode *bvp, *vp = ap->a_vp; 111*59486Smckusick dev_t bdev, dev = (dev_t)vp->v_rdev; 11237486Smckusick register int maj = major(dev); 11340375Smckusick int error; 11437486Smckusick 115*59486Smckusick /* 116*59486Smckusick * Don't allow open if fs is mounted -nodev. 117*59486Smckusick */ 11853863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 11939365Smckusick return (ENXIO); 12039365Smckusick 12153863Sheideman switch (vp->v_type) { 12237486Smckusick 12337486Smckusick case VCHR: 12437486Smckusick if ((u_int)maj >= nchrdev) 12537486Smckusick return (ENXIO); 126*59486Smckusick if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 127*59486Smckusick /* 128*59486Smckusick * When running in very secure mode, do not allow 129*59486Smckusick * opens for writing of any disk character devices. 130*59486Smckusick */ 131*59486Smckusick if (securelevel >= 2 && isdisk(dev, VCHR)) 132*59486Smckusick return (EPERM); 133*59486Smckusick /* 134*59486Smckusick * When running in secure mode, do not allow opens 135*59486Smckusick * for writing of /dev/mem, /dev/kmem, or character 136*59486Smckusick * devices whose corresponding block devices are 137*59486Smckusick * currently mounted. 138*59486Smckusick */ 139*59486Smckusick if (securelevel >= 1) { 140*59486Smckusick if ((bdev = chrtoblk(dev)) != NODEV && 141*59486Smckusick vfinddev(bdev, VBLK, &bvp) && 142*59486Smckusick bvp->v_usecount > 0 && 143*59486Smckusick (error = ufs_mountedon(bvp))) 144*59486Smckusick return (error); 145*59486Smckusick if (iskmemdev(dev)) 146*59486Smckusick return (EPERM); 147*59486Smckusick } 148*59486Smckusick } 14953863Sheideman VOP_UNLOCK(vp); 15053597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 15153863Sheideman VOP_LOCK(vp); 15249944Smckusick return (error); 15337486Smckusick 15437486Smckusick case VBLK: 15537486Smckusick if ((u_int)maj >= nblkdev) 15637486Smckusick return (ENXIO); 157*59486Smckusick /* 158*59486Smckusick * When running in very secure mode, do not allow 159*59486Smckusick * opens for writing of any disk block devices. 160*59486Smckusick */ 161*59486Smckusick if (securelevel >= 2 && ap->a_cred != FSCRED && 162*59486Smckusick (ap->a_mode & FWRITE) && isdisk(dev, VBLK)) 163*59486Smckusick return (EPERM); 164*59486Smckusick /* 165*59486Smckusick * Do not allow opens of block devices that are 166*59486Smckusick * currently mounted. 167*59486Smckusick */ 16853863Sheideman if (error = ufs_mountedon(vp)) 16940375Smckusick return (error); 17053597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 17137486Smckusick } 17237486Smckusick return (0); 17337486Smckusick } 17437486Smckusick 17537486Smckusick /* 17637486Smckusick * Vnode op for read 17737486Smckusick */ 17841961Smckusick /* ARGSUSED */ 17954439Smckusick spec_read(ap) 18054439Smckusick struct vop_read_args /* { 18154439Smckusick struct vnode *a_vp; 18254439Smckusick struct uio *a_uio; 18354439Smckusick int a_ioflag; 18454439Smckusick struct ucred *a_cred; 18554439Smckusick } */ *ap; 18637486Smckusick { 18753863Sheideman register struct vnode *vp = ap->a_vp; 18853863Sheideman register struct uio *uio = ap->a_uio; 18953863Sheideman struct proc *p = uio->uio_procp; 19039614Smckusick struct buf *bp; 19152321Smckusick daddr_t bn, nextbn; 19239614Smckusick long bsize, bscale; 19339614Smckusick struct partinfo dpart; 19439614Smckusick register int n, on; 19539614Smckusick int error = 0; 19637486Smckusick 19748015Smckusick #ifdef DIAGNOSTIC 19853863Sheideman if (uio->uio_rw != UIO_READ) 19939588Smckusick panic("spec_read mode"); 20053863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 20148015Smckusick panic("spec_read proc"); 20248015Smckusick #endif 20353863Sheideman if (uio->uio_resid == 0) 20439588Smckusick return (0); 20539588Smckusick 20653863Sheideman switch (vp->v_type) { 20739588Smckusick 20839588Smckusick case VCHR: 20953863Sheideman VOP_UNLOCK(vp); 21053863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 21153863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 21253863Sheideman VOP_LOCK(vp); 21339588Smckusick return (error); 21439588Smckusick 21539588Smckusick case VBLK: 21653863Sheideman if (uio->uio_offset < 0) 21739588Smckusick return (EINVAL); 21839614Smckusick bsize = BLKDEV_IOSIZE; 21953863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 22047540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 22139614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 22239614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 22339614Smckusick bsize = dpart.part->p_frag * 22439614Smckusick dpart.part->p_fsize; 22539614Smckusick } 22639614Smckusick bscale = bsize / DEV_BSIZE; 22739614Smckusick do { 22853863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 22953863Sheideman on = uio->uio_offset % bsize; 23055059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 23153863Sheideman if (vp->v_lastr + bscale == bn) { 23252321Smckusick nextbn = bn + bscale; 23353863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 23452321Smckusick (int *)&bsize, 1, NOCRED, &bp); 23552321Smckusick } else 23653863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 23753863Sheideman vp->v_lastr = bn; 23855059Spendry n = min(n, bsize - bp->b_resid); 23939614Smckusick if (error) { 24039614Smckusick brelse(bp); 24139614Smckusick return (error); 24239614Smckusick } 24353863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 24439614Smckusick if (n + on == bsize) 24539614Smckusick bp->b_flags |= B_AGE; 24639614Smckusick brelse(bp); 24753863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 24839614Smckusick return (error); 24939588Smckusick 25039588Smckusick default: 25139588Smckusick panic("spec_read type"); 25239588Smckusick } 25339588Smckusick /* NOTREACHED */ 25437486Smckusick } 25537486Smckusick 25637486Smckusick /* 25737486Smckusick * Vnode op for write 25837486Smckusick */ 25941961Smckusick /* ARGSUSED */ 26054439Smckusick spec_write(ap) 26154439Smckusick struct vop_write_args /* { 26254439Smckusick struct vnode *a_vp; 26354439Smckusick struct uio *a_uio; 26454439Smckusick int a_ioflag; 26554439Smckusick struct ucred *a_cred; 26654439Smckusick } */ *ap; 26737486Smckusick { 26853863Sheideman register struct vnode *vp = ap->a_vp; 26953863Sheideman register struct uio *uio = ap->a_uio; 27053863Sheideman struct proc *p = uio->uio_procp; 27139614Smckusick struct buf *bp; 27239614Smckusick daddr_t bn; 27339614Smckusick int bsize, blkmask; 27439614Smckusick struct partinfo dpart; 27545731Smckusick register int n, on; 27645731Smckusick int error = 0; 27737486Smckusick 27848015Smckusick #ifdef DIAGNOSTIC 27953863Sheideman if (uio->uio_rw != UIO_WRITE) 28039588Smckusick panic("spec_write mode"); 28153863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 28248015Smckusick panic("spec_write proc"); 28348015Smckusick #endif 28439588Smckusick 28553863Sheideman switch (vp->v_type) { 28639588Smckusick 28739588Smckusick case VCHR: 28853863Sheideman VOP_UNLOCK(vp); 28953863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 29053863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 29153863Sheideman VOP_LOCK(vp); 29239588Smckusick return (error); 29339588Smckusick 29439588Smckusick case VBLK: 29553863Sheideman if (uio->uio_resid == 0) 29639588Smckusick return (0); 29753863Sheideman if (uio->uio_offset < 0) 29839588Smckusick return (EINVAL); 29939614Smckusick bsize = BLKDEV_IOSIZE; 30053863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 30147540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 30239614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 30339614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 30439614Smckusick bsize = dpart.part->p_frag * 30539614Smckusick dpart.part->p_fsize; 30639614Smckusick } 30739614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 30839614Smckusick do { 30953863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 31053863Sheideman on = uio->uio_offset % bsize; 31155059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 31239614Smckusick if (n == bsize) 31357798Smckusick bp = getblk(vp, bn, bsize, 0, 0); 31439614Smckusick else 31553863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 31655059Spendry n = min(n, bsize - bp->b_resid); 31739614Smckusick if (error) { 31839614Smckusick brelse(bp); 31939614Smckusick return (error); 32039614Smckusick } 32153863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 32239614Smckusick if (n + on == bsize) { 32339614Smckusick bp->b_flags |= B_AGE; 32439614Smckusick bawrite(bp); 32539614Smckusick } else 32639614Smckusick bdwrite(bp); 32753863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 32839614Smckusick return (error); 32939588Smckusick 33039588Smckusick default: 33139588Smckusick panic("spec_write type"); 33239588Smckusick } 33339588Smckusick /* NOTREACHED */ 33437486Smckusick } 33537486Smckusick 33637486Smckusick /* 33737486Smckusick * Device ioctl operation. 33837486Smckusick */ 33937725Smckusick /* ARGSUSED */ 34054439Smckusick spec_ioctl(ap) 34154439Smckusick struct vop_ioctl_args /* { 34254439Smckusick struct vnode *a_vp; 34354439Smckusick int a_command; 34454439Smckusick caddr_t a_data; 34554439Smckusick int a_fflag; 34654439Smckusick struct ucred *a_cred; 34754439Smckusick struct proc *a_p; 34854439Smckusick } */ *ap; 34937486Smckusick { 35053597Sheideman dev_t dev = ap->a_vp->v_rdev; 35137486Smckusick 35253597Sheideman switch (ap->a_vp->v_type) { 35337486Smckusick 35437486Smckusick case VCHR: 35553597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 35653597Sheideman ap->a_fflag, ap->a_p)); 35737486Smckusick 35837486Smckusick case VBLK: 35953597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 36039666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 36139666Smckusick return (0); 36239666Smckusick else 36339666Smckusick return (1); 36453597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 36553597Sheideman ap->a_fflag, ap->a_p)); 36637486Smckusick 36737486Smckusick default: 36839446Smckusick panic("spec_ioctl"); 36937486Smckusick /* NOTREACHED */ 37037486Smckusick } 37137486Smckusick } 37237486Smckusick 37337725Smckusick /* ARGSUSED */ 37454439Smckusick spec_select(ap) 37554439Smckusick struct vop_select_args /* { 37654439Smckusick struct vnode *a_vp; 37754439Smckusick int a_which; 37854439Smckusick int a_fflags; 37954439Smckusick struct ucred *a_cred; 38054439Smckusick struct proc *a_p; 38154439Smckusick } */ *ap; 38237486Smckusick { 38337486Smckusick register dev_t dev; 38437486Smckusick 38553597Sheideman switch (ap->a_vp->v_type) { 38637486Smckusick 38737486Smckusick default: 38837486Smckusick return (1); /* XXX */ 38937486Smckusick 39037486Smckusick case VCHR: 39153597Sheideman dev = ap->a_vp->v_rdev; 39253597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 39337486Smckusick } 39437486Smckusick } 39554439Smckusick /* 39654439Smckusick * Synch buffers associated with a block device 39754439Smckusick */ 39854439Smckusick /* ARGSUSED */ 39954439Smckusick int 40054439Smckusick spec_fsync(ap) 40154439Smckusick struct vop_fsync_args /* { 40254439Smckusick struct vnode *a_vp; 40354439Smckusick struct ucred *a_cred; 40454439Smckusick int a_waitfor; 40554439Smckusick struct proc *a_p; 40654439Smckusick } */ *ap; 40754439Smckusick { 40854439Smckusick register struct vnode *vp = ap->a_vp; 40954439Smckusick register struct buf *bp; 41054439Smckusick struct buf *nbp; 41156548Smckusick int s; 41237486Smckusick 41354439Smckusick if (vp->v_type == VCHR) 41454439Smckusick return (0); 41554439Smckusick /* 41654439Smckusick * Flush all dirty buffers associated with a block device. 41754439Smckusick */ 41854439Smckusick loop: 41954439Smckusick s = splbio(); 42056471Smckusick for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) { 42156471Smckusick nbp = bp->b_vnbufs.qe_next; 42254439Smckusick if ((bp->b_flags & B_BUSY)) 42354439Smckusick continue; 42454439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 42554439Smckusick panic("spec_fsync: not dirty"); 42654439Smckusick bremfree(bp); 42754439Smckusick bp->b_flags |= B_BUSY; 42854439Smckusick splx(s); 42956548Smckusick bawrite(bp); 43054439Smckusick goto loop; 43154439Smckusick } 43254439Smckusick if (ap->a_waitfor == MNT_WAIT) { 43354439Smckusick while (vp->v_numoutput) { 43454439Smckusick vp->v_flag |= VBWAIT; 43554439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 43654439Smckusick } 43754439Smckusick #ifdef DIAGNOSTIC 43856471Smckusick if (vp->v_dirtyblkhd.le_next) { 43954439Smckusick vprint("spec_fsync: dirty", vp); 44054439Smckusick goto loop; 44154439Smckusick } 44254439Smckusick #endif 44354439Smckusick } 44454439Smckusick splx(s); 44556548Smckusick return (0); 44654439Smckusick } 44754439Smckusick 44837486Smckusick /* 44937486Smckusick * Just call the device strategy routine 45037486Smckusick */ 45154439Smckusick spec_strategy(ap) 45254439Smckusick struct vop_strategy_args /* { 45354439Smckusick struct buf *a_bp; 45454439Smckusick } */ *ap; 45537486Smckusick { 45639666Smckusick 45753597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 45837486Smckusick return (0); 45937486Smckusick } 46037486Smckusick 46139432Smckusick /* 46239666Smckusick * This is a noop, simply returning what one has been given. 46339666Smckusick */ 46454439Smckusick spec_bmap(ap) 46554439Smckusick struct vop_bmap_args /* { 46654439Smckusick struct vnode *a_vp; 46754439Smckusick daddr_t a_bn; 46854439Smckusick struct vnode **a_vpp; 46954439Smckusick daddr_t *a_bnp; 47054439Smckusick } */ *ap; 47139666Smckusick { 47239666Smckusick 47353597Sheideman if (ap->a_vpp != NULL) 47453597Sheideman *ap->a_vpp = ap->a_vp; 47553597Sheideman if (ap->a_bnp != NULL) 47653597Sheideman *ap->a_bnp = ap->a_bn; 47739666Smckusick return (0); 47839666Smckusick } 47939666Smckusick 48039666Smckusick /* 48139432Smckusick * At the moment we do not do any locking. 48239432Smckusick */ 48339489Smckusick /* ARGSUSED */ 48454439Smckusick spec_lock(ap) 48554439Smckusick struct vop_lock_args /* { 48654439Smckusick struct vnode *a_vp; 48754439Smckusick } */ *ap; 48837486Smckusick { 48937486Smckusick 49037486Smckusick return (0); 49137486Smckusick } 49237486Smckusick 49339489Smckusick /* ARGSUSED */ 49454439Smckusick spec_unlock(ap) 49554439Smckusick struct vop_unlock_args /* { 49654439Smckusick struct vnode *a_vp; 49754439Smckusick } */ *ap; 49837486Smckusick { 49937486Smckusick 50037486Smckusick return (0); 50137486Smckusick } 50237486Smckusick 50337486Smckusick /* 50437486Smckusick * Device close routine 50537486Smckusick */ 50637725Smckusick /* ARGSUSED */ 50754439Smckusick spec_close(ap) 50854439Smckusick struct vop_close_args /* { 50954439Smckusick struct vnode *a_vp; 51054439Smckusick int a_fflag; 51154439Smckusick struct ucred *a_cred; 51254439Smckusick struct proc *a_p; 51354439Smckusick } */ *ap; 51437486Smckusick { 51553863Sheideman register struct vnode *vp = ap->a_vp; 51653863Sheideman dev_t dev = vp->v_rdev; 51749273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 51854439Smckusick int mode, error; 51937486Smckusick 52053863Sheideman switch (vp->v_type) { 52137725Smckusick 52237725Smckusick case VCHR: 52339485Smckusick /* 52439485Smckusick * If the vnode is locked, then we are in the midst 52539485Smckusick * of forcably closing the device, otherwise we only 52639485Smckusick * close on last reference. 52739485Smckusick */ 52853863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 52937725Smckusick return (0); 53049273Skarels devclose = cdevsw[major(dev)].d_close; 53139432Smckusick mode = S_IFCHR; 53237725Smckusick break; 53337725Smckusick 53437725Smckusick case VBLK: 53537725Smckusick /* 53637725Smckusick * On last close of a block device (that isn't mounted) 53737725Smckusick * we must invalidate any in core blocks, so that 53837725Smckusick * we can, for instance, change floppy disks. 53937725Smckusick */ 54057798Smckusick if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0)) 54154439Smckusick return (error); 54237725Smckusick /* 54339485Smckusick * We do not want to really close the device if it 54439485Smckusick * is still in use unless we are trying to close it 54539485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 54639630Smckusick * holds a reference to the vnode, and because we mark 54739630Smckusick * any other vnodes that alias this device, when the 54839630Smckusick * sum of the reference counts on all the aliased 54939630Smckusick * vnodes descends to one, we are on last close. 55037725Smckusick */ 55153863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 55237725Smckusick return (0); 55349273Skarels devclose = bdevsw[major(dev)].d_close; 55439432Smckusick mode = S_IFBLK; 55537725Smckusick break; 55637725Smckusick 55737725Smckusick default: 55839446Smckusick panic("spec_close: not special"); 55937725Smckusick } 56037725Smckusick 56153597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 56237486Smckusick } 56337486Smckusick 56437486Smckusick /* 56539666Smckusick * Print out the contents of a special device vnode. 56639666Smckusick */ 56754439Smckusick spec_print(ap) 56854439Smckusick struct vop_print_args /* { 56954439Smckusick struct vnode *a_vp; 57054439Smckusick } */ *ap; 57139666Smckusick { 57239666Smckusick 57353597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 57453597Sheideman minor(ap->a_vp->v_rdev)); 57539666Smckusick } 57639666Smckusick 57739666Smckusick /* 57846196Smckusick * Special device advisory byte-level locks. 57946196Smckusick */ 58048015Smckusick /* ARGSUSED */ 58154439Smckusick spec_advlock(ap) 58254439Smckusick struct vop_advlock_args /* { 58354439Smckusick struct vnode *a_vp; 58454439Smckusick caddr_t a_id; 58554439Smckusick int a_op; 58654439Smckusick struct flock *a_fl; 58754439Smckusick int a_flags; 58854439Smckusick } */ *ap; 58946196Smckusick { 59046196Smckusick 59146196Smckusick return (EOPNOTSUPP); 59246196Smckusick } 59346196Smckusick 59446196Smckusick /* 59539507Smckusick * Special device failed operation 59637486Smckusick */ 59739507Smckusick spec_ebadf() 59839507Smckusick { 59939507Smckusick 60039507Smckusick return (EBADF); 60139507Smckusick } 60239507Smckusick 60339507Smckusick /* 60439507Smckusick * Special device bad operation 60539507Smckusick */ 60639446Smckusick spec_badop() 60737486Smckusick { 60837486Smckusick 60939446Smckusick panic("spec_badop called"); 61039292Smckusick /* NOTREACHED */ 61137486Smckusick } 612