137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 544443Sbostic * %sccs.include.redist.c% 637486Smckusick * 7*53597Sheideman * @(#)spec_vnops.c 7.44 (Berkeley) 05/15/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 91*53597Sheideman *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*53597Sheideman dev_t dev = (dev_t)ap->a_vp->v_rdev; 10737486Smckusick register int maj = major(dev); 10840375Smckusick int error; 10937486Smckusick 110*53597Sheideman if (ap->a_vp->v_mount && (ap->a_vp->v_mount->mnt_flag & MNT_NODEV)) 11139365Smckusick return (ENXIO); 11239365Smckusick 113*53597Sheideman switch (ap->a_vp->v_type) { 11437486Smckusick 11537486Smckusick case VCHR: 11637486Smckusick if ((u_int)maj >= nchrdev) 11737486Smckusick return (ENXIO); 118*53597Sheideman VOP_UNLOCK(ap->a_vp); 119*53597Sheideman error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); 120*53597Sheideman VOP_LOCK(ap->a_vp); 12149944Smckusick return (error); 12237486Smckusick 12337486Smckusick case VBLK: 12437486Smckusick if ((u_int)maj >= nblkdev) 12537486Smckusick return (ENXIO); 126*53597Sheideman if (error = ufs_mountedon(ap->a_vp)) 12740375Smckusick return (error); 128*53597Sheideman return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); 12937486Smckusick } 13037486Smckusick return (0); 13137486Smckusick } 13237486Smckusick 13337486Smckusick /* 13437486Smckusick * Vnode op for read 13537486Smckusick */ 13641961Smckusick /* ARGSUSED */ 13753542Sheideman spec_read (ap) 13853542Sheideman struct vop_read_args *ap; 13937486Smckusick { 14053542Sheideman USES_VOP_LOCK; 14153542Sheideman USES_VOP_UNLOCK; 142*53597Sheideman struct proc *p = ap->a_uio->uio_procp; 14339614Smckusick struct buf *bp; 14452321Smckusick daddr_t bn, nextbn; 14539614Smckusick long bsize, bscale; 14639614Smckusick struct partinfo dpart; 14739614Smckusick register int n, on; 14839614Smckusick int error = 0; 14937486Smckusick 15048015Smckusick #ifdef DIAGNOSTIC 151*53597Sheideman if (ap->a_uio->uio_rw != UIO_READ) 15239588Smckusick panic("spec_read mode"); 153*53597Sheideman if (ap->a_uio->uio_segflg == UIO_USERSPACE && ap->a_uio->uio_procp != curproc) 15448015Smckusick panic("spec_read proc"); 15548015Smckusick #endif 156*53597Sheideman if (ap->a_uio->uio_resid == 0) 15739588Smckusick return (0); 15839588Smckusick 159*53597Sheideman switch (ap->a_vp->v_type) { 16039588Smckusick 16139588Smckusick case VCHR: 162*53597Sheideman VOP_UNLOCK(ap->a_vp); 163*53597Sheideman error = (*cdevsw[major(ap->a_vp->v_rdev)].d_read) 164*53597Sheideman (ap->a_vp->v_rdev, ap->a_uio, ap->a_ioflag); 165*53597Sheideman VOP_LOCK(ap->a_vp); 16639588Smckusick return (error); 16739588Smckusick 16839588Smckusick case VBLK: 169*53597Sheideman if (ap->a_uio->uio_offset < 0) 17039588Smckusick return (EINVAL); 17139614Smckusick bsize = BLKDEV_IOSIZE; 172*53597Sheideman if ((*bdevsw[major(ap->a_vp->v_rdev)].d_ioctl)(ap->a_vp->v_rdev, DIOCGPART, 17347540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 17439614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 17539614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 17639614Smckusick bsize = dpart.part->p_frag * 17739614Smckusick dpart.part->p_fsize; 17839614Smckusick } 17939614Smckusick bscale = bsize / DEV_BSIZE; 18039614Smckusick do { 181*53597Sheideman bn = (ap->a_uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 182*53597Sheideman on = ap->a_uio->uio_offset % bsize; 183*53597Sheideman n = MIN((unsigned)(bsize - on), ap->a_uio->uio_resid); 184*53597Sheideman if (ap->a_vp->v_lastr + bscale == bn) { 18552321Smckusick nextbn = bn + bscale; 186*53597Sheideman error = breadn(ap->a_vp, bn, (int)bsize, &nextbn, 18752321Smckusick (int *)&bsize, 1, NOCRED, &bp); 18852321Smckusick } else 189*53597Sheideman error = bread(ap->a_vp, bn, (int)bsize, NOCRED, &bp); 190*53597Sheideman ap->a_vp->v_lastr = bn; 19139614Smckusick n = MIN(n, bsize - bp->b_resid); 19239614Smckusick if (error) { 19339614Smckusick brelse(bp); 19439614Smckusick return (error); 19539614Smckusick } 196*53597Sheideman error = uiomove(bp->b_un.b_addr + on, n, ap->a_uio); 19739614Smckusick if (n + on == bsize) 19839614Smckusick bp->b_flags |= B_AGE; 19939614Smckusick brelse(bp); 200*53597Sheideman } while (error == 0 && ap->a_uio->uio_resid > 0 && n != 0); 20139614Smckusick return (error); 20239588Smckusick 20339588Smckusick default: 20439588Smckusick panic("spec_read type"); 20539588Smckusick } 20639588Smckusick /* NOTREACHED */ 20737486Smckusick } 20837486Smckusick 20937486Smckusick /* 21037486Smckusick * Vnode op for write 21137486Smckusick */ 21241961Smckusick /* ARGSUSED */ 21353542Sheideman spec_write (ap) 21453542Sheideman struct vop_write_args *ap; 21537486Smckusick { 21653542Sheideman USES_VOP_LOCK; 21753542Sheideman USES_VOP_UNLOCK; 218*53597Sheideman struct proc *p = ap->a_uio->uio_procp; 21939614Smckusick struct buf *bp; 22039614Smckusick daddr_t bn; 22139614Smckusick int bsize, blkmask; 22239614Smckusick struct partinfo dpart; 22345731Smckusick register int n, on; 22445731Smckusick int error = 0; 22537486Smckusick 22648015Smckusick #ifdef DIAGNOSTIC 227*53597Sheideman if (ap->a_uio->uio_rw != UIO_WRITE) 22839588Smckusick panic("spec_write mode"); 229*53597Sheideman if (ap->a_uio->uio_segflg == UIO_USERSPACE && ap->a_uio->uio_procp != curproc) 23048015Smckusick panic("spec_write proc"); 23148015Smckusick #endif 23239588Smckusick 233*53597Sheideman switch (ap->a_vp->v_type) { 23439588Smckusick 23539588Smckusick case VCHR: 236*53597Sheideman VOP_UNLOCK(ap->a_vp); 237*53597Sheideman error = (*cdevsw[major(ap->a_vp->v_rdev)].d_write) 238*53597Sheideman (ap->a_vp->v_rdev, ap->a_uio, ap->a_ioflag); 239*53597Sheideman VOP_LOCK(ap->a_vp); 24039588Smckusick return (error); 24139588Smckusick 24239588Smckusick case VBLK: 243*53597Sheideman if (ap->a_uio->uio_resid == 0) 24439588Smckusick return (0); 245*53597Sheideman if (ap->a_uio->uio_offset < 0) 24639588Smckusick return (EINVAL); 24739614Smckusick bsize = BLKDEV_IOSIZE; 248*53597Sheideman if ((*bdevsw[major(ap->a_vp->v_rdev)].d_ioctl)(ap->a_vp->v_rdev, DIOCGPART, 24947540Skarels (caddr_t)&dpart, FREAD, p) == 0) { 25039614Smckusick if (dpart.part->p_fstype == FS_BSDFFS && 25139614Smckusick dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 25239614Smckusick bsize = dpart.part->p_frag * 25339614Smckusick dpart.part->p_fsize; 25439614Smckusick } 25539614Smckusick blkmask = (bsize / DEV_BSIZE) - 1; 25639614Smckusick do { 257*53597Sheideman bn = (ap->a_uio->uio_offset / DEV_BSIZE) &~ blkmask; 258*53597Sheideman on = ap->a_uio->uio_offset % bsize; 259*53597Sheideman n = MIN((unsigned)(bsize - on), ap->a_uio->uio_resid); 26039614Smckusick if (n == bsize) 261*53597Sheideman bp = getblk(ap->a_vp, bn, bsize); 26239614Smckusick else 263*53597Sheideman error = bread(ap->a_vp, bn, bsize, NOCRED, &bp); 26439614Smckusick n = MIN(n, bsize - bp->b_resid); 26539614Smckusick if (error) { 26639614Smckusick brelse(bp); 26739614Smckusick return (error); 26839614Smckusick } 269*53597Sheideman error = uiomove(bp->b_un.b_addr + on, n, ap->a_uio); 27039614Smckusick if (n + on == bsize) { 27139614Smckusick bp->b_flags |= B_AGE; 27239614Smckusick bawrite(bp); 27339614Smckusick } else 27439614Smckusick bdwrite(bp); 275*53597Sheideman } while (error == 0 && ap->a_uio->uio_resid > 0 && n != 0); 27639614Smckusick return (error); 27739588Smckusick 27839588Smckusick default: 27939588Smckusick panic("spec_write type"); 28039588Smckusick } 28139588Smckusick /* NOTREACHED */ 28237486Smckusick } 28337486Smckusick 28437486Smckusick /* 28537486Smckusick * Device ioctl operation. 28637486Smckusick */ 28737725Smckusick /* ARGSUSED */ 28853542Sheideman spec_ioctl (ap) 28953542Sheideman struct vop_ioctl_args *ap; 29037486Smckusick { 291*53597Sheideman dev_t dev = ap->a_vp->v_rdev; 29237486Smckusick 293*53597Sheideman switch (ap->a_vp->v_type) { 29437486Smckusick 29537486Smckusick case VCHR: 296*53597Sheideman return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 297*53597Sheideman ap->a_fflag, ap->a_p)); 29837486Smckusick 29937486Smckusick case VBLK: 300*53597Sheideman if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) 30139666Smckusick if (bdevsw[major(dev)].d_flags & B_TAPE) 30239666Smckusick return (0); 30339666Smckusick else 30439666Smckusick return (1); 305*53597Sheideman return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, 306*53597Sheideman ap->a_fflag, ap->a_p)); 30737486Smckusick 30837486Smckusick default: 30939446Smckusick panic("spec_ioctl"); 31037486Smckusick /* NOTREACHED */ 31137486Smckusick } 31237486Smckusick } 31337486Smckusick 31437725Smckusick /* ARGSUSED */ 31553542Sheideman spec_select (ap) 31653542Sheideman struct vop_select_args *ap; 31737486Smckusick { 31837486Smckusick register dev_t dev; 31937486Smckusick 320*53597Sheideman switch (ap->a_vp->v_type) { 32137486Smckusick 32237486Smckusick default: 32337486Smckusick return (1); /* XXX */ 32437486Smckusick 32537486Smckusick case VCHR: 326*53597Sheideman dev = ap->a_vp->v_rdev; 327*53597Sheideman return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); 32837486Smckusick } 32937486Smckusick } 33037486Smckusick 33137486Smckusick /* 33237486Smckusick * Just call the device strategy routine 33337486Smckusick */ 33453542Sheideman spec_strategy (ap) 33553542Sheideman struct vop_strategy_args *ap; 33637486Smckusick { 33739666Smckusick 338*53597Sheideman (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); 33937486Smckusick return (0); 34037486Smckusick } 34137486Smckusick 34239432Smckusick /* 34339666Smckusick * This is a noop, simply returning what one has been given. 34439666Smckusick */ 34553542Sheideman spec_bmap (ap) 34653542Sheideman struct vop_bmap_args *ap; 34739666Smckusick { 34839666Smckusick 349*53597Sheideman if (ap->a_vpp != NULL) 350*53597Sheideman *ap->a_vpp = ap->a_vp; 351*53597Sheideman if (ap->a_bnp != NULL) 352*53597Sheideman *ap->a_bnp = ap->a_bn; 35339666Smckusick return (0); 35439666Smckusick } 35539666Smckusick 35639666Smckusick /* 35739432Smckusick * At the moment we do not do any locking. 35839432Smckusick */ 35939489Smckusick /* ARGSUSED */ 36053542Sheideman spec_lock (ap) 36153542Sheideman struct vop_lock_args *ap; 36237486Smckusick { 36337486Smckusick 36437486Smckusick return (0); 36537486Smckusick } 36637486Smckusick 36739489Smckusick /* ARGSUSED */ 36853542Sheideman spec_unlock (ap) 36953542Sheideman struct vop_unlock_args *ap; 37037486Smckusick { 37137486Smckusick 37237486Smckusick return (0); 37337486Smckusick } 37437486Smckusick 37537486Smckusick /* 37637486Smckusick * Device close routine 37737486Smckusick */ 37837725Smckusick /* ARGSUSED */ 37953542Sheideman spec_close (ap) 38053542Sheideman struct vop_close_args *ap; 38137486Smckusick { 382*53597Sheideman dev_t dev = ap->a_vp->v_rdev; 38349273Skarels int (*devclose) __P((dev_t, int, int, struct proc *)); 38440707Skarels int mode; 38537486Smckusick 386*53597Sheideman switch (ap->a_vp->v_type) { 38737725Smckusick 38837725Smckusick case VCHR: 38939485Smckusick /* 39039485Smckusick * If the vnode is locked, then we are in the midst 39139485Smckusick * of forcably closing the device, otherwise we only 39239485Smckusick * close on last reference. 39339485Smckusick */ 394*53597Sheideman if (vcount(ap->a_vp) > 1 && (ap->a_vp->v_flag & VXLOCK) == 0) 39537725Smckusick return (0); 39649273Skarels devclose = cdevsw[major(dev)].d_close; 39739432Smckusick mode = S_IFCHR; 39837725Smckusick break; 39937725Smckusick 40037725Smckusick case VBLK: 40137725Smckusick /* 40237725Smckusick * On last close of a block device (that isn't mounted) 40337725Smckusick * we must invalidate any in core blocks, so that 40437725Smckusick * we can, for instance, change floppy disks. 40537725Smckusick */ 406*53597Sheideman vflushbuf(ap->a_vp, 0); 407*53597Sheideman if (vinvalbuf(ap->a_vp, 1)) 40838613Smckusick return (0); 40937725Smckusick /* 41039485Smckusick * We do not want to really close the device if it 41139485Smckusick * is still in use unless we are trying to close it 41239485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 41339630Smckusick * holds a reference to the vnode, and because we mark 41439630Smckusick * any other vnodes that alias this device, when the 41539630Smckusick * sum of the reference counts on all the aliased 41639630Smckusick * vnodes descends to one, we are on last close. 41737725Smckusick */ 418*53597Sheideman if (vcount(ap->a_vp) > 1 && (ap->a_vp->v_flag & VXLOCK) == 0) 41937725Smckusick return (0); 42049273Skarels devclose = bdevsw[major(dev)].d_close; 42139432Smckusick mode = S_IFBLK; 42237725Smckusick break; 42337725Smckusick 42437725Smckusick default: 42539446Smckusick panic("spec_close: not special"); 42637725Smckusick } 42737725Smckusick 428*53597Sheideman return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); 42937486Smckusick } 43037486Smckusick 43137486Smckusick /* 43239666Smckusick * Print out the contents of a special device vnode. 43339666Smckusick */ 43453542Sheideman spec_print (ap) 43553542Sheideman struct vop_print_args *ap; 43639666Smckusick { 43739666Smckusick 438*53597Sheideman printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 439*53597Sheideman minor(ap->a_vp->v_rdev)); 44039666Smckusick } 44139666Smckusick 44239666Smckusick /* 44346196Smckusick * Special device advisory byte-level locks. 44446196Smckusick */ 44548015Smckusick /* ARGSUSED */ 44653542Sheideman spec_advlock (ap) 44753542Sheideman struct vop_advlock_args *ap; 44846196Smckusick { 44946196Smckusick 45046196Smckusick return (EOPNOTSUPP); 45146196Smckusick } 45246196Smckusick 45346196Smckusick /* 45439507Smckusick * Special device failed operation 45537486Smckusick */ 45639507Smckusick spec_ebadf() 45739507Smckusick { 45839507Smckusick 45939507Smckusick return (EBADF); 46039507Smckusick } 46139507Smckusick 46239507Smckusick /* 46339507Smckusick * Special device bad operation 46439507Smckusick */ 46539446Smckusick spec_badop() 46637486Smckusick { 46737486Smckusick 46839446Smckusick panic("spec_badop called"); 46939292Smckusick /* NOTREACHED */ 47037486Smckusick } 471