123398Smckusick /* 237731Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337731Smckusick * All rights reserved. 423398Smckusick * 5*44460Sbostic * %sccs.include.redist.c% 637731Smckusick * 7*44460Sbostic * @(#)vfs_vnops.c 7.23 (Berkeley) 06/28/90 823398Smckusick */ 918Sbill 1017099Sbloom #include "param.h" 1117099Sbloom #include "systm.h" 1217099Sbloom #include "user.h" 1337731Smckusick #include "kernel.h" 1417099Sbloom #include "file.h" 1537731Smckusick #include "stat.h" 1637731Smckusick #include "buf.h" 1737731Smckusick #include "proc.h" 1837731Smckusick #include "uio.h" 1917099Sbloom #include "socket.h" 2017099Sbloom #include "socketvar.h" 2137731Smckusick #include "mount.h" 2237731Smckusick #include "vnode.h" 2337731Smckusick #include "ioctl.h" 2437731Smckusick #include "tty.h" 2518Sbill 2637731Smckusick int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close(); 2737731Smckusick struct fileops vnops = 2837731Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; 2937520Smckusick 3018Sbill /* 3137731Smckusick * Common code for vnode open operations. 3237731Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 3318Sbill */ 3437731Smckusick vn_open(ndp, fmode, cmode) 3537731Smckusick register struct nameidata *ndp; 3637731Smckusick int fmode, cmode; 3737731Smckusick { 3837731Smckusick register struct vnode *vp; 3937731Smckusick struct vattr vat; 4037731Smckusick struct vattr *vap = &vat; 4137731Smckusick int error; 4237731Smckusick 4337731Smckusick if (fmode & FCREAT) { 4437731Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 4537731Smckusick if ((fmode & FEXCL) == 0) 4637731Smckusick ndp->ni_nameiop |= FOLLOW; 4737731Smckusick if (error = namei(ndp)) 4837731Smckusick return (error); 4937731Smckusick if (ndp->ni_vp == NULL) { 5041362Smckusick VATTR_NULL(vap); 5137731Smckusick vap->va_type = VREG; 5237731Smckusick vap->va_mode = cmode; 5337731Smckusick if (error = VOP_CREATE(ndp, vap)) 5437731Smckusick return (error); 5537731Smckusick fmode &= ~FTRUNC; 5637731Smckusick vp = ndp->ni_vp; 5737731Smckusick } else { 5839761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 5939761Smckusick vrele(ndp->ni_dvp); 6043343Smckusick else 6139761Smckusick vput(ndp->ni_dvp); 6239761Smckusick ndp->ni_dvp = NULL; 6337731Smckusick vp = ndp->ni_vp; 6437731Smckusick if (fmode & FEXCL) { 6537731Smckusick error = EEXIST; 6637731Smckusick goto bad; 6737731Smckusick } 6837731Smckusick fmode &= ~FCREAT; 6937731Smckusick } 7037731Smckusick } else { 7137731Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 7237731Smckusick if (error = namei(ndp)) 7337731Smckusick return (error); 7437731Smckusick vp = ndp->ni_vp; 7537731Smckusick } 7637731Smckusick if (vp->v_type == VSOCK) { 7737731Smckusick error = EOPNOTSUPP; 7837731Smckusick goto bad; 7937731Smckusick } 8037731Smckusick if ((fmode & FCREAT) == 0) { 8137731Smckusick if (fmode & FREAD) { 8238401Smckusick if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred)) 8337731Smckusick goto bad; 8437731Smckusick } 8537731Smckusick if (fmode & (FWRITE|FTRUNC)) { 8637731Smckusick if (vp->v_type == VDIR) { 8737731Smckusick error = EISDIR; 8837731Smckusick goto bad; 8937731Smckusick } 9038401Smckusick if ((error = vn_writechk(vp)) || 9138401Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 9238401Smckusick goto bad; 9337731Smckusick } 9437731Smckusick } 9537731Smckusick if (fmode & FTRUNC) { 9641362Smckusick VATTR_NULL(vap); 9737731Smckusick vap->va_size = 0; 9837731Smckusick if (error = VOP_SETATTR(vp, vap, ndp->ni_cred)) 9937731Smckusick goto bad; 10037731Smckusick } 10137731Smckusick VOP_UNLOCK(vp); 10238351Smckusick error = VOP_OPEN(vp, fmode, ndp->ni_cred); 10338351Smckusick if (error) 10438351Smckusick vrele(vp); 10538351Smckusick return (error); 10637731Smckusick 10737731Smckusick bad: 10837731Smckusick vput(vp); 10940707Skarels return (error); 11037731Smckusick } 11137731Smckusick 11237731Smckusick /* 11338401Smckusick * Check for write permissions on the specified vnode. 11438401Smckusick * The read-only status of the file system is checked. 11538401Smckusick * Also, prototype text segments cannot be written. 11637731Smckusick */ 11738401Smckusick vn_writechk(vp) 11837731Smckusick register struct vnode *vp; 11918Sbill { 12018Sbill 12138401Smckusick /* 12238401Smckusick * Disallow write attempts on read-only file systems; 12338401Smckusick * unless the file is a socket or a block or character 12438401Smckusick * device resident on the file system. 12538401Smckusick */ 12641400Smckusick if ((vp->v_mount->mnt_flag & MNT_RDONLY) && vp->v_type != VCHR && 12738401Smckusick vp->v_type != VBLK && vp->v_type != VSOCK) 12838401Smckusick return (EROFS); 12938401Smckusick /* 13038401Smckusick * If there's shared text associated with 13138401Smckusick * the vnode, try to free it up once. If 13238401Smckusick * we fail, we can't allow writing. 13338401Smckusick */ 13438401Smckusick if (vp->v_flag & VTEXT) 13538401Smckusick xrele(vp); 13638401Smckusick if (vp->v_flag & VTEXT) 13738401Smckusick return (ETXTBSY); 13838401Smckusick return (0); 13937731Smckusick } 14037731Smckusick 14137731Smckusick /* 14237731Smckusick * Vnode version of rdwri() for calls on file systems. 14337731Smckusick */ 14437731Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid) 14537731Smckusick enum uio_rw rw; 14637731Smckusick struct vnode *vp; 14737731Smckusick caddr_t base; 14837731Smckusick int len; 14937731Smckusick off_t offset; 15037731Smckusick enum uio_seg segflg; 15137731Smckusick int ioflg; 15237731Smckusick struct ucred *cred; 15337731Smckusick int *aresid; 15437731Smckusick { 15537731Smckusick struct uio auio; 15637731Smckusick struct iovec aiov; 15737731Smckusick int error; 15837731Smckusick 15939590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 16039590Smckusick VOP_LOCK(vp); 16137731Smckusick auio.uio_iov = &aiov; 16237731Smckusick auio.uio_iovcnt = 1; 16337731Smckusick aiov.iov_base = base; 16437731Smckusick aiov.iov_len = len; 16537731Smckusick auio.uio_resid = len; 16637731Smckusick auio.uio_offset = offset; 16737731Smckusick auio.uio_segflg = segflg; 16837731Smckusick auio.uio_rw = rw; 16937731Smckusick if (rw == UIO_READ) 17039590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 17137731Smckusick else 17239590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 17337731Smckusick if (aresid) 17437731Smckusick *aresid = auio.uio_resid; 17537731Smckusick else 17637731Smckusick if (auio.uio_resid && error == 0) 17737731Smckusick error = EIO; 17839590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 17939590Smckusick VOP_UNLOCK(vp); 18037731Smckusick return (error); 18137731Smckusick } 18237731Smckusick 18337731Smckusick vn_read(fp, uio, cred) 18437731Smckusick struct file *fp; 18537731Smckusick struct uio *uio; 18637731Smckusick struct ucred *cred; 18737731Smckusick { 18839590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 18939590Smckusick int count, error; 19037731Smckusick 19139590Smckusick VOP_LOCK(vp); 19239590Smckusick uio->uio_offset = fp->f_offset; 19339590Smckusick count = uio->uio_resid; 19439590Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred); 19539590Smckusick fp->f_offset += count - uio->uio_resid; 19639590Smckusick VOP_UNLOCK(vp); 19739590Smckusick return (error); 19837731Smckusick } 19937731Smckusick 20037731Smckusick vn_write(fp, uio, cred) 20137731Smckusick struct file *fp; 20237731Smckusick struct uio *uio; 20337731Smckusick struct ucred *cred; 20437731Smckusick { 20537731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 20639590Smckusick int count, error, ioflag = 0; 20737731Smckusick 20837731Smckusick if (vp->v_type == VREG && (fp->f_flag & FAPPEND)) 20937731Smckusick ioflag |= IO_APPEND; 21037731Smckusick if (fp->f_flag & FNDELAY) 21137731Smckusick ioflag |= IO_NDELAY; 21239590Smckusick VOP_LOCK(vp); 21339590Smckusick uio->uio_offset = fp->f_offset; 21439590Smckusick count = uio->uio_resid; 21539590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 21639590Smckusick if (ioflag & IO_APPEND) 21739590Smckusick fp->f_offset = uio->uio_offset; 21839590Smckusick else 21939590Smckusick fp->f_offset += count - uio->uio_resid; 22039590Smckusick VOP_UNLOCK(vp); 22139590Smckusick return (error); 22237731Smckusick } 22337731Smckusick 22437731Smckusick /* 22537731Smckusick * Get stat info for a vnode. 22637731Smckusick */ 22737731Smckusick vn_stat(vp, sb) 22837731Smckusick struct vnode *vp; 22937731Smckusick register struct stat *sb; 23037731Smckusick { 23137731Smckusick struct vattr vattr; 23237731Smckusick register struct vattr *vap; 23337731Smckusick int error; 23437731Smckusick u_short mode; 23537731Smckusick 23637731Smckusick vap = &vattr; 23737731Smckusick error = VOP_GETATTR(vp, vap, u.u_cred); 23837731Smckusick if (error) 23937731Smckusick return (error); 24037731Smckusick /* 24137731Smckusick * Copy from vattr table 24237731Smckusick */ 24337731Smckusick sb->st_dev = vap->va_fsid; 24437731Smckusick sb->st_ino = vap->va_fileid; 24537731Smckusick mode = vap->va_mode; 24637731Smckusick switch (vp->v_type) { 24737731Smckusick case VREG: 24839382Smckusick mode |= S_IFREG; 24937731Smckusick break; 25037731Smckusick case VDIR: 25139382Smckusick mode |= S_IFDIR; 25237731Smckusick break; 25337731Smckusick case VBLK: 25439382Smckusick mode |= S_IFBLK; 25537731Smckusick break; 25637731Smckusick case VCHR: 25739382Smckusick mode |= S_IFCHR; 25837731Smckusick break; 25937731Smckusick case VLNK: 26039382Smckusick mode |= S_IFLNK; 26137731Smckusick break; 26237731Smckusick case VSOCK: 26339382Smckusick mode |= S_IFSOCK; 26437731Smckusick break; 26540284Smckusick case VFIFO: 26640284Smckusick mode |= S_IFIFO; 26740284Smckusick break; 26837731Smckusick default: 26937731Smckusick return (EBADF); 27037731Smckusick }; 27137731Smckusick sb->st_mode = mode; 27237731Smckusick sb->st_nlink = vap->va_nlink; 27337731Smckusick sb->st_uid = vap->va_uid; 27437731Smckusick sb->st_gid = vap->va_gid; 27537731Smckusick sb->st_rdev = vap->va_rdev; 27637731Smckusick sb->st_size = vap->va_size; 27737731Smckusick sb->st_atime = vap->va_atime.tv_sec; 27837731Smckusick sb->st_spare1 = 0; 27937731Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 28037731Smckusick sb->st_spare2 = 0; 28137731Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 28237731Smckusick sb->st_spare3 = 0; 28337731Smckusick sb->st_blksize = vap->va_blocksize; 28438257Smckusick sb->st_flags = vap->va_flags; 28538257Smckusick sb->st_gen = vap->va_gen; 28638769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 28737731Smckusick return (0); 28837731Smckusick } 28937731Smckusick 29037731Smckusick /* 29137731Smckusick * Vnode ioctl call 29237731Smckusick */ 29337731Smckusick vn_ioctl(fp, com, data) 29437731Smckusick struct file *fp; 29537731Smckusick int com; 29637731Smckusick caddr_t data; 29737731Smckusick { 29837731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 29937731Smckusick struct vattr vattr; 30037731Smckusick int error; 30137731Smckusick 30237731Smckusick switch (vp->v_type) { 30337731Smckusick 30437731Smckusick case VREG: 30537731Smckusick case VDIR: 30637731Smckusick if (com == FIONREAD) { 30737731Smckusick if (error = VOP_GETATTR(vp, &vattr, u.u_cred)) 30837731Smckusick return (error); 30937731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 31037731Smckusick return (0); 31118Sbill } 31237731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 31337731Smckusick return (0); /* XXX */ 31437731Smckusick /* fall into ... */ 31537731Smckusick 31637731Smckusick default: 31737731Smckusick return (ENOTTY); 31837731Smckusick 31940284Smckusick case VFIFO: 32037731Smckusick case VCHR: 32137731Smckusick case VBLK: 32239564Smarc error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred); 32339564Smarc if (error == 0 && com == TIOCSCTTY) { 32439564Smarc u.u_procp->p_session->s_ttyvp = vp; 32539564Smarc VREF(vp); 32639564Smarc } 32739564Smarc return (error); 32818Sbill } 32937731Smckusick } 33037731Smckusick 33137731Smckusick /* 33237731Smckusick * Vnode select call 33337731Smckusick */ 33437731Smckusick vn_select(fp, which) 33537731Smckusick struct file *fp; 33637731Smckusick int which; 33737731Smckusick { 33840707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 33940284Smckusick u.u_cred)); 34037731Smckusick } 34137731Smckusick 34237731Smckusick /* 34337731Smckusick * Vnode close call 34437731Smckusick */ 34537731Smckusick vn_close(fp) 34637731Smckusick register struct file *fp; 34737731Smckusick { 34837731Smckusick struct vnode *vp = ((struct vnode *)fp->f_data); 34937731Smckusick int error; 35037731Smckusick 35137731Smckusick if (fp->f_flag & (FSHLOCK|FEXLOCK)) 35237731Smckusick vn_unlock(fp, FSHLOCK|FEXLOCK); 35311162Ssam /* 35437731Smckusick * Must delete vnode reference from this file entry 35537731Smckusick * before VOP_CLOSE, so that only other references 35637731Smckusick * will prevent close. 35711162Ssam */ 35837731Smckusick fp->f_data = (caddr_t) 0; 35937731Smckusick error = VOP_CLOSE(vp, fp->f_flag, u.u_cred); 36037731Smckusick vrele(vp); 36137731Smckusick return (error); 36237731Smckusick } 36337731Smckusick 36437731Smckusick /* 36537731Smckusick * Place an advisory lock on a vnode. 36637731Smckusick * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries 36737731Smckusick */ 36837731Smckusick vn_lock(fp, cmd) 36937731Smckusick register struct file *fp; 37037731Smckusick int cmd; 37137731Smckusick { 37237731Smckusick register int priority = PLOCK; 37337731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 37440707Skarels int error = 0; 37540707Skarels static char lockstr[] = "flock"; 37637731Smckusick 37737731Smckusick if ((cmd & LOCK_EX) == 0) 37837731Smckusick priority += 4; 37940707Skarels priority |= PCATCH; 38040707Skarels 38111162Ssam /* 38237731Smckusick * If there's a exclusive lock currently applied 38337731Smckusick * to the file, then we've gotta wait for the 38437731Smckusick * lock with everyone else. 38511162Ssam */ 38637731Smckusick again: 38737731Smckusick while (vp->v_flag & VEXLOCK) { 38837731Smckusick /* 38937731Smckusick * If we're holding an exclusive 39037731Smckusick * lock, then release it. 39137731Smckusick */ 39237731Smckusick if (fp->f_flag & FEXLOCK) { 39337731Smckusick vn_unlock(fp, FEXLOCK); 39437731Smckusick continue; 39537731Smckusick } 39637731Smckusick if (cmd & LOCK_NB) 39737731Smckusick return (EWOULDBLOCK); 39837731Smckusick vp->v_flag |= VLWAIT; 39940707Skarels if (error = tsleep((caddr_t)&vp->v_exlockc, priority, 40040707Skarels lockstr, 0)) 40140707Skarels return (error); 40218Sbill } 40340707Skarels if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) { 40437731Smckusick /* 40537731Smckusick * Must wait for any shared locks to finish 40637731Smckusick * before we try to apply a exclusive lock. 40737731Smckusick * 40837731Smckusick * If we're holding a shared 40937731Smckusick * lock, then release it. 41037731Smckusick */ 41137731Smckusick if (fp->f_flag & FSHLOCK) { 41237731Smckusick vn_unlock(fp, FSHLOCK); 41337731Smckusick goto again; 41437731Smckusick } 41537731Smckusick if (cmd & LOCK_NB) 41637731Smckusick return (EWOULDBLOCK); 41737731Smckusick vp->v_flag |= VLWAIT; 41840707Skarels if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH, 41940707Skarels lockstr, 0) == 0) 42040707Skarels return (error); 42137731Smckusick } 42237731Smckusick if (fp->f_flag & FEXLOCK) 42337731Smckusick panic("vn_lock"); 42437731Smckusick if (cmd & LOCK_EX) { 42537731Smckusick cmd &= ~LOCK_SH; 42637731Smckusick vp->v_exlockc++; 42737731Smckusick vp->v_flag |= VEXLOCK; 42837731Smckusick fp->f_flag |= FEXLOCK; 42937731Smckusick } 43037731Smckusick if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { 43137731Smckusick vp->v_shlockc++; 43237731Smckusick vp->v_flag |= VSHLOCK; 43337731Smckusick fp->f_flag |= FSHLOCK; 43437731Smckusick } 43537731Smckusick return (0); 43618Sbill } 43718Sbill 43818Sbill /* 43937731Smckusick * Unlock a file. 44018Sbill */ 44137731Smckusick vn_unlock(fp, kind) 44237731Smckusick register struct file *fp; 44337731Smckusick int kind; 44418Sbill { 44537731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 44637731Smckusick int flags; 44718Sbill 44837731Smckusick kind &= fp->f_flag; 44937731Smckusick if (vp == NULL || kind == 0) 45037731Smckusick return; 45137731Smckusick flags = vp->v_flag; 45237731Smckusick if (kind & FSHLOCK) { 45337731Smckusick if ((flags & VSHLOCK) == 0) 45437731Smckusick panic("vn_unlock: SHLOCK"); 45537731Smckusick if (--vp->v_shlockc == 0) { 45637731Smckusick vp->v_flag &= ~VSHLOCK; 45737731Smckusick if (flags & VLWAIT) 45837731Smckusick wakeup((caddr_t)&vp->v_shlockc); 45937731Smckusick } 46037731Smckusick fp->f_flag &= ~FSHLOCK; 46137552Smckusick } 46237731Smckusick if (kind & FEXLOCK) { 46337731Smckusick if ((flags & VEXLOCK) == 0) 46437731Smckusick panic("vn_unlock: EXLOCK"); 46537731Smckusick if (--vp->v_exlockc == 0) { 46637731Smckusick vp->v_flag &= ~(VEXLOCK|VLWAIT); 46737731Smckusick if (flags & VLWAIT) 46837731Smckusick wakeup((caddr_t)&vp->v_exlockc); 46937731Smckusick } 47037731Smckusick fp->f_flag &= ~FEXLOCK; 47137731Smckusick } 47218Sbill } 47318Sbill 47418Sbill /* 47537731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 47637731Smckusick * - look up fsid in mount list (if not found ret error) 47737731Smckusick * - get vp by calling VFS_FHTOVP() macro 47837731Smckusick * - if lockflag lock it with VOP_LOCK() 47918Sbill */ 48037731Smckusick vn_fhtovp(fhp, lockflag, vpp) 48137731Smckusick fhandle_t *fhp; 48237731Smckusick int lockflag; 48337731Smckusick struct vnode **vpp; 48418Sbill { 48537731Smckusick register struct mount *mp; 48618Sbill 48737731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 48837731Smckusick return (ESTALE); 48938146Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 49038146Smckusick return (ESTALE); 49138146Smckusick if (!lockflag) 49238146Smckusick VOP_UNLOCK(*vpp); 49337731Smckusick return (0); 49437731Smckusick } 49537731Smckusick 49637731Smckusick /* 49737731Smckusick * Noop 49837731Smckusick */ 49937731Smckusick vfs_noop() 50037731Smckusick { 50137731Smckusick 50237731Smckusick return (ENXIO); 50337731Smckusick } 50437731Smckusick 50537731Smckusick /* 50637731Smckusick * Null op 50737731Smckusick */ 50837731Smckusick vfs_nullop() 50937731Smckusick { 51037731Smckusick 51137731Smckusick return (0); 51237731Smckusick } 513