137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*53863Sheideman * @(#)spec_vnops.c 7.45 (Berkeley) 06/04/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 8753542Sheideman spec_lookup (ap) 8853542Sheideman struct vop_lookup_args *ap; 8939292Smckusick { 9039292Smckusick 9153597Sheideman *ap->a_vpp = NULL; 9239292Smckusick return (ENOTDIR); 9339292Smckusick } 9439292Smckusick 9539292Smckusick /* 9649273Skarels * Open a special file: Don't allow open if fs is mounted -nodev, 9749273Skarels * and don't allow opens of block devices that are currently mounted. 9849273Skarels * Otherwise, call device driver open function. 9937486Smckusick */ 10037725Smckusick /* ARGSUSED */ 10153542Sheideman spec_open (ap) 10253542Sheideman struct vop_open_args *ap; 10337486Smckusick { 10453542Sheideman USES_VOP_LOCK; 10553542Sheideman USES_VOP_UNLOCK; 106*53863Sheideman register struct vnode *vp = ap->a_vp; 107*53863Sheideman dev_t dev = (dev_t)vp->v_rdev; 10837486Smckusick register int maj = major(dev); 10940375Smckusick int error; 11037486Smckusick 111*53863Sheideman if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 11239365Smckusick return (ENXIO); 11339365Smckusick 114*53863Sheideman switch (vp->v_type) { 11537486Smckusick 11637486Smckusick case VCHR: 11737486Smckusick if ((u_int)maj >= nchrdev) 11837486Smckusick return (ENXIO); 119*53863Sheideman VOP_UNLOCK(vp); 12053597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 121*53863Sheideman VOP_LOCK(vp); 12249944Smckusick return (error); 12337486Smckusick 12437486Smckusick case VBLK: 12537486Smckusick if ((u_int)maj >= nblkdev) 12637486Smckusick return (ENXIO); 127*53863Sheideman if (error = ufs_mountedon(vp)) 12840375Smckusick return (error); 12953597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 13037486Smckusick } 13137486Smckusick return (0); 13237486Smckusick } 13337486Smckusick 13437486Smckusick /* 13537486Smckusick * Vnode op for read 13637486Smckusick */ 13741961Smckusick /* ARGSUSED */ 13853542Sheideman spec_read (ap) 13953542Sheideman struct vop_read_args *ap; 14037486Smckusick { 14153542Sheideman USES_VOP_LOCK; 14253542Sheideman USES_VOP_UNLOCK; 143*53863Sheideman register struct vnode *vp = ap->a_vp; 144*53863Sheideman register struct uio *uio = ap->a_uio; 145*53863Sheideman struct proc *p = uio->uio_procp; 14639614Smckusick struct buf *bp; 14752321Smckusick daddr_t bn, nextbn; 14839614Smckusick long bsize, bscale; 14939614Smckusick struct partinfo dpart; 15039614Smckusick register int n, on; 15139614Smckusick int error = 0; 15237486Smckusick 15348015Smckusick #ifdef DIAGNOSTIC 154*53863Sheideman if (uio->uio_rw != UIO_READ) 15539588Smckusick panic("spec_read mode"); 156*53863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 15748015Smckusick panic("spec_read proc"); 15848015Smckusick #endif 159*53863Sheideman if (uio->uio_resid == 0) 16039588Smckusick return (0); 16139588Smckusick 162*53863Sheideman switch (vp->v_type) { 16339588Smckusick 16439588Smckusick case VCHR: 165*53863Sheideman VOP_UNLOCK(vp); 166*53863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_read) 167*53863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 168*53863Sheideman VOP_LOCK(vp); 16939588Smckusick return (error); 17039588Smckusick 17139588Smckusick case VBLK: 172*53863Sheideman if (uio->uio_offset < 0) 17339588Smckusick return (EINVAL); 17439614Smckusick bsize = BLKDEV_IOSIZE; 175*53863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17647540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 17739614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17839614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17939614Smckusick bsize = dpart.part->p_frag * 18039614Smckusick dpart.part->p_fsize; 18139614Smckusick } 18239614Smckusick bscale = bsize / DEV_BSIZE; 18339614Smckusick do { 184*53863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 185*53863Sheideman on = uio->uio_offset % bsize; 186*53863Sheideman n = MIN((unsigned)(bsize - on), uio->uio_resid); 187*53863Sheideman if (vp->v_lastr + bscale == bn) { 18852321Smckusick nextbn = bn + bscale; 189*53863Sheideman error = breadn(vp, bn, (int)bsize, &nextbn, 19052321Smckusick (int *)&bsize, 1, NOCRED, &bp); 19152321Smckusick } else 192*53863Sheideman error = bread(vp, bn, (int)bsize, NOCRED, &bp); 193*53863Sheideman vp->v_lastr = bn; 19439614Smckusick n = MIN(n, bsize - bp->b_resid); 19539614Smckusick if (error) { 19639614Smckusick brelse(bp); 19739614Smckusick return (error); 19839614Smckusick } 199*53863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 20039614Smckusick if (n + on == bsize) 20139614Smckusick bp->b_flags |= B_AGE; 20239614Smckusick brelse(bp); 203*53863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 20439614Smckusick return (error); 20539588Smckusick 20639588Smckusick default: 20739588Smckusick panic("spec_read type"); 20839588Smckusick } 20939588Smckusick /* NOTREACHED */ 21037486Smckusick } 21137486Smckusick 21237486Smckusick /* 21337486Smckusick * Vnode op for write 21437486Smckusick */ 21541961Smckusick /* ARGSUSED */ 21653542Sheideman spec_write (ap) 21753542Sheideman struct vop_write_args *ap; 21837486Smckusick { 21953542Sheideman USES_VOP_LOCK; 22053542Sheideman USES_VOP_UNLOCK; 221*53863Sheideman register struct vnode *vp = ap->a_vp; 222*53863Sheideman register struct uio *uio = ap->a_uio; 223*53863Sheideman struct proc *p = uio->uio_procp; 22439614Smckusick struct buf *bp; 22539614Smckusick daddr_t bn; 22639614Smckusick int bsize, blkmask; 22739614Smckusick struct partinfo dpart; 22845731Smckusick register int n, on; 22945731Smckusick int error = 0; 23037486Smckusick 23148015Smckusick #ifdef DIAGNOSTIC 232*53863Sheideman if (uio->uio_rw != UIO_WRITE) 23339588Smckusick panic("spec_write mode"); 234*53863Sheideman if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 23548015Smckusick panic("spec_write proc"); 23648015Smckusick #endif 23739588Smckusick 238*53863Sheideman switch (vp->v_type) { 23939588Smckusick 24039588Smckusick case VCHR: 241*53863Sheideman VOP_UNLOCK(vp); 242*53863Sheideman error = (*cdevsw[major(vp->v_rdev)].d_write) 243*53863Sheideman (vp->v_rdev, uio, ap->a_ioflag); 244*53863Sheideman VOP_LOCK(vp); 24539588Smckusick return (error); 24639588Smckusick 24739588Smckusick case VBLK: 248*53863Sheideman if (uio->uio_resid == 0) 24939588Smckusick return (0); 250*53863Sheideman if (uio->uio_offset < 0) 25139588Smckusick return (EINVAL); 25239614Smckusick bsize = BLKDEV_IOSIZE; 253*53863Sheideman if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 25447540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 25539614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 25639614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25739614Smckusick bsize = dpart.part->p_frag * 25839614Smckusick dpart.part->p_fsize; 25939614Smckusick } 26039614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 26139614Smckusick do { 262*53863Sheideman bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 263*53863Sheideman on = uio->uio_offset % bsize; 264*53863Sheideman n = MIN((unsigned)(bsize - on), uio->uio_resid); 26539614Smckusick if (n == bsize) 266*53863Sheideman bp = getblk(vp, bn, bsize); 26739614Smckusick else 268*53863Sheideman error = bread(vp, bn, bsize, NOCRED, &bp); 26939614Smckusick n = MIN(n, bsize - bp->b_resid); 27039614Smckusick if (error) { 27139614Smckusick brelse(bp); 27239614Smckusick return (error); 27339614Smckusick } 274*53863Sheideman error = uiomove(bp->b_un.b_addr + on, n, uio); 27539614Smckusick if (n + on == bsize) { 27639614Smckusick bp->b_flags |= B_AGE; 27739614Smckusick bawrite(bp); 27839614Smckusick } else 27939614Smckusick bdwrite(bp); 280*53863Sheideman } while (error == 0 && uio->uio_resid > 0 && n != 0); 28139614Smckusick return (error); 28239588Smckusick 28339588Smckusick default: 28439588Smckusick panic("spec_write type"); 28539588Smckusick } 28639588Smckusick /* NOTREACHED */ 28737486Smckusick } 28837486Smckusick 28937486Smckusick /* 29037486Smckusick * Device ioctl operation. 29137486Smckusick */ 29237725Smckusick /* ARGSUSED */ 29353542Sheideman spec_ioctl (ap) 29453542Sheideman struct vop_ioctl_args *ap; 29537486Smckusick { 29653597Sheideman dev_t dev = ap->a_vp->v_rdev; 29737486Smckusick 29853597Sheideman switch (ap->a_vp->v_type) { 29937486Smckusick 30037486Smckusick case VCHR: 30153597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 30253597Sheideman ap->a_fflag, ap->a_p)); 30337486Smckusick 30437486Smckusick case VBLK: 30553597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 30639666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 30739666Smckusick return (0); 30839666Smckusick else 30939666Smckusick return (1); 31053597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 31153597Sheideman ap->a_fflag, ap->a_p)); 31237486Smckusick 31337486Smckusick default: 31439446Smckusick panic("spec_ioctl"); 31537486Smckusick /* NOTREACHED */ 31637486Smckusick } 31737486Smckusick } 31837486Smckusick 31937725Smckusick /* ARGSUSED */ 32053542Sheideman spec_select (ap) 32153542Sheideman struct vop_select_args *ap; 32237486Smckusick { 32337486Smckusick register dev_t dev; 32437486Smckusick 32553597Sheideman switch (ap->a_vp->v_type) { 32637486Smckusick 32737486Smckusick default: 32837486Smckusick return (1); /* XXX */ 32937486Smckusick 33037486Smckusick case VCHR: 33153597Sheideman dev = ap->a_vp->v_rdev; 33253597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 33337486Smckusick } 33437486Smckusick } 33537486Smckusick 33637486Smckusick /* 33737486Smckusick * Just call the device strategy routine 33837486Smckusick */ 33953542Sheideman spec_strategy (ap) 34053542Sheideman struct vop_strategy_args *ap; 34137486Smckusick { 34239666Smckusick 34353597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 34437486Smckusick return (0); 34537486Smckusick } 34637486Smckusick 34739432Smckusick /* 34839666Smckusick * This is a noop, simply returning what one has been given. 34939666Smckusick */ 35053542Sheideman spec_bmap (ap) 35153542Sheideman struct vop_bmap_args *ap; 35239666Smckusick { 35339666Smckusick 35453597Sheideman if (ap->a_vpp != NULL) 35553597Sheideman *ap->a_vpp = ap->a_vp; 35653597Sheideman if (ap->a_bnp != NULL) 35753597Sheideman *ap->a_bnp = ap->a_bn; 35839666Smckusick return (0); 35939666Smckusick } 36039666Smckusick 36139666Smckusick /* 36239432Smckusick * At the moment we do not do any locking. 36339432Smckusick */ 36439489Smckusick /* ARGSUSED */ 36553542Sheideman spec_lock (ap) 36653542Sheideman struct vop_lock_args *ap; 36737486Smckusick { 36837486Smckusick 36937486Smckusick return (0); 37037486Smckusick } 37137486Smckusick 37239489Smckusick /* ARGSUSED */ 37353542Sheideman spec_unlock (ap) 37453542Sheideman struct vop_unlock_args *ap; 37537486Smckusick { 37637486Smckusick 37737486Smckusick return (0); 37837486Smckusick } 37937486Smckusick 38037486Smckusick /* 38137486Smckusick * Device close routine 38237486Smckusick */ 38337725Smckusick /* ARGSUSED */ 38453542Sheideman spec_close (ap) 38553542Sheideman struct vop_close_args *ap; 38637486Smckusick { 387*53863Sheideman register struct vnode *vp = ap->a_vp; 388*53863Sheideman dev_t dev = vp->v_rdev; 38949273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 39040707Skarels int mode; 39137486Smckusick 392*53863Sheideman switch (vp->v_type) { 39337725Smckusick 39437725Smckusick case VCHR: 39539485Smckusick /* 39639485Smckusick * If the vnode is locked, then we are in the midst 39739485Smckusick * of forcably closing the device, otherwise we only 39839485Smckusick * close on last reference. 39939485Smckusick */ 400*53863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 40137725Smckusick return (0); 40249273Skarels devclose = cdevsw[major(dev)].d_close; 40339432Smckusick mode = S_IFCHR; 40437725Smckusick break; 40537725Smckusick 40637725Smckusick case VBLK: 40737725Smckusick /* 40837725Smckusick * On last close of a block device (that isn't mounted) 40937725Smckusick * we must invalidate any in core blocks, so that 41037725Smckusick * we can, for instance, change floppy disks. 41137725Smckusick */ 412*53863Sheideman vflushbuf(vp, 0); 413*53863Sheideman if (vinvalbuf(vp, 1)) 41438613Smckusick return (0); 41537725Smckusick /* 41639485Smckusick * We do not want to really close the device if it 41739485Smckusick * is still in use unless we are trying to close it 41839485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 41939630Smckusick * holds a reference to the vnode, and because we mark 42039630Smckusick * any other vnodes that alias this device, when the 42139630Smckusick * sum of the reference counts on all the aliased 42239630Smckusick * vnodes descends to one, we are on last close. 42337725Smckusick */ 424*53863Sheideman if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) 42537725Smckusick return (0); 42649273Skarels devclose = bdevsw[major(dev)].d_close; 42739432Smckusick mode = S_IFBLK; 42837725Smckusick break; 42937725Smckusick 43037725Smckusick default: 43139446Smckusick panic("spec_close: not special"); 43237725Smckusick } 43337725Smckusick 43453597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 43537486Smckusick } 43637486Smckusick 43737486Smckusick /* 43839666Smckusick * Print out the contents of a special device vnode. 43939666Smckusick */ 44053542Sheideman spec_print (ap) 44153542Sheideman struct vop_print_args *ap; 44239666Smckusick { 44339666Smckusick 44453597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 44553597Sheideman minor(ap->a_vp->v_rdev)); 44639666Smckusick } 44739666Smckusick 44839666Smckusick /* 44946196Smckusick * Special device advisory byte-level locks. 45046196Smckusick */ 45148015Smckusick /* ARGSUSED */ 45253542Sheideman spec_advlock (ap) 45353542Sheideman struct vop_advlock_args *ap; 45446196Smckusick { 45546196Smckusick 45646196Smckusick return (EOPNOTSUPP); 45746196Smckusick } 45846196Smckusick 45946196Smckusick /* 46039507Smckusick * Special device failed operation 46137486Smckusick */ 46239507Smckusick spec_ebadf() 46339507Smckusick { 46439507Smckusick 46539507Smckusick return (EBADF); 46639507Smckusick } 46739507Smckusick 46839507Smckusick /* 46939507Smckusick * Special device bad operation 47039507Smckusick */ 47139446Smckusick spec_badop() 47237486Smckusick { 47337486Smckusick 47439446Smckusick panic("spec_badop called"); 47539292Smckusick /* NOTREACHED */ 47637486Smckusick } 477