123398Smckusick /* 237731Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337731Smckusick * All rights reserved. 423398Smckusick * 544460Sbostic * %sccs.include.redist.c% 637731Smckusick * 7*53469Smckusick * @(#)vfs_vnops.c 7.38 (Berkeley) 05/13/92 823398Smckusick */ 918Sbill 1017099Sbloom #include "param.h" 1117099Sbloom #include "systm.h" 1237731Smckusick #include "kernel.h" 1317099Sbloom #include "file.h" 1437731Smckusick #include "stat.h" 1537731Smckusick #include "buf.h" 1637731Smckusick #include "proc.h" 1737731Smckusick #include "mount.h" 1848030Smckusick #include "namei.h" 1937731Smckusick #include "vnode.h" 2037731Smckusick #include "ioctl.h" 2137731Smckusick #include "tty.h" 22*53469Smckusick #include <vm/vm.h> 2318Sbill 2437731Smckusick struct fileops vnops = 2550164Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; 2637520Smckusick 2718Sbill /* 2837731Smckusick * Common code for vnode open operations. 2937731Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 3018Sbill */ 3152310Smckusick vn_open(ndp, fmode, cmode) 3237731Smckusick register struct nameidata *ndp; 3337731Smckusick int fmode, cmode; 3437731Smckusick { 3537731Smckusick register struct vnode *vp; 3652310Smckusick register struct proc *p = ndp->ni_cnd.cn_proc; 3752331Smckusick register struct ucred *cred = p->p_ucred; 3837731Smckusick struct vattr vat; 3937731Smckusick struct vattr *vap = &vat; 4037731Smckusick int error; 4137731Smckusick 4249943Smckusick if (fmode & O_CREAT) { 4352310Smckusick ndp->ni_cnd.cn_nameiop = CREATE; 4452310Smckusick ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 4549943Smckusick if ((fmode & O_EXCL) == 0) 4652310Smckusick ndp->ni_cnd.cn_flags |= FOLLOW; 4752310Smckusick 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; 5352191Smckusick LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE); 5452310Smckusick if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 5552310Smckusick &ndp->ni_cnd, vap)) 5637731Smckusick return (error); 5749943Smckusick fmode &= ~O_TRUNC; 5837731Smckusick vp = ndp->ni_vp; 5937731Smckusick } else { 6052230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 6139761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 6239761Smckusick vrele(ndp->ni_dvp); 6343343Smckusick else 6439761Smckusick vput(ndp->ni_dvp); 6539761Smckusick ndp->ni_dvp = NULL; 6637731Smckusick vp = ndp->ni_vp; 6749943Smckusick if (fmode & O_EXCL) { 6837731Smckusick error = EEXIST; 6937731Smckusick goto bad; 7037731Smckusick } 7149943Smckusick fmode &= ~O_CREAT; 7237731Smckusick } 7337731Smckusick } else { 7452310Smckusick ndp->ni_cnd.cn_nameiop = LOOKUP; 7552310Smckusick ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 7652310Smckusick if (error = namei(ndp)) 7737731Smckusick return (error); 7837731Smckusick vp = ndp->ni_vp; 7937731Smckusick } 8037731Smckusick if (vp->v_type == VSOCK) { 8137731Smckusick error = EOPNOTSUPP; 8237731Smckusick goto bad; 8337731Smckusick } 8449943Smckusick if ((fmode & O_CREAT) == 0) { 8537731Smckusick if (fmode & FREAD) { 8648030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 8737731Smckusick goto bad; 8837731Smckusick } 8949943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 9037731Smckusick if (vp->v_type == VDIR) { 9137731Smckusick error = EISDIR; 9237731Smckusick goto bad; 9337731Smckusick } 9438401Smckusick if ((error = vn_writechk(vp)) || 9548030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 9638401Smckusick goto bad; 9737731Smckusick } 9837731Smckusick } 9949943Smckusick if (fmode & O_TRUNC) { 10041362Smckusick VATTR_NULL(vap); 10137731Smckusick vap->va_size = 0; 10252191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 10348030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 10437731Smckusick goto bad; 10537731Smckusick } 10650110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 10750110Smckusick goto bad; 10850110Smckusick if (fmode & FWRITE) 10950110Smckusick vp->v_writecount++; 11050110Smckusick return (0); 11137731Smckusick bad: 11237731Smckusick vput(vp); 11340707Skarels return (error); 11437731Smckusick } 11537731Smckusick 11637731Smckusick /* 11738401Smckusick * Check for write permissions on the specified vnode. 11838401Smckusick * The read-only status of the file system is checked. 11938401Smckusick * Also, prototype text segments cannot be written. 12037731Smckusick */ 12138401Smckusick vn_writechk(vp) 12237731Smckusick register struct vnode *vp; 12318Sbill { 12418Sbill 12538401Smckusick /* 12638401Smckusick * Disallow write attempts on read-only file systems; 12738401Smckusick * unless the file is a socket or a block or character 12838401Smckusick * device resident on the file system. 12938401Smckusick */ 13045060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 13145060Smckusick switch (vp->v_type) { 13245060Smckusick case VREG: case VDIR: case VLNK: 13345060Smckusick return (EROFS); 13445060Smckusick } 13545060Smckusick } 13638401Smckusick /* 13738401Smckusick * If there's shared text associated with 13838401Smckusick * the vnode, try to free it up once. If 13938401Smckusick * we fail, we can't allow writing. 14038401Smckusick */ 14145744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 14238401Smckusick return (ETXTBSY); 14338401Smckusick return (0); 14437731Smckusick } 14537731Smckusick 14637731Smckusick /* 14750164Smckusick * Vnode close call 14837731Smckusick */ 14950164Smckusick vn_close(vp, flags, cred, p) 15050164Smckusick register struct vnode *vp; 15150164Smckusick int flags; 15250164Smckusick struct ucred *cred; 15350164Smckusick struct proc *p; 15450164Smckusick { 15550164Smckusick int error; 15650164Smckusick 15750164Smckusick if (flags & FWRITE) 15850164Smckusick vp->v_writecount--; 15950164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 16050164Smckusick vrele(vp); 16150164Smckusick return (error); 16250164Smckusick } 16350164Smckusick 16450164Smckusick /* 16550164Smckusick * Package up an I/O request on a vnode into a uio and do it. 16650164Smckusick */ 16748030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 16837731Smckusick enum uio_rw rw; 16937731Smckusick struct vnode *vp; 17037731Smckusick caddr_t base; 17137731Smckusick int len; 17237731Smckusick off_t offset; 17337731Smckusick enum uio_seg segflg; 17437731Smckusick int ioflg; 17537731Smckusick struct ucred *cred; 17637731Smckusick int *aresid; 17748030Smckusick struct proc *p; 17837731Smckusick { 17937731Smckusick struct uio auio; 18037731Smckusick struct iovec aiov; 18137731Smckusick int error; 18237731Smckusick 18339590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 18439590Smckusick VOP_LOCK(vp); 18537731Smckusick auio.uio_iov = &aiov; 18637731Smckusick auio.uio_iovcnt = 1; 18737731Smckusick aiov.iov_base = base; 18837731Smckusick aiov.iov_len = len; 18937731Smckusick auio.uio_resid = len; 19037731Smckusick auio.uio_offset = offset; 19137731Smckusick auio.uio_segflg = segflg; 19237731Smckusick auio.uio_rw = rw; 19348030Smckusick auio.uio_procp = p; 19452191Smckusick if (rw == UIO_READ) { 19552191Smckusick LEASE_CHECK(vp, p, cred, LEASE_READ); 19639590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 19752191Smckusick } else { 19852191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 19939590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 20052191Smckusick } 20137731Smckusick if (aresid) 20237731Smckusick *aresid = auio.uio_resid; 20337731Smckusick else 20437731Smckusick if (auio.uio_resid && error == 0) 20537731Smckusick error = EIO; 20639590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 20739590Smckusick VOP_UNLOCK(vp); 20837731Smckusick return (error); 20937731Smckusick } 21037731Smckusick 21150164Smckusick /* 21250164Smckusick * File table vnode read routine. 21350164Smckusick */ 21437731Smckusick vn_read(fp, uio, cred) 21537731Smckusick struct file *fp; 21637731Smckusick struct uio *uio; 21737731Smckusick struct ucred *cred; 21837731Smckusick { 21939590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 22039590Smckusick int count, error; 22137731Smckusick 22239590Smckusick VOP_LOCK(vp); 22339590Smckusick uio->uio_offset = fp->f_offset; 22439590Smckusick count = uio->uio_resid; 22552191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ); 22649943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 22749943Smckusick cred); 22839590Smckusick fp->f_offset += count - uio->uio_resid; 22939590Smckusick VOP_UNLOCK(vp); 23039590Smckusick return (error); 23137731Smckusick } 23237731Smckusick 23350164Smckusick /* 23450164Smckusick * File table vnode write routine. 23550164Smckusick */ 23637731Smckusick vn_write(fp, uio, cred) 23737731Smckusick struct file *fp; 23837731Smckusick struct uio *uio; 23937731Smckusick struct ucred *cred; 24037731Smckusick { 24137731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 24239590Smckusick int count, error, ioflag = 0; 24337731Smckusick 24449943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 24537731Smckusick ioflag |= IO_APPEND; 24649943Smckusick if (fp->f_flag & FNONBLOCK) 24737731Smckusick ioflag |= IO_NDELAY; 24839590Smckusick VOP_LOCK(vp); 24939590Smckusick uio->uio_offset = fp->f_offset; 25039590Smckusick count = uio->uio_resid; 25152191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE); 25239590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 25339590Smckusick if (ioflag & IO_APPEND) 25439590Smckusick fp->f_offset = uio->uio_offset; 25539590Smckusick else 25639590Smckusick fp->f_offset += count - uio->uio_resid; 25739590Smckusick VOP_UNLOCK(vp); 25839590Smckusick return (error); 25937731Smckusick } 26037731Smckusick 26137731Smckusick /* 26250164Smckusick * File table vnode stat routine. 26337731Smckusick */ 26448030Smckusick vn_stat(vp, sb, p) 26537731Smckusick struct vnode *vp; 26637731Smckusick register struct stat *sb; 26748030Smckusick struct proc *p; 26837731Smckusick { 26937731Smckusick struct vattr vattr; 27037731Smckusick register struct vattr *vap; 27137731Smckusick int error; 27237731Smckusick u_short mode; 27337731Smckusick 27437731Smckusick vap = &vattr; 27548030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 27637731Smckusick if (error) 27737731Smckusick return (error); 27837731Smckusick /* 27937731Smckusick * Copy from vattr table 28037731Smckusick */ 28137731Smckusick sb->st_dev = vap->va_fsid; 28237731Smckusick sb->st_ino = vap->va_fileid; 28337731Smckusick mode = vap->va_mode; 28437731Smckusick switch (vp->v_type) { 28537731Smckusick case VREG: 28639382Smckusick mode |= S_IFREG; 28737731Smckusick break; 28837731Smckusick case VDIR: 28939382Smckusick mode |= S_IFDIR; 29037731Smckusick break; 29137731Smckusick case VBLK: 29239382Smckusick mode |= S_IFBLK; 29337731Smckusick break; 29437731Smckusick case VCHR: 29539382Smckusick mode |= S_IFCHR; 29637731Smckusick break; 29737731Smckusick case VLNK: 29839382Smckusick mode |= S_IFLNK; 29937731Smckusick break; 30037731Smckusick case VSOCK: 30139382Smckusick mode |= S_IFSOCK; 30237731Smckusick break; 30340284Smckusick case VFIFO: 30440284Smckusick mode |= S_IFIFO; 30540284Smckusick break; 30637731Smckusick default: 30737731Smckusick return (EBADF); 30837731Smckusick }; 30937731Smckusick sb->st_mode = mode; 31037731Smckusick sb->st_nlink = vap->va_nlink; 31137731Smckusick sb->st_uid = vap->va_uid; 31237731Smckusick sb->st_gid = vap->va_gid; 31337731Smckusick sb->st_rdev = vap->va_rdev; 31437731Smckusick sb->st_size = vap->va_size; 315*53469Smckusick sb->st_atimeval= vap->va_atime; 316*53469Smckusick sb->st_mtimeval= vap->va_mtime; 317*53469Smckusick sb->st_ctimeval= vap->va_ctime; 31837731Smckusick sb->st_blksize = vap->va_blocksize; 31938257Smckusick sb->st_flags = vap->va_flags; 32038257Smckusick sb->st_gen = vap->va_gen; 32138769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 32237731Smckusick return (0); 32337731Smckusick } 32437731Smckusick 32537731Smckusick /* 32650164Smckusick * File table vnode ioctl routine. 32737731Smckusick */ 32848030Smckusick vn_ioctl(fp, com, data, p) 32937731Smckusick struct file *fp; 33037731Smckusick int com; 33137731Smckusick caddr_t data; 33248030Smckusick struct proc *p; 33337731Smckusick { 33437731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 33537731Smckusick struct vattr vattr; 33637731Smckusick int error; 33737731Smckusick 33837731Smckusick switch (vp->v_type) { 33937731Smckusick 34037731Smckusick case VREG: 34137731Smckusick case VDIR: 34237731Smckusick if (com == FIONREAD) { 34348030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 34437731Smckusick return (error); 34537731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 34637731Smckusick return (0); 34718Sbill } 34837731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 34937731Smckusick return (0); /* XXX */ 35037731Smckusick /* fall into ... */ 35137731Smckusick 35237731Smckusick default: 35337731Smckusick return (ENOTTY); 35437731Smckusick 35540284Smckusick case VFIFO: 35637731Smckusick case VCHR: 35737731Smckusick case VBLK: 35848030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 35939564Smarc if (error == 0 && com == TIOCSCTTY) { 36047540Skarels p->p_session->s_ttyvp = vp; 36139564Smarc VREF(vp); 36239564Smarc } 36339564Smarc return (error); 36418Sbill } 36537731Smckusick } 36637731Smckusick 36737731Smckusick /* 36850164Smckusick * File table vnode select routine. 36937731Smckusick */ 37048030Smckusick vn_select(fp, which, p) 37137731Smckusick struct file *fp; 37237731Smckusick int which; 37348030Smckusick struct proc *p; 37437731Smckusick { 37547540Skarels 37640707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 37750164Smckusick fp->f_cred, p)); 37837731Smckusick } 37937731Smckusick 38037731Smckusick /* 38150164Smckusick * File table vnode close routine. 38237731Smckusick */ 38350164Smckusick vn_closefile(fp, p) 38450164Smckusick struct file *fp; 38548030Smckusick struct proc *p; 38637731Smckusick { 38737731Smckusick 38850164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 38950164Smckusick fp->f_cred, p)); 39037731Smckusick } 39137731Smckusick 39237731Smckusick /* 39337731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 39437731Smckusick * - look up fsid in mount list (if not found ret error) 39537731Smckusick * - get vp by calling VFS_FHTOVP() macro 39637731Smckusick * - if lockflag lock it with VOP_LOCK() 39718Sbill */ 39837731Smckusick vn_fhtovp(fhp, lockflag, vpp) 39937731Smckusick fhandle_t *fhp; 40037731Smckusick int lockflag; 40137731Smckusick struct vnode **vpp; 40218Sbill { 40337731Smckusick register struct mount *mp; 40418Sbill 40537731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 40637731Smckusick return (ESTALE); 40752191Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) 40838146Smckusick return (ESTALE); 40938146Smckusick if (!lockflag) 41038146Smckusick VOP_UNLOCK(*vpp); 41137731Smckusick return (0); 41237731Smckusick } 413