137486Smckusick /* 237486Smckusick * Copyright (c) 1989 The Regents of the University of California. 337486Smckusick * All rights reserved. 437486Smckusick * 537486Smckusick * Redistribution and use in source and binary forms are permitted 637486Smckusick * provided that the above copyright notice and this paragraph are 737486Smckusick * duplicated in all such forms and that any documentation, 837486Smckusick * advertising materials, and other materials related to such 937486Smckusick * distribution and use acknowledge that the software was developed 1037486Smckusick * by the University of California, Berkeley. The name of the 1137486Smckusick * University may not be used to endorse or promote products derived 1237486Smckusick * from this software without specific prior written permission. 1337486Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437486Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537486Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637486Smckusick * 17*39622Smckusick * @(#)spec_vnops.c 7.17 (Berkeley) 11/25/89 1837486Smckusick */ 1937486Smckusick 2037486Smckusick #include "param.h" 2137486Smckusick #include "systm.h" 2237725Smckusick #include "user.h" 2337725Smckusick #include "kernel.h" 2437486Smckusick #include "conf.h" 2537486Smckusick #include "buf.h" 2639365Smckusick #include "mount.h" 2737486Smckusick #include "vnode.h" 2839588Smckusick #include "../ufs/inode.h" 2939432Smckusick #include "stat.h" 3037486Smckusick #include "errno.h" 3139614Smckusick #include "ioctl.h" 3239614Smckusick #include "file.h" 3339614Smckusick #include "disklabel.h" 3437486Smckusick 3539446Smckusick int spec_lookup(), 3639446Smckusick spec_open(), 3739446Smckusick spec_read(), 3839446Smckusick spec_write(), 3939446Smckusick spec_strategy(), 4039446Smckusick spec_ioctl(), 4139446Smckusick spec_select(), 4239446Smckusick spec_lock(), 4339446Smckusick spec_unlock(), 4439446Smckusick spec_close(), 4539507Smckusick spec_ebadf(), 4639446Smckusick spec_badop(), 4739446Smckusick spec_nullop(); 4837486Smckusick 4939446Smckusick struct vnodeops spec_vnodeops = { 5039507Smckusick spec_lookup, /* lookup */ 5139507Smckusick spec_badop, /* create */ 5239507Smckusick spec_badop, /* mknod */ 5339507Smckusick spec_open, /* open */ 5439507Smckusick spec_close, /* close */ 5539507Smckusick spec_ebadf, /* access */ 5639507Smckusick spec_ebadf, /* getattr */ 5739507Smckusick spec_ebadf, /* setattr */ 5839507Smckusick spec_read, /* read */ 5939507Smckusick spec_write, /* write */ 6039507Smckusick spec_ioctl, /* ioctl */ 6139507Smckusick spec_select, /* select */ 6239507Smckusick spec_badop, /* mmap */ 6339507Smckusick spec_nullop, /* fsync */ 6439507Smckusick spec_badop, /* seek */ 6539507Smckusick spec_badop, /* remove */ 6639507Smckusick spec_badop, /* link */ 6739507Smckusick spec_badop, /* rename */ 6839507Smckusick spec_badop, /* mkdir */ 6939507Smckusick spec_badop, /* rmdir */ 7039507Smckusick spec_badop, /* symlink */ 7139507Smckusick spec_badop, /* readdir */ 7239507Smckusick spec_badop, /* readlink */ 7339507Smckusick spec_badop, /* abortop */ 7439507Smckusick spec_nullop, /* inactive */ 7539507Smckusick spec_nullop, /* reclaim */ 7639507Smckusick spec_lock, /* lock */ 7739507Smckusick spec_unlock, /* unlock */ 7839507Smckusick spec_badop, /* bmap */ 7939507Smckusick spec_strategy, /* strategy */ 8037486Smckusick }; 8137486Smckusick 8237486Smckusick /* 8339292Smckusick * Trivial lookup routine that always fails. 8439292Smckusick */ 8539446Smckusick spec_lookup(vp, ndp) 8639292Smckusick struct vnode *vp; 8739292Smckusick struct nameidata *ndp; 8839292Smckusick { 8939292Smckusick 9039292Smckusick ndp->ni_dvp = vp; 9139292Smckusick ndp->ni_vp = NULL; 9239292Smckusick return (ENOTDIR); 9339292Smckusick } 9439292Smckusick 9539292Smckusick /* 9637486Smckusick * Open called to allow handler 9737486Smckusick * of special files to initialize and 9837486Smckusick * validate before actual IO. 9937486Smckusick */ 10037725Smckusick /* ARGSUSED */ 10139446Smckusick spec_open(vp, mode, cred) 10237486Smckusick register struct vnode *vp; 10337486Smckusick int mode; 10437486Smckusick struct ucred *cred; 10537486Smckusick { 10637486Smckusick dev_t dev = (dev_t)vp->v_rdev; 10737486Smckusick register int maj = major(dev); 10837486Smckusick 10939365Smckusick if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV)) 11039365Smckusick return (ENXIO); 11139365Smckusick 11237486Smckusick switch (vp->v_type) { 11337486Smckusick 11437486Smckusick case VCHR: 11537486Smckusick if ((u_int)maj >= nchrdev) 11637486Smckusick return (ENXIO); 11739432Smckusick return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 11837486Smckusick 11937486Smckusick case VBLK: 12037486Smckusick if ((u_int)maj >= nblkdev) 12137486Smckusick return (ENXIO); 12239432Smckusick return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 12337486Smckusick } 12437486Smckusick return (0); 12537486Smckusick } 12637486Smckusick 12737486Smckusick /* 12837486Smckusick * Vnode op for read 12937486Smckusick */ 13039588Smckusick spec_read(vp, uio, ioflag, cred) 13137486Smckusick register struct vnode *vp; 13239614Smckusick register struct uio *uio; 13337486Smckusick int ioflag; 13437486Smckusick struct ucred *cred; 13537486Smckusick { 13639614Smckusick struct buf *bp; 13739614Smckusick daddr_t bn; 13839614Smckusick long bsize, bscale; 13939614Smckusick struct partinfo dpart; 14039614Smckusick register int n, on; 14139614Smckusick int error = 0; 14239588Smckusick extern int mem_no; 14337486Smckusick 14439588Smckusick if (uio->uio_rw != UIO_READ) 14539588Smckusick panic("spec_read mode"); 14639588Smckusick if (uio->uio_resid == 0) 14739588Smckusick return (0); 14839588Smckusick /* 14939588Smckusick * XXX Set access flag for the ufs filesystem. 15039588Smckusick */ 15139588Smckusick if (vp->v_tag == VT_UFS) 15239588Smckusick VTOI(vp)->i_flag |= IACC; 15339588Smckusick 15439588Smckusick switch (vp->v_type) { 15539588Smckusick 15639588Smckusick case VCHR: 15739588Smckusick /* 15839588Smckusick * Negative offsets allowed only for /dev/kmem 15939588Smckusick */ 16039588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 16139588Smckusick return (EINVAL); 16239588Smckusick VOP_UNLOCK(vp); 16339588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_read) 16439588Smckusick (vp->v_rdev, uio, ioflag); 16537725Smckusick VOP_LOCK(vp); 16639588Smckusick return (error); 16739588Smckusick 16839588Smckusick case VBLK: 16939588Smckusick if (uio->uio_offset < 0) 17039588Smckusick return (EINVAL); 17139614Smckusick bsize = BLKDEV_IOSIZE; 17239614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 17339614Smckusick (caddr_t)&dpart, FREAD) == 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 { 18139614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); 18239614Smckusick on = uio->uio_offset % bsize; 18339614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 18439614Smckusick if (vp->v_lastr + bscale == bn) 18539614Smckusick error = breada(vp, bn, (int)bsize, bn + bscale, 18639614Smckusick (int)bsize, NOCRED, &bp); 18739614Smckusick else 18839614Smckusick error = bread(vp, bn, (int)bsize, NOCRED, &bp); 18939614Smckusick vp->v_lastr = bn; 19039614Smckusick n = MIN(n, bsize - bp->b_resid); 19139614Smckusick if (error) { 19239614Smckusick brelse(bp); 19339614Smckusick return (error); 19439614Smckusick } 19539614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 19639614Smckusick if (n + on == bsize) 19739614Smckusick bp->b_flags |= B_AGE; 19839614Smckusick brelse(bp); 19939614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 20039614Smckusick return (error); 20139588Smckusick 20239588Smckusick default: 20339588Smckusick panic("spec_read type"); 20439588Smckusick } 20539588Smckusick /* NOTREACHED */ 20637486Smckusick } 20737486Smckusick 20837486Smckusick /* 20937486Smckusick * Vnode op for write 21037486Smckusick */ 21139588Smckusick spec_write(vp, uio, ioflag, cred) 21237486Smckusick register struct vnode *vp; 21339614Smckusick register struct uio *uio; 21437486Smckusick int ioflag; 21537486Smckusick struct ucred *cred; 21637486Smckusick { 21739614Smckusick struct buf *bp; 21839614Smckusick daddr_t bn; 21939614Smckusick int bsize, blkmask; 22039614Smckusick struct partinfo dpart; 22139614Smckusick register int n, on, i; 22239614Smckusick int count, error = 0; 22339588Smckusick extern int mem_no; 22437486Smckusick 22539588Smckusick if (uio->uio_rw != UIO_WRITE) 22639588Smckusick panic("spec_write mode"); 22739588Smckusick /* 22839588Smckusick * XXX Set update and change flags for the ufs filesystem. 22939588Smckusick */ 23039588Smckusick if (vp->v_tag == VT_UFS) 23139588Smckusick VTOI(vp)->i_flag |= IUPD|ICHG; 23239588Smckusick 23339588Smckusick switch (vp->v_type) { 23439588Smckusick 23539588Smckusick case VCHR: 23639588Smckusick /* 23739588Smckusick * Negative offsets allowed only for /dev/kmem 23839588Smckusick */ 23939588Smckusick if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no) 24039588Smckusick return (EINVAL); 24139588Smckusick VOP_UNLOCK(vp); 24239588Smckusick error = (*cdevsw[major(vp->v_rdev)].d_write) 24339588Smckusick (vp->v_rdev, uio, ioflag); 24437725Smckusick VOP_LOCK(vp); 24539588Smckusick return (error); 24639588Smckusick 24739588Smckusick case VBLK: 24839588Smckusick if (uio->uio_resid == 0) 24939588Smckusick return (0); 25039588Smckusick if (uio->uio_offset < 0) 25139588Smckusick return (EINVAL); 25239614Smckusick bsize = BLKDEV_IOSIZE; 25339614Smckusick if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, 25439614Smckusick (caddr_t)&dpart, FREAD) == 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 { 26239614Smckusick bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; 26339614Smckusick on = uio->uio_offset % bsize; 26439614Smckusick n = MIN((unsigned)(bsize - on), uio->uio_resid); 26539614Smckusick count = howmany(bsize, CLBYTES); 26639614Smckusick for (i = 0; i < count; i++) 26739614Smckusick munhash(vp, bn + i * (CLBYTES / DEV_BSIZE)); 26839614Smckusick if (n == bsize) 26939614Smckusick bp = getblk(vp, bn, bsize); 27039614Smckusick else 27139614Smckusick error = bread(vp, bn, bsize, NOCRED, &bp); 27239614Smckusick n = MIN(n, bsize - bp->b_resid); 27339614Smckusick if (error) { 27439614Smckusick brelse(bp); 27539614Smckusick return (error); 27639614Smckusick } 27739614Smckusick error = uiomove(bp->b_un.b_addr + on, n, uio); 27839614Smckusick if (n + on == bsize) { 27939614Smckusick bp->b_flags |= B_AGE; 28039614Smckusick bawrite(bp); 28139614Smckusick } else 28239614Smckusick bdwrite(bp); 28339614Smckusick } while (error == 0 && uio->uio_resid > 0 && n != 0); 28439614Smckusick return (error); 28539588Smckusick 28639588Smckusick default: 28739588Smckusick panic("spec_write type"); 28839588Smckusick } 28939588Smckusick /* NOTREACHED */ 29037486Smckusick } 29137486Smckusick 29237486Smckusick /* 29337486Smckusick * Device ioctl operation. 29437486Smckusick */ 29537725Smckusick /* ARGSUSED */ 29639446Smckusick spec_ioctl(vp, com, data, fflag, cred) 29737486Smckusick struct vnode *vp; 29837486Smckusick register int com; 29937486Smckusick caddr_t data; 30037486Smckusick int fflag; 30137486Smckusick struct ucred *cred; 30237486Smckusick { 30337725Smckusick dev_t dev = vp->v_rdev; 30437486Smckusick 30537486Smckusick switch (vp->v_type) { 30637486Smckusick 30737486Smckusick case VCHR: 30837486Smckusick return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 30937486Smckusick 31037486Smckusick case VBLK: 31137486Smckusick return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag)); 31237486Smckusick 31337486Smckusick default: 31439446Smckusick panic("spec_ioctl"); 31537486Smckusick /* NOTREACHED */ 31637486Smckusick } 31737486Smckusick } 31837486Smckusick 31937725Smckusick /* ARGSUSED */ 32039446Smckusick spec_select(vp, which, cred) 32137486Smckusick struct vnode *vp; 32237486Smckusick int which; 32337486Smckusick struct ucred *cred; 32437486Smckusick { 32537486Smckusick register dev_t dev; 32637486Smckusick 32737486Smckusick switch (vp->v_type) { 32837486Smckusick 32937486Smckusick default: 33037486Smckusick return (1); /* XXX */ 33137486Smckusick 33237486Smckusick case VCHR: 33337725Smckusick dev = vp->v_rdev; 33437486Smckusick return (*cdevsw[major(dev)].d_select)(dev, which); 33537486Smckusick } 33637486Smckusick } 33737486Smckusick 33837486Smckusick /* 33937486Smckusick * Just call the device strategy routine 34037486Smckusick */ 34139446Smckusick spec_strategy(bp) 34237486Smckusick register struct buf *bp; 34337486Smckusick { 34437486Smckusick (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 34537486Smckusick return (0); 34637486Smckusick } 34737486Smckusick 34839432Smckusick /* 34939432Smckusick * At the moment we do not do any locking. 35039432Smckusick */ 35139489Smckusick /* ARGSUSED */ 35239446Smckusick spec_lock(vp) 35337486Smckusick struct vnode *vp; 35437486Smckusick { 35537486Smckusick 35637486Smckusick return (0); 35737486Smckusick } 35837486Smckusick 35939489Smckusick /* ARGSUSED */ 36039446Smckusick spec_unlock(vp) 36137486Smckusick struct vnode *vp; 36237486Smckusick { 36337486Smckusick 36437486Smckusick return (0); 36537486Smckusick } 36637486Smckusick 36737486Smckusick /* 36837486Smckusick * Device close routine 36937486Smckusick */ 37037725Smckusick /* ARGSUSED */ 37139446Smckusick spec_close(vp, flag, cred) 37237725Smckusick register struct vnode *vp; 37337486Smckusick int flag; 37437486Smckusick struct ucred *cred; 37537486Smckusick { 37637486Smckusick dev_t dev = vp->v_rdev; 37737725Smckusick int (*cfunc)(); 37837725Smckusick int error, mode; 37937486Smckusick 38037725Smckusick switch (vp->v_type) { 38137725Smckusick 38237725Smckusick case VCHR: 38339485Smckusick /* 38439485Smckusick * If the vnode is locked, then we are in the midst 38539485Smckusick * of forcably closing the device, otherwise we only 38639485Smckusick * close on last reference. 38739485Smckusick */ 38839485Smckusick if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0) 38937725Smckusick return (0); 39037725Smckusick cfunc = cdevsw[major(dev)].d_close; 39139432Smckusick mode = S_IFCHR; 39237725Smckusick break; 39337725Smckusick 39437725Smckusick case VBLK: 39537725Smckusick /* 39637725Smckusick * On last close of a block device (that isn't mounted) 39737725Smckusick * we must invalidate any in core blocks, so that 39837725Smckusick * we can, for instance, change floppy disks. 39937725Smckusick */ 400*39622Smckusick bflush(vp->v_mounton); 401*39622Smckusick if (binval(vp->v_mounton)) 40238613Smckusick return (0); 40337725Smckusick /* 40439485Smckusick * We do not want to really close the device if it 40539485Smckusick * is still in use unless we are trying to close it 40639485Smckusick * forcibly. Since every use (buffer, vnode, swap, cmap) 40737725Smckusick * holds a reference to the vnode, and because we ensure 40837725Smckusick * that there cannot be more than one vnode per device, 40937725Smckusick * we need only check that we are down to the last 41039485Smckusick * reference to detect last close. 41137725Smckusick */ 41239485Smckusick if (vp->v_count > 1 && (vp->v_flag & VXLOCK) == 0) 41337725Smckusick return (0); 41437725Smckusick cfunc = bdevsw[major(dev)].d_close; 41539432Smckusick mode = S_IFBLK; 41637725Smckusick break; 41737725Smckusick 41837725Smckusick default: 41939446Smckusick panic("spec_close: not special"); 42037725Smckusick } 42137725Smckusick 42237725Smckusick if (setjmp(&u.u_qsave)) { 42337725Smckusick /* 42437725Smckusick * If device close routine is interrupted, 42537725Smckusick * must return so closef can clean up. 42637725Smckusick */ 42737725Smckusick error = EINTR; 42837725Smckusick } else 42937725Smckusick error = (*cfunc)(dev, flag, mode); 43037725Smckusick return (error); 43137486Smckusick } 43237486Smckusick 43337486Smckusick /* 43439507Smckusick * Special device failed operation 43537486Smckusick */ 43639507Smckusick spec_ebadf() 43739507Smckusick { 43839507Smckusick 43939507Smckusick return (EBADF); 44039507Smckusick } 44139507Smckusick 44239507Smckusick /* 44339507Smckusick * Special device bad operation 44439507Smckusick */ 44539446Smckusick spec_badop() 44637486Smckusick { 44737486Smckusick 44839446Smckusick panic("spec_badop called"); 44939292Smckusick /* NOTREACHED */ 45037486Smckusick } 45137486Smckusick 45237486Smckusick /* 45339507Smckusick * Special device null operation 45437486Smckusick */ 45539446Smckusick spec_nullop() 45637486Smckusick { 45737486Smckusick 45837486Smckusick return (0); 45937486Smckusick } 460