137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*56548Smckusick * @(#)spec_vnops.c 7.51 (Berkeley) 10/12/92 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 /* 9949273Skarels * Open a special file: Don't allow open if fs is mounted -nodev, 10049273Skarels * and don't allow opens of block devices that are currently mounted. 10149273Skarels * Otherwise, call device driver open function. 10237486Smckusick */ 10337725Smckusick /* ARGSUSED */ 10454439Smckusick spec_open(ap) 10554439Smckusick struct vop_open_args /* { 10654439Smckusick struct vnode *a_vp; 10754439Smckusick int a_mode; 10854439Smckusick struct ucred *a_cred; 10954439Smckusick struct proc *a_p; 11054439Smckusick } */ *ap; 11137486Smckusick { 11253863Sheideman register struct vnode *vp = ap->a_vp; 11353863Sheideman dev_t dev = (dev_t)vp->v_rdev; 11437486Smckusick register int maj = major(dev); 11540375Smckusick int error; 11637486Smckusick 11753863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 11839365Smckusick return (ENXIO); 11939365Smckusick 12053863Sheideman switch (vp->v_type) { 12137486Smckusick 12237486Smckusick case VCHR: 12337486Smckusick if ((u_int)maj >= nchrdev) 12437486Smckusick return (ENXIO); 12553863Sheideman VOP_UNLOCK(vp); 12653597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 12753863Sheideman VOP_LOCK(vp); 12849944Smckusick return (error); 12937486Smckusick 13037486Smckusick case VBLK: 13137486Smckusick if ((u_int)maj >= nblkdev) 13237486Smckusick return (ENXIO); 13353863Sheideman if (error = ufs_mountedon(vp)) 13440375Smckusick return (error); 13553597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 13637486Smckusick } 13737486Smckusick return (0); 13837486Smckusick } 13937486Smckusick 14037486Smckusick /* 14137486Smckusick * Vnode op for read 14237486Smckusick */ 14341961Smckusick /* ARGSUSED */ 14454439Smckusick spec_read(ap) 14554439Smckusick struct vop_read_args /* { 14654439Smckusick struct vnode *a_vp; 14754439Smckusick struct uio *a_uio; 14854439Smckusick int a_ioflag; 14954439Smckusick struct ucred *a_cred; 15054439Smckusick } */ *ap; 15137486Smckusick { 15253863Sheideman register struct vnode *vp = ap->a_vp; 15353863Sheideman register struct uio *uio = ap->a_uio; 15453863Sheideman struct proc *p = uio->uio_procp; 15539614Smckusick struct buf *bp; 15652321Smckusick daddr_t bn, nextbn; 15739614Smckusick long bsize, bscale; 15839614Smckusick struct partinfo dpart; 15939614Smckusick register int n, on; 16039614Smckusick int error = 0; 16137486Smckusick 16248015Smckusick #ifdef DIAGNOSTIC 16353863Sheideman if (uio->uio_rw != UIO_READ) 16439588Smckusick panic("spec_read mode"); 16553863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 16648015Smckusick panic("spec_read proc"); 16748015Smckusick #endif 16853863Sheideman if (uio->uio_resid == 0) 16939588Smckusick return (0); 17039588Smckusick 17153863Sheideman switch (vp->v_type) { 17239588Smckusick 17339588Smckusick case VCHR: 17453863Sheideman VOP_UNLOCK(vp); 17553863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 17653863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 17753863Sheideman VOP_LOCK(vp); 17839588Smckusick return (error); 17939588Smckusick 18039588Smckusick case VBLK: 18153863Sheideman if (uio->uio_offset < 0) 18239588Smckusick return (EINVAL); 18339614Smckusick bsize = BLKDEV_IOSIZE; 18453863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 18547540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 18639614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 18739614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 18839614Smckusick bsize = dpart.part->p_frag * 18939614Smckusick dpart.part->p_fsize; 19039614Smckusick } 19139614Smckusick bscale = bsize / DEV_BSIZE; 19239614Smckusick do { 19353863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 19453863Sheideman on = uio->uio_offset % bsize; 19555059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 19653863Sheideman if (vp->v_lastr + bscale == bn) { 19752321Smckusick nextbn = bn + bscale; 19853863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 19952321Smckusick (int *)&bsize, 1, NOCRED, &bp); 20052321Smckusick } else 20153863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 20253863Sheideman vp->v_lastr = bn; 20355059Spendry n = min(n, bsize - bp->b_resid); 20439614Smckusick if (error) { 20539614Smckusick brelse(bp); 20639614Smckusick return (error); 20739614Smckusick } 20853863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 20939614Smckusick if (n + on == bsize) 21039614Smckusick bp->b_flags |= B_AGE; 21139614Smckusick brelse(bp); 21253863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 21339614Smckusick return (error); 21439588Smckusick 21539588Smckusick default: 21639588Smckusick panic("spec_read type"); 21739588Smckusick } 21839588Smckusick /* NOTREACHED */ 21937486Smckusick } 22037486Smckusick 22137486Smckusick /* 22237486Smckusick * Vnode op for write 22337486Smckusick */ 22441961Smckusick /* ARGSUSED */ 22554439Smckusick spec_write(ap) 22654439Smckusick struct vop_write_args /* { 22754439Smckusick struct vnode *a_vp; 22854439Smckusick struct uio *a_uio; 22954439Smckusick int a_ioflag; 23054439Smckusick struct ucred *a_cred; 23154439Smckusick } */ *ap; 23237486Smckusick { 23353863Sheideman register struct vnode *vp = ap->a_vp; 23453863Sheideman register struct uio *uio = ap->a_uio; 23553863Sheideman struct proc *p = uio->uio_procp; 23639614Smckusick struct buf *bp; 23739614Smckusick daddr_t bn; 23839614Smckusick int bsize, blkmask; 23939614Smckusick struct partinfo dpart; 24045731Smckusick register int n, on; 24145731Smckusick int error = 0; 24237486Smckusick 24348015Smckusick #ifdef DIAGNOSTIC 24453863Sheideman if (uio->uio_rw != UIO_WRITE) 24539588Smckusick panic("spec_write mode"); 24653863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 24748015Smckusick panic("spec_write proc"); 24848015Smckusick #endif 24939588Smckusick 25053863Sheideman switch (vp->v_type) { 25139588Smckusick 25239588Smckusick case VCHR: 25353863Sheideman VOP_UNLOCK(vp); 25453863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 25553863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 25653863Sheideman VOP_LOCK(vp); 25739588Smckusick return (error); 25839588Smckusick 25939588Smckusick case VBLK: 26053863Sheideman if (uio->uio_resid == 0) 26139588Smckusick return (0); 26253863Sheideman if (uio->uio_offset < 0) 26339588Smckusick return (EINVAL); 26439614Smckusick bsize = BLKDEV_IOSIZE; 26553863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 26647540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 26739614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 26839614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 26939614Smckusick bsize = dpart.part->p_frag * 27039614Smckusick dpart.part->p_fsize; 27139614Smckusick } 27239614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 27339614Smckusick do { 27453863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 27553863Sheideman on = uio->uio_offset % bsize; 27655059Spendry n = min((unsigned)(bsize - on), uio->uio_resid); 27739614Smckusick if (n == bsize) 27853863Sheideman bp = getblk(vp, bn, bsize); 27939614Smckusick else 28053863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 28155059Spendry n = min(n, bsize - bp->b_resid); 28239614Smckusick if (error) { 28339614Smckusick brelse(bp); 28439614Smckusick return (error); 28539614Smckusick } 28653863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 28739614Smckusick if (n + on == bsize) { 28839614Smckusick bp->b_flags |= B_AGE; 28939614Smckusick bawrite(bp); 29039614Smckusick } else 29139614Smckusick bdwrite(bp); 29253863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 29339614Smckusick return (error); 29439588Smckusick 29539588Smckusick default: 29639588Smckusick panic("spec_write type"); 29739588Smckusick } 29839588Smckusick /* NOTREACHED */ 29937486Smckusick } 30037486Smckusick 30137486Smckusick /* 30237486Smckusick * Device ioctl operation. 30337486Smckusick */ 30437725Smckusick /* ARGSUSED */ 30554439Smckusick spec_ioctl(ap) 30654439Smckusick struct vop_ioctl_args /* { 30754439Smckusick struct vnode *a_vp; 30854439Smckusick int a_command; 30954439Smckusick caddr_t a_data; 31054439Smckusick int a_fflag; 31154439Smckusick struct ucred *a_cred; 31254439Smckusick struct proc *a_p; 31354439Smckusick } */ *ap; 31437486Smckusick { 31553597Sheideman dev_t dev = ap->a_vp->v_rdev; 31637486Smckusick 31753597Sheideman switch (ap->a_vp->v_type) { 31837486Smckusick 31937486Smckusick case VCHR: 32053597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 32153597Sheideman ap->a_fflag, ap->a_p)); 32237486Smckusick 32337486Smckusick case VBLK: 32453597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 32539666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 32639666Smckusick return (0); 32739666Smckusick else 32839666Smckusick return (1); 32953597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 33053597Sheideman ap->a_fflag, ap->a_p)); 33137486Smckusick 33237486Smckusick default: 33339446Smckusick panic("spec_ioctl"); 33437486Smckusick /* NOTREACHED */ 33537486Smckusick } 33637486Smckusick } 33737486Smckusick 33837725Smckusick /* ARGSUSED */ 33954439Smckusick spec_select(ap) 34054439Smckusick struct vop_select_args /* { 34154439Smckusick struct vnode *a_vp; 34254439Smckusick int a_which; 34354439Smckusick int a_fflags; 34454439Smckusick struct ucred *a_cred; 34554439Smckusick struct proc *a_p; 34654439Smckusick } */ *ap; 34737486Smckusick { 34837486Smckusick register dev_t dev; 34937486Smckusick 35053597Sheideman switch (ap->a_vp->v_type) { 35137486Smckusick 35237486Smckusick default: 35337486Smckusick return (1); /* XXX */ 35437486Smckusick 35537486Smckusick case VCHR: 35653597Sheideman dev = ap->a_vp->v_rdev; 35753597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 35837486Smckusick } 35937486Smckusick } 36054439Smckusick /* 36154439Smckusick * Synch buffers associated with a block device 36254439Smckusick */ 36354439Smckusick /* ARGSUSED */ 36454439Smckusick int 36554439Smckusick spec_fsync(ap) 36654439Smckusick struct vop_fsync_args /* { 36754439Smckusick struct vnode *a_vp; 36854439Smckusick struct ucred *a_cred; 36954439Smckusick int a_waitfor; 37054439Smckusick struct proc *a_p; 37154439Smckusick } */ *ap; 37254439Smckusick { 37354439Smckusick register struct vnode *vp = ap->a_vp; 37454439Smckusick register struct buf *bp; 37554439Smckusick struct buf *nbp; 376*56548Smckusick int s; 37737486Smckusick 37854439Smckusick if (vp->v_type == VCHR) 37954439Smckusick return (0); 38054439Smckusick /* 38154439Smckusick * Flush all dirty buffers associated with a block device. 38254439Smckusick */ 38354439Smckusick loop: 38454439Smckusick s = splbio(); 38556471Smckusick for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) { 38656471Smckusick nbp = bp->b_vnbufs.qe_next; 38754439Smckusick if ((bp->b_flags & B_BUSY)) 38854439Smckusick continue; 38954439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 39054439Smckusick panic("spec_fsync: not dirty"); 39154439Smckusick bremfree(bp); 39254439Smckusick bp->b_flags |= B_BUSY; 39354439Smckusick splx(s); 394*56548Smckusick bawrite(bp); 39554439Smckusick goto loop; 39654439Smckusick } 39754439Smckusick if (ap->a_waitfor == MNT_WAIT) { 39854439Smckusick while (vp->v_numoutput) { 39954439Smckusick vp->v_flag |= VBWAIT; 40054439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 40154439Smckusick } 40254439Smckusick #ifdef DIAGNOSTIC 40356471Smckusick if (vp->v_dirtyblkhd.le_next) { 40454439Smckusick vprint("spec_fsync: dirty", vp); 40554439Smckusick goto loop; 40654439Smckusick } 40754439Smckusick #endif 40854439Smckusick } 40954439Smckusick splx(s); 410*56548Smckusick return (0); 41154439Smckusick } 41254439Smckusick 41337486Smckusick /* 41437486Smckusick * Just call the device strategy routine 41537486Smckusick */ 41654439Smckusick spec_strategy(ap) 41754439Smckusick struct vop_strategy_args /* { 41854439Smckusick struct buf *a_bp; 41954439Smckusick } */ *ap; 42037486Smckusick { 42139666Smckusick 42253597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 42337486Smckusick return (0); 42437486Smckusick } 42537486Smckusick 42639432Smckusick /* 42739666Smckusick * This is a noop, simply returning what one has been given. 42839666Smckusick */ 42954439Smckusick spec_bmap(ap) 43054439Smckusick struct vop_bmap_args /* { 43154439Smckusick struct vnode *a_vp; 43254439Smckusick daddr_t a_bn; 43354439Smckusick struct vnode **a_vpp; 43454439Smckusick daddr_t *a_bnp; 43554439Smckusick } */ *ap; 43639666Smckusick { 43739666Smckusick 43853597Sheideman if (ap->a_vpp != NULL) 43953597Sheideman *ap->a_vpp = ap->a_vp; 44053597Sheideman if (ap->a_bnp != NULL) 44153597Sheideman *ap->a_bnp = ap->a_bn; 44239666Smckusick return (0); 44339666Smckusick } 44439666Smckusick 44539666Smckusick /* 44639432Smckusick * At the moment we do not do any locking. 44739432Smckusick */ 44839489Smckusick /* ARGSUSED */ 44954439Smckusick spec_lock(ap) 45054439Smckusick struct vop_lock_args /* { 45154439Smckusick struct vnode *a_vp; 45254439Smckusick } */ *ap; 45337486Smckusick { 45437486Smckusick 45537486Smckusick return (0); 45637486Smckusick } 45737486Smckusick 45839489Smckusick /* ARGSUSED */ 45954439Smckusick spec_unlock(ap) 46054439Smckusick struct vop_unlock_args /* { 46154439Smckusick struct vnode *a_vp; 46254439Smckusick } */ *ap; 46337486Smckusick { 46437486Smckusick 46537486Smckusick return (0); 46637486Smckusick } 46737486Smckusick 46837486Smckusick /* 46937486Smckusick * Device close routine 47037486Smckusick */ 47137725Smckusick /* ARGSUSED */ 47254439Smckusick spec_close(ap) 47354439Smckusick struct vop_close_args /* { 47454439Smckusick struct vnode *a_vp; 47554439Smckusick int a_fflag; 47654439Smckusick struct ucred *a_cred; 47754439Smckusick struct proc *a_p; 47854439Smckusick } */ *ap; 47937486Smckusick { 48053863Sheideman register struct vnode *vp = ap->a_vp; 48153863Sheideman dev_t dev = vp->v_rdev; 48249273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 48354439Smckusick int mode, error; 48437486Smckusick 48553863Sheideman switch (vp->v_type) { 48637725Smckusick 48737725Smckusick case VCHR: 48839485Smckusick /* 48939485Smckusick * If the vnode is locked, then we are in the midst 49039485Smckusick * of forcably closing the device, otherwise we only 49139485Smckusick * close on last reference. 49239485Smckusick */ 49353863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 49437725Smckusick return (0); 49549273Skarels devclose = cdevsw[major(dev)].d_close; 49639432Smckusick mode = S_IFCHR; 49737725Smckusick break; 49837725Smckusick 49937725Smckusick case VBLK: 50037725Smckusick /* 50137725Smckusick * On last close of a block device (that isn't mounted) 50237725Smckusick * we must invalidate any in core blocks, so that 50337725Smckusick * we can, for instance, change floppy disks. 50437725Smckusick */ 50554439Smckusick if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p)) 50654439Smckusick return (error); 50737725Smckusick /* 50839485Smckusick * We do not want to really close the device if it 50939485Smckusick * is still in use unless we are trying to close it 51039485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 51139630Smckusick * holds a reference to the vnode, and because we mark 51239630Smckusick * any other vnodes that alias this device, when the 51339630Smckusick * sum of the reference counts on all the aliased 51439630Smckusick * vnodes descends to one, we are on last close. 51537725Smckusick */ 51653863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 51737725Smckusick return (0); 51849273Skarels devclose = bdevsw[major(dev)].d_close; 51939432Smckusick mode = S_IFBLK; 52037725Smckusick break; 52137725Smckusick 52237725Smckusick default: 52339446Smckusick panic("spec_close: not special"); 52437725Smckusick } 52537725Smckusick 52653597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 52737486Smckusick } 52837486Smckusick 52937486Smckusick /* 53039666Smckusick * Print out the contents of a special device vnode. 53139666Smckusick */ 53254439Smckusick spec_print(ap) 53354439Smckusick struct vop_print_args /* { 53454439Smckusick struct vnode *a_vp; 53554439Smckusick } */ *ap; 53639666Smckusick { 53739666Smckusick 53853597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 53953597Sheideman minor(ap->a_vp->v_rdev)); 54039666Smckusick } 54139666Smckusick 54239666Smckusick /* 54346196Smckusick * Special device advisory byte-level locks. 54446196Smckusick */ 54548015Smckusick /* ARGSUSED */ 54654439Smckusick spec_advlock(ap) 54754439Smckusick struct vop_advlock_args /* { 54854439Smckusick struct vnode *a_vp; 54954439Smckusick caddr_t a_id; 55054439Smckusick int a_op; 55154439Smckusick struct flock *a_fl; 55254439Smckusick int a_flags; 55354439Smckusick } */ *ap; 55446196Smckusick { 55546196Smckusick 55646196Smckusick return (EOPNOTSUPP); 55746196Smckusick } 55846196Smckusick 55946196Smckusick /* 56039507Smckusick * Special device failed operation 56137486Smckusick */ 56239507Smckusick spec_ebadf() 56339507Smckusick { 56439507Smckusick 56539507Smckusick return (EBADF); 56639507Smckusick } 56739507Smckusick 56839507Smckusick /* 56939507Smckusick * Special device bad operation 57039507Smckusick */ 57139446Smckusick spec_badop() 57237486Smckusick { 57337486Smckusick 57439446Smckusick panic("spec_badop called"); 57539292Smckusick /* NOTREACHED */ 57637486Smckusick } 577