137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*54439Smckusick * @(#)spec_vnops.c 7.46 (Berkeley) 06/25/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/specdev.h> 2051457Sbostic #include <sys/stat.h> 2151457Sbostic #include <sys/errno.h> 2251457Sbostic #include <sys/ioctl.h> 2351457Sbostic #include <sys/file.h> 2451457Sbostic #include <sys/disklabel.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_vget_desc, spec_vget }, /* vget */ 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 87*54439Smckusick spec_lookup(ap) 88*54439Smckusick struct vop_lookup_args /* { 89*54439Smckusick struct vnode *a_dvp; 90*54439Smckusick struct vnode **a_vpp; 91*54439Smckusick struct componentname *a_cnp; 92*54439Smckusick } */ *ap; 9339292Smckusick { 9439292Smckusick 9553597Sheideman *ap->a_vpp = NULL; 9639292Smckusick return (ENOTDIR); 9739292Smckusick } 9839292Smckusick 9939292Smckusick /* 10049273Skarels * Open a special file: Don't allow open if fs is mounted -nodev, 10149273Skarels * and don't allow opens of block devices that are currently mounted. 10249273Skarels * Otherwise, call device driver open function. 10337486Smckusick */ 10437725Smckusick /* ARGSUSED */ 105*54439Smckusick spec_open(ap) 106*54439Smckusick struct vop_open_args /* { 107*54439Smckusick struct vnode *a_vp; 108*54439Smckusick int a_mode; 109*54439Smckusick struct ucred *a_cred; 110*54439Smckusick struct proc *a_p; 111*54439Smckusick } */ *ap; 11237486Smckusick { 11353542Sheideman USES_VOP_LOCK; 11453542Sheideman USES_VOP_UNLOCK; 11553863Sheideman register struct vnode *vp = ap->a_vp; 11653863Sheideman dev_t dev = (dev_t)vp->v_rdev; 11737486Smckusick register int maj = major(dev); 11840375Smckusick int error; 11937486Smckusick 12053863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 12139365Smckusick return (ENXIO); 12239365Smckusick 12353863Sheideman switch (vp->v_type) { 12437486Smckusick 12537486Smckusick case VCHR: 12637486Smckusick if ((u_int)maj >= nchrdev) 12737486Smckusick return (ENXIO); 12853863Sheideman VOP_UNLOCK(vp); 12953597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 13053863Sheideman VOP_LOCK(vp); 13149944Smckusick return (error); 13237486Smckusick 13337486Smckusick case VBLK: 13437486Smckusick if ((u_int)maj >= nblkdev) 13537486Smckusick return (ENXIO); 13653863Sheideman if (error = ufs_mountedon(vp)) 13740375Smckusick return (error); 13853597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 13937486Smckusick } 14037486Smckusick return (0); 14137486Smckusick } 14237486Smckusick 14337486Smckusick /* 14437486Smckusick * Vnode op for read 14537486Smckusick */ 14641961Smckusick /* ARGSUSED */ 147*54439Smckusick spec_read(ap) 148*54439Smckusick struct vop_read_args /* { 149*54439Smckusick struct vnode *a_vp; 150*54439Smckusick struct uio *a_uio; 151*54439Smckusick int a_ioflag; 152*54439Smckusick struct ucred *a_cred; 153*54439Smckusick } */ *ap; 15437486Smckusick { 15553542Sheideman USES_VOP_LOCK; 15653542Sheideman USES_VOP_UNLOCK; 15753863Sheideman register struct vnode *vp = ap->a_vp; 15853863Sheideman register struct uio *uio = ap->a_uio; 15953863Sheideman struct proc *p = uio->uio_procp; 16039614Smckusick struct buf *bp; 16152321Smckusick daddr_t bn, nextbn; 16239614Smckusick long bsize, bscale; 16339614Smckusick struct partinfo dpart; 16439614Smckusick register int n, on; 16539614Smckusick int error = 0; 16637486Smckusick 16748015Smckusick #ifdef DIAGNOSTIC 16853863Sheideman if (uio->uio_rw != UIO_READ) 16939588Smckusick panic("spec_read mode"); 17053863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 17148015Smckusick panic("spec_read proc"); 17248015Smckusick #endif 17353863Sheideman if (uio->uio_resid == 0) 17439588Smckusick return (0); 17539588Smckusick 17653863Sheideman switch (vp->v_type) { 17739588Smckusick 17839588Smckusick case VCHR: 17953863Sheideman VOP_UNLOCK(vp); 18053863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 18153863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 18253863Sheideman VOP_LOCK(vp); 18339588Smckusick return (error); 18439588Smckusick 18539588Smckusick case VBLK: 18653863Sheideman if (uio->uio_offset < 0) 18739588Smckusick return (EINVAL); 18839614Smckusick bsize = BLKDEV_IOSIZE; 18953863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 19047540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 19139614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 19239614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 19339614Smckusick bsize = dpart.part->p_frag * 19439614Smckusick dpart.part->p_fsize; 19539614Smckusick } 19639614Smckusick bscale = bsize / DEV_BSIZE; 19739614Smckusick do { 19853863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 19953863Sheideman on = uio->uio_offset % bsize; 20053863Sheideman n = MIN((unsigned)(bsize - on), uio->uio_resid); 20153863Sheideman if (vp->v_lastr + bscale == bn) { 20252321Smckusick nextbn = bn + bscale; 20353863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 20452321Smckusick (int *)&bsize, 1, NOCRED, &bp); 20552321Smckusick } else 20653863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 20753863Sheideman vp->v_lastr = bn; 20839614Smckusick n = MIN(n, bsize - bp->b_resid); 20939614Smckusick if (error) { 21039614Smckusick brelse(bp); 21139614Smckusick return (error); 21239614Smckusick } 21353863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 21439614Smckusick if (n + on == bsize) 21539614Smckusick bp->b_flags |= B_AGE; 21639614Smckusick brelse(bp); 21753863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 21839614Smckusick return (error); 21939588Smckusick 22039588Smckusick default: 22139588Smckusick panic("spec_read type"); 22239588Smckusick } 22339588Smckusick /* NOTREACHED */ 22437486Smckusick } 22537486Smckusick 22637486Smckusick /* 22737486Smckusick * Vnode op for write 22837486Smckusick */ 22941961Smckusick /* ARGSUSED */ 230*54439Smckusick spec_write(ap) 231*54439Smckusick struct vop_write_args /* { 232*54439Smckusick struct vnode *a_vp; 233*54439Smckusick struct uio *a_uio; 234*54439Smckusick int a_ioflag; 235*54439Smckusick struct ucred *a_cred; 236*54439Smckusick } */ *ap; 23737486Smckusick { 23853542Sheideman USES_VOP_LOCK; 23953542Sheideman USES_VOP_UNLOCK; 24053863Sheideman register struct vnode *vp = ap->a_vp; 24153863Sheideman register struct uio *uio = ap->a_uio; 24253863Sheideman struct proc *p = uio->uio_procp; 24339614Smckusick struct buf *bp; 24439614Smckusick daddr_t bn; 24539614Smckusick int bsize, blkmask; 24639614Smckusick struct partinfo dpart; 24745731Smckusick register int n, on; 24845731Smckusick int error = 0; 24937486Smckusick 25048015Smckusick #ifdef DIAGNOSTIC 25153863Sheideman if (uio->uio_rw != UIO_WRITE) 25239588Smckusick panic("spec_write mode"); 25353863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 25448015Smckusick panic("spec_write proc"); 25548015Smckusick #endif 25639588Smckusick 25753863Sheideman switch (vp->v_type) { 25839588Smckusick 25939588Smckusick case VCHR: 26053863Sheideman VOP_UNLOCK(vp); 26153863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 26253863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 26353863Sheideman VOP_LOCK(vp); 26439588Smckusick return (error); 26539588Smckusick 26639588Smckusick case VBLK: 26753863Sheideman if (uio->uio_resid == 0) 26839588Smckusick return (0); 26953863Sheideman if (uio->uio_offset < 0) 27039588Smckusick return (EINVAL); 27139614Smckusick bsize = BLKDEV_IOSIZE; 27253863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 27347540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 27439614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 27539614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 27639614Smckusick bsize = dpart.part->p_frag * 27739614Smckusick dpart.part->p_fsize; 27839614Smckusick } 27939614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 28039614Smckusick do { 28153863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 28253863Sheideman on = uio->uio_offset % bsize; 28353863Sheideman n = MIN((unsigned)(bsize - on), uio->uio_resid); 28439614Smckusick if (n == bsize) 28553863Sheideman bp = getblk(vp, bn, bsize); 28639614Smckusick else 28753863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 28839614Smckusick n = MIN(n, bsize - bp->b_resid); 28939614Smckusick if (error) { 29039614Smckusick brelse(bp); 29139614Smckusick return (error); 29239614Smckusick } 29353863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 29439614Smckusick if (n + on == bsize) { 29539614Smckusick bp->b_flags |= B_AGE; 29639614Smckusick bawrite(bp); 29739614Smckusick } else 29839614Smckusick bdwrite(bp); 29953863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 30039614Smckusick return (error); 30139588Smckusick 30239588Smckusick default: 30339588Smckusick panic("spec_write type"); 30439588Smckusick } 30539588Smckusick /* NOTREACHED */ 30637486Smckusick } 30737486Smckusick 30837486Smckusick /* 30937486Smckusick * Device ioctl operation. 31037486Smckusick */ 31137725Smckusick /* ARGSUSED */ 312*54439Smckusick spec_ioctl(ap) 313*54439Smckusick struct vop_ioctl_args /* { 314*54439Smckusick struct vnode *a_vp; 315*54439Smckusick int a_command; 316*54439Smckusick caddr_t a_data; 317*54439Smckusick int a_fflag; 318*54439Smckusick struct ucred *a_cred; 319*54439Smckusick struct proc *a_p; 320*54439Smckusick } */ *ap; 32137486Smckusick { 32253597Sheideman dev_t dev = ap->a_vp->v_rdev; 32337486Smckusick 32453597Sheideman switch (ap->a_vp->v_type) { 32537486Smckusick 32637486Smckusick case VCHR: 32753597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 32853597Sheideman ap->a_fflag, ap->a_p)); 32937486Smckusick 33037486Smckusick case VBLK: 33153597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 33239666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 33339666Smckusick return (0); 33439666Smckusick else 33539666Smckusick return (1); 33653597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 33753597Sheideman ap->a_fflag, ap->a_p)); 33837486Smckusick 33937486Smckusick default: 34039446Smckusick panic("spec_ioctl"); 34137486Smckusick /* NOTREACHED */ 34237486Smckusick } 34337486Smckusick } 34437486Smckusick 34537725Smckusick /* ARGSUSED */ 346*54439Smckusick spec_select(ap) 347*54439Smckusick struct vop_select_args /* { 348*54439Smckusick struct vnode *a_vp; 349*54439Smckusick int a_which; 350*54439Smckusick int a_fflags; 351*54439Smckusick struct ucred *a_cred; 352*54439Smckusick struct proc *a_p; 353*54439Smckusick } */ *ap; 35437486Smckusick { 35537486Smckusick register dev_t dev; 35637486Smckusick 35753597Sheideman switch (ap->a_vp->v_type) { 35837486Smckusick 35937486Smckusick default: 36037486Smckusick return (1); /* XXX */ 36137486Smckusick 36237486Smckusick case VCHR: 36353597Sheideman dev = ap->a_vp->v_rdev; 36453597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 36537486Smckusick } 36637486Smckusick } 367*54439Smckusick /* 368*54439Smckusick * Synch buffers associated with a block device 369*54439Smckusick */ 370*54439Smckusick /* ARGSUSED */ 371*54439Smckusick int 372*54439Smckusick spec_fsync(ap) 373*54439Smckusick struct vop_fsync_args /* { 374*54439Smckusick struct vnode *a_vp; 375*54439Smckusick struct ucred *a_cred; 376*54439Smckusick int a_waitfor; 377*54439Smckusick struct proc *a_p; 378*54439Smckusick } */ *ap; 379*54439Smckusick { 380*54439Smckusick register struct vnode *vp = ap->a_vp; 381*54439Smckusick register struct buf *bp; 382*54439Smckusick struct buf *nbp; 383*54439Smckusick int s, error, allerror = 0; 38437486Smckusick 385*54439Smckusick if (vp->v_type == VCHR) 386*54439Smckusick return (0); 387*54439Smckusick /* 388*54439Smckusick * Flush all dirty buffers associated with a block device. 389*54439Smckusick */ 390*54439Smckusick loop: 391*54439Smckusick s = splbio(); 392*54439Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 393*54439Smckusick nbp = bp->b_blockf; 394*54439Smckusick if ((bp->b_flags & B_BUSY)) 395*54439Smckusick continue; 396*54439Smckusick if ((bp->b_flags & B_DELWRI) == 0) 397*54439Smckusick panic("spec_fsync: not dirty"); 398*54439Smckusick bremfree(bp); 399*54439Smckusick bp->b_flags |= B_BUSY; 400*54439Smckusick splx(s); 401*54439Smckusick if (error = bawrite(bp)) 402*54439Smckusick allerror = error; 403*54439Smckusick goto loop; 404*54439Smckusick } 405*54439Smckusick if (ap->a_waitfor == MNT_WAIT) { 406*54439Smckusick while (vp->v_numoutput) { 407*54439Smckusick vp->v_flag |= VBWAIT; 408*54439Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 409*54439Smckusick } 410*54439Smckusick #ifdef DIAGNOSTIC 411*54439Smckusick if (vp->v_dirtyblkhd) { 412*54439Smckusick vprint("spec_fsync: dirty", vp); 413*54439Smckusick goto loop; 414*54439Smckusick } 415*54439Smckusick #endif 416*54439Smckusick } 417*54439Smckusick splx(s); 418*54439Smckusick return (allerror); 419*54439Smckusick } 420*54439Smckusick 42137486Smckusick /* 42237486Smckusick * Just call the device strategy routine 42337486Smckusick */ 424*54439Smckusick spec_strategy(ap) 425*54439Smckusick struct vop_strategy_args /* { 426*54439Smckusick struct buf *a_bp; 427*54439Smckusick } */ *ap; 42837486Smckusick { 42939666Smckusick 43053597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 43137486Smckusick return (0); 43237486Smckusick } 43337486Smckusick 43439432Smckusick /* 43539666Smckusick * This is a noop, simply returning what one has been given. 43639666Smckusick */ 437*54439Smckusick spec_bmap(ap) 438*54439Smckusick struct vop_bmap_args /* { 439*54439Smckusick struct vnode *a_vp; 440*54439Smckusick daddr_t a_bn; 441*54439Smckusick struct vnode **a_vpp; 442*54439Smckusick daddr_t *a_bnp; 443*54439Smckusick } */ *ap; 44439666Smckusick { 44539666Smckusick 44653597Sheideman if (ap->a_vpp != NULL) 44753597Sheideman *ap->a_vpp = ap->a_vp; 44853597Sheideman if (ap->a_bnp != NULL) 44953597Sheideman *ap->a_bnp = ap->a_bn; 45039666Smckusick return (0); 45139666Smckusick } 45239666Smckusick 45339666Smckusick /* 45439432Smckusick * At the moment we do not do any locking. 45539432Smckusick */ 45639489Smckusick /* ARGSUSED */ 457*54439Smckusick spec_lock(ap) 458*54439Smckusick struct vop_lock_args /* { 459*54439Smckusick struct vnode *a_vp; 460*54439Smckusick } */ *ap; 46137486Smckusick { 46237486Smckusick 46337486Smckusick return (0); 46437486Smckusick } 46537486Smckusick 46639489Smckusick /* ARGSUSED */ 467*54439Smckusick spec_unlock(ap) 468*54439Smckusick struct vop_unlock_args /* { 469*54439Smckusick struct vnode *a_vp; 470*54439Smckusick } */ *ap; 47137486Smckusick { 47237486Smckusick 47337486Smckusick return (0); 47437486Smckusick } 47537486Smckusick 47637486Smckusick /* 47737486Smckusick * Device close routine 47837486Smckusick */ 47937725Smckusick /* ARGSUSED */ 480*54439Smckusick spec_close(ap) 481*54439Smckusick struct vop_close_args /* { 482*54439Smckusick struct vnode *a_vp; 483*54439Smckusick int a_fflag; 484*54439Smckusick struct ucred *a_cred; 485*54439Smckusick struct proc *a_p; 486*54439Smckusick } */ *ap; 48737486Smckusick { 48853863Sheideman register struct vnode *vp = ap->a_vp; 48953863Sheideman dev_t dev = vp->v_rdev; 49049273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 491*54439Smckusick int mode, error; 49237486Smckusick 49353863Sheideman switch (vp->v_type) { 49437725Smckusick 49537725Smckusick case VCHR: 49639485Smckusick /* 49739485Smckusick * If the vnode is locked, then we are in the midst 49839485Smckusick * of forcably closing the device, otherwise we only 49939485Smckusick * close on last reference. 50039485Smckusick */ 50153863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 50237725Smckusick return (0); 50349273Skarels devclose = cdevsw[major(dev)].d_close; 50439432Smckusick mode = S_IFCHR; 50537725Smckusick break; 50637725Smckusick 50737725Smckusick case VBLK: 50837725Smckusick /* 50937725Smckusick * On last close of a block device (that isn't mounted) 51037725Smckusick * we must invalidate any in core blocks, so that 51137725Smckusick * we can, for instance, change floppy disks. 51237725Smckusick */ 513*54439Smckusick if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p)) 514*54439Smckusick return (error); 51537725Smckusick /* 51639485Smckusick * We do not want to really close the device if it 51739485Smckusick * is still in use unless we are trying to close it 51839485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 51939630Smckusick * holds a reference to the vnode, and because we mark 52039630Smckusick * any other vnodes that alias this device, when the 52139630Smckusick * sum of the reference counts on all the aliased 52239630Smckusick * vnodes descends to one, we are on last close. 52337725Smckusick */ 52453863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 52537725Smckusick return (0); 52649273Skarels devclose = bdevsw[major(dev)].d_close; 52739432Smckusick mode = S_IFBLK; 52837725Smckusick break; 52937725Smckusick 53037725Smckusick default: 53139446Smckusick panic("spec_close: not special"); 53237725Smckusick } 53337725Smckusick 53453597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 53537486Smckusick } 53637486Smckusick 53737486Smckusick /* 53839666Smckusick * Print out the contents of a special device vnode. 53939666Smckusick */ 540*54439Smckusick spec_print(ap) 541*54439Smckusick struct vop_print_args /* { 542*54439Smckusick struct vnode *a_vp; 543*54439Smckusick } */ *ap; 54439666Smckusick { 54539666Smckusick 54653597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 54753597Sheideman minor(ap->a_vp->v_rdev)); 54839666Smckusick } 54939666Smckusick 55039666Smckusick /* 55146196Smckusick * Special device advisory byte-level locks. 55246196Smckusick */ 55348015Smckusick /* ARGSUSED */ 554*54439Smckusick spec_advlock(ap) 555*54439Smckusick struct vop_advlock_args /* { 556*54439Smckusick struct vnode *a_vp; 557*54439Smckusick caddr_t a_id; 558*54439Smckusick int a_op; 559*54439Smckusick struct flock *a_fl; 560*54439Smckusick int a_flags; 561*54439Smckusick } */ *ap; 56246196Smckusick { 56346196Smckusick 56446196Smckusick return (EOPNOTSUPP); 56546196Smckusick } 56646196Smckusick 56746196Smckusick /* 56839507Smckusick * Special device failed operation 56937486Smckusick */ 57039507Smckusick spec_ebadf() 57139507Smckusick { 57239507Smckusick 57339507Smckusick return (EBADF); 57439507Smckusick } 57539507Smckusick 57639507Smckusick /* 57739507Smckusick * Special device bad operation 57839507Smckusick */ 57939446Smckusick spec_badop() 58037486Smckusick { 58137486Smckusick 58239446Smckusick panic("spec_badop called"); 58339292Smckusick /* NOTREACHED */ 58437486Smckusick } 585