123398Smckusick /* 263181Sbostic * Copyright (c) 1982, 1986, 1989, 1993 363181Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923398Smckusick * 1044460Sbostic * %sccs.include.redist.c% 1137731Smckusick * 12*69407Smckusick * @(#)vfs_vnops.c 8.11 (Berkeley) 05/14/95 1323398Smckusick */ 1418Sbill 1556517Sbostic #include <sys/param.h> 1656517Sbostic #include <sys/systm.h> 1756517Sbostic #include <sys/kernel.h> 1856517Sbostic #include <sys/file.h> 1956517Sbostic #include <sys/stat.h> 2056517Sbostic #include <sys/buf.h> 2156517Sbostic #include <sys/proc.h> 2256517Sbostic #include <sys/mount.h> 2356517Sbostic #include <sys/namei.h> 2456517Sbostic #include <sys/vnode.h> 2556517Sbostic #include <sys/ioctl.h> 2656517Sbostic #include <sys/tty.h> 2756517Sbostic 2853469Smckusick #include <vm/vm.h> 2918Sbill 3037731Smckusick struct fileops vnops = 3150164Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; 3237520Smckusick 3318Sbill /* 3437731Smckusick * Common code for vnode open operations. 3537731Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 3618Sbill */ 3752310Smckusick vn_open(ndp, fmode, cmode) 3837731Smckusick register struct nameidata *ndp; 3937731Smckusick int fmode, cmode; 4037731Smckusick { 4137731Smckusick register struct vnode *vp; 4252310Smckusick register struct proc *p = ndp->ni_cnd.cn_proc; 4352331Smckusick register struct ucred *cred = p->p_ucred; 4437731Smckusick struct vattr vat; 4537731Smckusick struct vattr *vap = &vat; 4637731Smckusick int error; 4737731Smckusick 4849943Smckusick if (fmode & O_CREAT) { 4952310Smckusick ndp->ni_cnd.cn_nameiop = CREATE; 5052310Smckusick ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 5149943Smckusick if ((fmode & O_EXCL) == 0) 5252310Smckusick ndp->ni_cnd.cn_flags |= FOLLOW; 5352310Smckusick if (error = namei(ndp)) 5437731Smckusick return (error); 5537731Smckusick if (ndp->ni_vp == NULL) { 5641362Smckusick VATTR_NULL(vap); 5737731Smckusick vap->va_type = VREG; 5837731Smckusick vap->va_mode = cmode; 5968578Smckusick if (fmode & O_EXCL) 6068578Smckusick vap->va_vaflags |= VA_EXCLUSIVE; 6167655Smckusick VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE); 6252310Smckusick if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 6352310Smckusick &ndp->ni_cnd, vap)) 6437731Smckusick return (error); 6549943Smckusick fmode &= ~O_TRUNC; 6637731Smckusick vp = ndp->ni_vp; 6737731Smckusick } else { 6852230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 6939761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 7039761Smckusick vrele(ndp->ni_dvp); 7143343Smckusick else 7239761Smckusick vput(ndp->ni_dvp); 7339761Smckusick ndp->ni_dvp = NULL; 7437731Smckusick vp = ndp->ni_vp; 7549943Smckusick if (fmode & O_EXCL) { 7637731Smckusick error = EEXIST; 7737731Smckusick goto bad; 7837731Smckusick } 7949943Smckusick fmode &= ~O_CREAT; 8037731Smckusick } 8137731Smckusick } else { 8252310Smckusick ndp->ni_cnd.cn_nameiop = LOOKUP; 8352310Smckusick ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 8452310Smckusick if (error = namei(ndp)) 8537731Smckusick return (error); 8637731Smckusick vp = ndp->ni_vp; 8737731Smckusick } 8837731Smckusick if (vp->v_type == VSOCK) { 8937731Smckusick error = EOPNOTSUPP; 9037731Smckusick goto bad; 9137731Smckusick } 9249943Smckusick if ((fmode & O_CREAT) == 0) { 9337731Smckusick if (fmode & FREAD) { 9448030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 9537731Smckusick goto bad; 9637731Smckusick } 9749943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 9837731Smckusick if (vp->v_type == VDIR) { 9937731Smckusick error = EISDIR; 10037731Smckusick goto bad; 10137731Smckusick } 10238401Smckusick if ((error = vn_writechk(vp)) || 10348030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 10438401Smckusick goto bad; 10537731Smckusick } 10637731Smckusick } 10749943Smckusick if (fmode & O_TRUNC) { 108*69407Smckusick VOP_UNLOCK(vp, 0, p); /* XXX */ 10967655Smckusick VOP_LEASE(vp, p, cred, LEASE_WRITE); 110*69407Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ 11141362Smckusick VATTR_NULL(vap); 11237731Smckusick vap->va_size = 0; 11348030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 11437731Smckusick goto bad; 11537731Smckusick } 11650110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 11750110Smckusick goto bad; 11850110Smckusick if (fmode & FWRITE) 11950110Smckusick vp->v_writecount++; 12050110Smckusick return (0); 12137731Smckusick bad: 12237731Smckusick vput(vp); 12340707Skarels return (error); 12437731Smckusick } 12537731Smckusick 12637731Smckusick /* 12738401Smckusick * Check for write permissions on the specified vnode. 12838401Smckusick * The read-only status of the file system is checked. 12938401Smckusick * Also, prototype text segments cannot be written. 13037731Smckusick */ 13138401Smckusick vn_writechk(vp) 13237731Smckusick register struct vnode *vp; 13318Sbill { 13418Sbill 13538401Smckusick /* 13638401Smckusick * Disallow write attempts on read-only file systems; 13738401Smckusick * unless the file is a socket or a block or character 13838401Smckusick * device resident on the file system. 13938401Smckusick */ 14045060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 14145060Smckusick switch (vp->v_type) { 14245060Smckusick case VREG: case VDIR: case VLNK: 14345060Smckusick return (EROFS); 14445060Smckusick } 14545060Smckusick } 14638401Smckusick /* 14738401Smckusick * If there's shared text associated with 14838401Smckusick * the vnode, try to free it up once. If 14938401Smckusick * we fail, we can't allow writing. 15038401Smckusick */ 15145744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 15238401Smckusick return (ETXTBSY); 15338401Smckusick return (0); 15437731Smckusick } 15537731Smckusick 15637731Smckusick /* 15750164Smckusick * Vnode close call 15837731Smckusick */ 15950164Smckusick vn_close(vp, flags, cred, p) 16050164Smckusick register struct vnode *vp; 16150164Smckusick int flags; 16250164Smckusick struct ucred *cred; 16350164Smckusick struct proc *p; 16450164Smckusick { 16550164Smckusick int error; 16650164Smckusick 16750164Smckusick if (flags & FWRITE) 16850164Smckusick vp->v_writecount--; 16950164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 17050164Smckusick vrele(vp); 17150164Smckusick return (error); 17250164Smckusick } 17350164Smckusick 17450164Smckusick /* 17550164Smckusick * Package up an I/O request on a vnode into a uio and do it. 17650164Smckusick */ 17748030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 17837731Smckusick enum uio_rw rw; 17937731Smckusick struct vnode *vp; 18037731Smckusick caddr_t base; 18137731Smckusick int len; 18237731Smckusick off_t offset; 18337731Smckusick enum uio_seg segflg; 18437731Smckusick int ioflg; 18537731Smckusick struct ucred *cred; 18637731Smckusick int *aresid; 18748030Smckusick struct proc *p; 18837731Smckusick { 18937731Smckusick struct uio auio; 19037731Smckusick struct iovec aiov; 19137731Smckusick int error; 19237731Smckusick 19339590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 194*69407Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 19537731Smckusick auio.uio_iov = &aiov; 19637731Smckusick auio.uio_iovcnt = 1; 19737731Smckusick aiov.iov_base = base; 19837731Smckusick aiov.iov_len = len; 19937731Smckusick auio.uio_resid = len; 20037731Smckusick auio.uio_offset = offset; 20137731Smckusick auio.uio_segflg = segflg; 20237731Smckusick auio.uio_rw = rw; 20348030Smckusick auio.uio_procp = p; 20452191Smckusick if (rw == UIO_READ) { 20539590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 20652191Smckusick } else { 20739590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 20852191Smckusick } 20937731Smckusick if (aresid) 21037731Smckusick *aresid = auio.uio_resid; 21137731Smckusick else 21237731Smckusick if (auio.uio_resid && error == 0) 21337731Smckusick error = EIO; 21439590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 215*69407Smckusick VOP_UNLOCK(vp, 0, p); 21637731Smckusick return (error); 21737731Smckusick } 21837731Smckusick 21950164Smckusick /* 22050164Smckusick * File table vnode read routine. 22150164Smckusick */ 22237731Smckusick vn_read(fp, uio, cred) 22337731Smckusick struct file *fp; 22437731Smckusick struct uio *uio; 22537731Smckusick struct ucred *cred; 22637731Smckusick { 227*69407Smckusick struct vnode *vp = (struct vnode *)fp->f_data; 228*69407Smckusick struct proc *p = uio->uio_procp; 22939590Smckusick int count, error; 23037731Smckusick 231*69407Smckusick VOP_LEASE(vp, p, cred, LEASE_READ); 232*69407Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 23339590Smckusick uio->uio_offset = fp->f_offset; 23439590Smckusick count = uio->uio_resid; 23549943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 23649943Smckusick cred); 23739590Smckusick fp->f_offset += count - uio->uio_resid; 238*69407Smckusick VOP_UNLOCK(vp, 0, p); 23939590Smckusick return (error); 24037731Smckusick } 24137731Smckusick 24250164Smckusick /* 24350164Smckusick * File table vnode write routine. 24450164Smckusick */ 24537731Smckusick vn_write(fp, uio, cred) 24637731Smckusick struct file *fp; 24737731Smckusick struct uio *uio; 24837731Smckusick struct ucred *cred; 24937731Smckusick { 250*69407Smckusick struct vnode *vp = (struct vnode *)fp->f_data; 251*69407Smckusick struct proc *p = uio->uio_procp; 25268064Smckusick int count, error, ioflag = IO_UNIT; 25337731Smckusick 25449943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 25537731Smckusick ioflag |= IO_APPEND; 25649943Smckusick if (fp->f_flag & FNONBLOCK) 25737731Smckusick ioflag |= IO_NDELAY; 25868725Smckusick if ((fp->f_flag & O_FSYNC) || (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)) 25968712Smckusick ioflag |= IO_SYNC; 260*69407Smckusick VOP_LEASE(vp, p, cred, LEASE_WRITE); 261*69407Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 26239590Smckusick uio->uio_offset = fp->f_offset; 26339590Smckusick count = uio->uio_resid; 26439590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 26539590Smckusick if (ioflag & IO_APPEND) 26639590Smckusick fp->f_offset = uio->uio_offset; 26739590Smckusick else 26839590Smckusick fp->f_offset += count - uio->uio_resid; 269*69407Smckusick VOP_UNLOCK(vp, 0, p); 27039590Smckusick return (error); 27137731Smckusick } 27237731Smckusick 27337731Smckusick /* 27450164Smckusick * File table vnode stat routine. 27537731Smckusick */ 27648030Smckusick vn_stat(vp, sb, p) 27737731Smckusick struct vnode *vp; 27837731Smckusick register struct stat *sb; 27948030Smckusick struct proc *p; 28037731Smckusick { 28137731Smckusick struct vattr vattr; 28237731Smckusick register struct vattr *vap; 28337731Smckusick int error; 28437731Smckusick u_short mode; 28537731Smckusick 28637731Smckusick vap = &vattr; 28748030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 28837731Smckusick if (error) 28937731Smckusick return (error); 29037731Smckusick /* 29137731Smckusick * Copy from vattr table 29237731Smckusick */ 29337731Smckusick sb->st_dev = vap->va_fsid; 29437731Smckusick sb->st_ino = vap->va_fileid; 29537731Smckusick mode = vap->va_mode; 29637731Smckusick switch (vp->v_type) { 29737731Smckusick case VREG: 29839382Smckusick mode |= S_IFREG; 29937731Smckusick break; 30037731Smckusick case VDIR: 30139382Smckusick mode |= S_IFDIR; 30237731Smckusick break; 30337731Smckusick case VBLK: 30439382Smckusick mode |= S_IFBLK; 30537731Smckusick break; 30637731Smckusick case VCHR: 30739382Smckusick mode |= S_IFCHR; 30837731Smckusick break; 30937731Smckusick case VLNK: 31039382Smckusick mode |= S_IFLNK; 31137731Smckusick break; 31237731Smckusick case VSOCK: 31339382Smckusick mode |= S_IFSOCK; 31437731Smckusick break; 31540284Smckusick case VFIFO: 31640284Smckusick mode |= S_IFIFO; 31740284Smckusick break; 31837731Smckusick default: 31937731Smckusick return (EBADF); 32037731Smckusick }; 32137731Smckusick sb->st_mode = mode; 32237731Smckusick sb->st_nlink = vap->va_nlink; 32337731Smckusick sb->st_uid = vap->va_uid; 32437731Smckusick sb->st_gid = vap->va_gid; 32537731Smckusick sb->st_rdev = vap->va_rdev; 32637731Smckusick sb->st_size = vap->va_size; 32754100Smckusick sb->st_atimespec = vap->va_atime; 32868321Scgd sb->st_mtimespec = vap->va_mtime; 32954100Smckusick sb->st_ctimespec = vap->va_ctime; 33037731Smckusick sb->st_blksize = vap->va_blocksize; 33138257Smckusick sb->st_flags = vap->va_flags; 33238257Smckusick sb->st_gen = vap->va_gen; 33338769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 33437731Smckusick return (0); 33537731Smckusick } 33637731Smckusick 33737731Smckusick /* 33850164Smckusick * File table vnode ioctl routine. 33937731Smckusick */ 34048030Smckusick vn_ioctl(fp, com, data, p) 34137731Smckusick struct file *fp; 34268171Scgd u_long com; 34337731Smckusick caddr_t data; 34448030Smckusick struct proc *p; 34537731Smckusick { 34637731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 34737731Smckusick struct vattr vattr; 34837731Smckusick int error; 34937731Smckusick 35037731Smckusick switch (vp->v_type) { 35137731Smckusick 35237731Smckusick case VREG: 35337731Smckusick case VDIR: 35437731Smckusick if (com == FIONREAD) { 35548030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 35637731Smckusick return (error); 35754772Storek *(int *)data = vattr.va_size - fp->f_offset; 35837731Smckusick return (0); 35918Sbill } 36037731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 36137731Smckusick return (0); /* XXX */ 36237731Smckusick /* fall into ... */ 36337731Smckusick 36437731Smckusick default: 36537731Smckusick return (ENOTTY); 36637731Smckusick 36740284Smckusick case VFIFO: 36837731Smckusick case VCHR: 36937731Smckusick case VBLK: 37048030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 37139564Smarc if (error == 0 && com == TIOCSCTTY) { 37267686Smckusick if (p->p_session->s_ttyvp) 37367686Smckusick vrele(p->p_session->s_ttyvp); 37447540Skarels p->p_session->s_ttyvp = vp; 37539564Smarc VREF(vp); 37639564Smarc } 37739564Smarc return (error); 37818Sbill } 37937731Smckusick } 38037731Smckusick 38137731Smckusick /* 38250164Smckusick * File table vnode select routine. 38337731Smckusick */ 38448030Smckusick vn_select(fp, which, p) 38537731Smckusick struct file *fp; 38637731Smckusick int which; 38748030Smckusick struct proc *p; 38837731Smckusick { 38947540Skarels 39040707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 39150164Smckusick fp->f_cred, p)); 39237731Smckusick } 39337731Smckusick 39437731Smckusick /* 395*69407Smckusick * Check that the vnode is still valid, and if so 396*69407Smckusick * acquire requested lock. 397*69407Smckusick */ 398*69407Smckusick int 399*69407Smckusick vn_lock(vp, flags, p) 400*69407Smckusick struct vnode *vp; 401*69407Smckusick int flags; 402*69407Smckusick struct proc *p; 403*69407Smckusick { 404*69407Smckusick int error; 405*69407Smckusick 406*69407Smckusick do { 407*69407Smckusick if ((flags & LK_INTERLOCK) == 0) 408*69407Smckusick simple_lock(&vp->v_interlock); 409*69407Smckusick if (vp->v_flag & VXLOCK) { 410*69407Smckusick vp->v_flag |= VXWANT; 411*69407Smckusick simple_unlock(&vp->v_interlock); 412*69407Smckusick tsleep((caddr_t)vp, PINOD, "vn_lock", 0); 413*69407Smckusick error = ENOENT; 414*69407Smckusick } else { 415*69407Smckusick error = VOP_LOCK(vp, flags | LK_INTERLOCK, p); 416*69407Smckusick if (error == 0) 417*69407Smckusick return (error); 418*69407Smckusick #ifdef DEBUG 419*69407Smckusick if (error == EWOULDBLOCK) 420*69407Smckusick panic("vn_lock: hung lock"); 421*69407Smckusick #endif 422*69407Smckusick } 423*69407Smckusick flags &= ~LK_INTERLOCK; 424*69407Smckusick } while (flags & LK_RETRY); 425*69407Smckusick return (error); 426*69407Smckusick } 427*69407Smckusick 428*69407Smckusick /* 42950164Smckusick * File table vnode close routine. 43037731Smckusick */ 43150164Smckusick vn_closefile(fp, p) 43250164Smckusick struct file *fp; 43348030Smckusick struct proc *p; 43437731Smckusick { 43537731Smckusick 43650164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 43750164Smckusick fp->f_cred, p)); 43837731Smckusick } 439