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*52191Smckusick * @(#)vfs_vnops.c 7.34 (Berkeley) 01/14/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" 2218Sbill 2337731Smckusick struct fileops vnops = 2450164Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; 2537520Smckusick 2618Sbill /* 2737731Smckusick * Common code for vnode open operations. 2837731Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 2918Sbill */ 3047540Skarels vn_open(ndp, p, fmode, cmode) 3137731Smckusick register struct nameidata *ndp; 3247540Skarels struct proc *p; 3337731Smckusick int fmode, cmode; 3437731Smckusick { 3537731Smckusick register struct vnode *vp; 3647540Skarels register struct ucred *cred = p->p_ucred; 3737731Smckusick struct vattr vat; 3837731Smckusick struct vattr *vap = &vat; 3937731Smckusick int error; 4037731Smckusick 4149943Smckusick if (fmode & O_CREAT) { 4237731Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 4349943Smckusick if ((fmode & O_EXCL) == 0) 4437731Smckusick ndp->ni_nameiop |= FOLLOW; 4547540Skarels if (error = namei(ndp, p)) 4637731Smckusick return (error); 4737731Smckusick if (ndp->ni_vp == NULL) { 4841362Smckusick VATTR_NULL(vap); 4937731Smckusick vap->va_type = VREG; 5037731Smckusick vap->va_mode = cmode; 51*52191Smckusick LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE); 5248030Smckusick if (error = VOP_CREATE(ndp, vap, p)) 5337731Smckusick return (error); 5449943Smckusick fmode &= ~O_TRUNC; 5537731Smckusick vp = ndp->ni_vp; 5637731Smckusick } else { 5749732Smckusick VOP_ABORTOP(ndp); 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; 6449943Smckusick if (fmode & O_EXCL) { 6537731Smckusick error = EEXIST; 6637731Smckusick goto bad; 6737731Smckusick } 6849943Smckusick fmode &= ~O_CREAT; 6937731Smckusick } 7037731Smckusick } else { 7137731Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 7247540Skarels if (error = namei(ndp, p)) 7337731Smckusick return (error); 7437731Smckusick vp = ndp->ni_vp; 7537731Smckusick } 7637731Smckusick if (vp->v_type == VSOCK) { 7737731Smckusick error = EOPNOTSUPP; 7837731Smckusick goto bad; 7937731Smckusick } 8049943Smckusick if ((fmode & O_CREAT) == 0) { 8137731Smckusick if (fmode & FREAD) { 8248030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 8337731Smckusick goto bad; 8437731Smckusick } 8549943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 8637731Smckusick if (vp->v_type == VDIR) { 8737731Smckusick error = EISDIR; 8837731Smckusick goto bad; 8937731Smckusick } 9038401Smckusick if ((error = vn_writechk(vp)) || 9148030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 9238401Smckusick goto bad; 9337731Smckusick } 9437731Smckusick } 9549943Smckusick if (fmode & O_TRUNC) { 9641362Smckusick VATTR_NULL(vap); 9737731Smckusick vap->va_size = 0; 98*52191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 9948030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 10037731Smckusick goto bad; 10137731Smckusick } 10250110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 10350110Smckusick goto bad; 10450110Smckusick if (fmode & FWRITE) 10550110Smckusick vp->v_writecount++; 10650110Smckusick return (0); 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 */ 12645060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 12745060Smckusick switch (vp->v_type) { 12845060Smckusick case VREG: case VDIR: case VLNK: 12945060Smckusick return (EROFS); 13045060Smckusick } 13145060Smckusick } 13238401Smckusick /* 13338401Smckusick * If there's shared text associated with 13438401Smckusick * the vnode, try to free it up once. If 13538401Smckusick * we fail, we can't allow writing. 13638401Smckusick */ 13745744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 13838401Smckusick return (ETXTBSY); 13938401Smckusick return (0); 14037731Smckusick } 14137731Smckusick 14237731Smckusick /* 14350164Smckusick * Vnode close call 14437731Smckusick */ 14550164Smckusick vn_close(vp, flags, cred, p) 14650164Smckusick register struct vnode *vp; 14750164Smckusick int flags; 14850164Smckusick struct ucred *cred; 14950164Smckusick struct proc *p; 15050164Smckusick { 15150164Smckusick int error; 15250164Smckusick 15350164Smckusick if (flags & FWRITE) 15450164Smckusick vp->v_writecount--; 15550164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 15650164Smckusick vrele(vp); 15750164Smckusick return (error); 15850164Smckusick } 15950164Smckusick 16050164Smckusick /* 16150164Smckusick * Package up an I/O request on a vnode into a uio and do it. 16250164Smckusick */ 16348030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 16437731Smckusick enum uio_rw rw; 16537731Smckusick struct vnode *vp; 16637731Smckusick caddr_t base; 16737731Smckusick int len; 16837731Smckusick off_t offset; 16937731Smckusick enum uio_seg segflg; 17037731Smckusick int ioflg; 17137731Smckusick struct ucred *cred; 17237731Smckusick int *aresid; 17348030Smckusick struct proc *p; 17437731Smckusick { 17537731Smckusick struct uio auio; 17637731Smckusick struct iovec aiov; 17737731Smckusick int error; 17837731Smckusick 17939590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 18039590Smckusick VOP_LOCK(vp); 18137731Smckusick auio.uio_iov = &aiov; 18237731Smckusick auio.uio_iovcnt = 1; 18337731Smckusick aiov.iov_base = base; 18437731Smckusick aiov.iov_len = len; 18537731Smckusick auio.uio_resid = len; 18637731Smckusick auio.uio_offset = offset; 18737731Smckusick auio.uio_segflg = segflg; 18837731Smckusick auio.uio_rw = rw; 18948030Smckusick auio.uio_procp = p; 190*52191Smckusick if (rw == UIO_READ) { 191*52191Smckusick LEASE_CHECK(vp, p, cred, LEASE_READ); 19239590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 193*52191Smckusick } else { 194*52191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 19539590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 196*52191Smckusick } 19737731Smckusick if (aresid) 19837731Smckusick *aresid = auio.uio_resid; 19937731Smckusick else 20037731Smckusick if (auio.uio_resid && error == 0) 20137731Smckusick error = EIO; 20239590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 20339590Smckusick VOP_UNLOCK(vp); 20437731Smckusick return (error); 20537731Smckusick } 20637731Smckusick 20750164Smckusick /* 20850164Smckusick * File table vnode read routine. 20950164Smckusick */ 21037731Smckusick vn_read(fp, uio, cred) 21137731Smckusick struct file *fp; 21237731Smckusick struct uio *uio; 21337731Smckusick struct ucred *cred; 21437731Smckusick { 21539590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 21639590Smckusick int count, error; 21737731Smckusick 21839590Smckusick VOP_LOCK(vp); 21939590Smckusick uio->uio_offset = fp->f_offset; 22039590Smckusick count = uio->uio_resid; 221*52191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ); 22249943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 22349943Smckusick cred); 22439590Smckusick fp->f_offset += count - uio->uio_resid; 22539590Smckusick VOP_UNLOCK(vp); 22639590Smckusick return (error); 22737731Smckusick } 22837731Smckusick 22950164Smckusick /* 23050164Smckusick * File table vnode write routine. 23150164Smckusick */ 23237731Smckusick vn_write(fp, uio, cred) 23337731Smckusick struct file *fp; 23437731Smckusick struct uio *uio; 23537731Smckusick struct ucred *cred; 23637731Smckusick { 23737731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 23839590Smckusick int count, error, ioflag = 0; 23937731Smckusick 24049943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 24137731Smckusick ioflag |= IO_APPEND; 24249943Smckusick if (fp->f_flag & FNONBLOCK) 24337731Smckusick ioflag |= IO_NDELAY; 24439590Smckusick VOP_LOCK(vp); 24539590Smckusick uio->uio_offset = fp->f_offset; 24639590Smckusick count = uio->uio_resid; 247*52191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE); 24839590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 24939590Smckusick if (ioflag & IO_APPEND) 25039590Smckusick fp->f_offset = uio->uio_offset; 25139590Smckusick else 25239590Smckusick fp->f_offset += count - uio->uio_resid; 25339590Smckusick VOP_UNLOCK(vp); 25439590Smckusick return (error); 25537731Smckusick } 25637731Smckusick 25737731Smckusick /* 25850164Smckusick * File table vnode stat routine. 25937731Smckusick */ 26048030Smckusick vn_stat(vp, sb, p) 26137731Smckusick struct vnode *vp; 26237731Smckusick register struct stat *sb; 26348030Smckusick struct proc *p; 26437731Smckusick { 26537731Smckusick struct vattr vattr; 26637731Smckusick register struct vattr *vap; 26737731Smckusick int error; 26837731Smckusick u_short mode; 26937731Smckusick 27037731Smckusick vap = &vattr; 27148030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 27237731Smckusick if (error) 27337731Smckusick return (error); 27437731Smckusick /* 27537731Smckusick * Copy from vattr table 27637731Smckusick */ 27737731Smckusick sb->st_dev = vap->va_fsid; 27837731Smckusick sb->st_ino = vap->va_fileid; 27937731Smckusick mode = vap->va_mode; 28037731Smckusick switch (vp->v_type) { 28137731Smckusick case VREG: 28239382Smckusick mode |= S_IFREG; 28337731Smckusick break; 28437731Smckusick case VDIR: 28539382Smckusick mode |= S_IFDIR; 28637731Smckusick break; 28737731Smckusick case VBLK: 28839382Smckusick mode |= S_IFBLK; 28937731Smckusick break; 29037731Smckusick case VCHR: 29139382Smckusick mode |= S_IFCHR; 29237731Smckusick break; 29337731Smckusick case VLNK: 29439382Smckusick mode |= S_IFLNK; 29537731Smckusick break; 29637731Smckusick case VSOCK: 29739382Smckusick mode |= S_IFSOCK; 29837731Smckusick break; 29940284Smckusick case VFIFO: 30040284Smckusick mode |= S_IFIFO; 30140284Smckusick break; 30237731Smckusick default: 30337731Smckusick return (EBADF); 30437731Smckusick }; 30537731Smckusick sb->st_mode = mode; 30637731Smckusick sb->st_nlink = vap->va_nlink; 30737731Smckusick sb->st_uid = vap->va_uid; 30837731Smckusick sb->st_gid = vap->va_gid; 30937731Smckusick sb->st_rdev = vap->va_rdev; 31037731Smckusick sb->st_size = vap->va_size; 31137731Smckusick sb->st_atime = vap->va_atime.tv_sec; 31237731Smckusick sb->st_spare1 = 0; 31337731Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 31437731Smckusick sb->st_spare2 = 0; 31537731Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 31637731Smckusick sb->st_spare3 = 0; 31737731Smckusick sb->st_blksize = vap->va_blocksize; 31838257Smckusick sb->st_flags = vap->va_flags; 31938257Smckusick sb->st_gen = vap->va_gen; 32038769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 32137731Smckusick return (0); 32237731Smckusick } 32337731Smckusick 32437731Smckusick /* 32550164Smckusick * File table vnode ioctl routine. 32637731Smckusick */ 32748030Smckusick vn_ioctl(fp, com, data, p) 32837731Smckusick struct file *fp; 32937731Smckusick int com; 33037731Smckusick caddr_t data; 33148030Smckusick struct proc *p; 33237731Smckusick { 33337731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 33437731Smckusick struct vattr vattr; 33537731Smckusick int error; 33637731Smckusick 33737731Smckusick switch (vp->v_type) { 33837731Smckusick 33937731Smckusick case VREG: 34037731Smckusick case VDIR: 34137731Smckusick if (com == FIONREAD) { 34248030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 34337731Smckusick return (error); 34437731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 34537731Smckusick return (0); 34618Sbill } 34737731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 34837731Smckusick return (0); /* XXX */ 34937731Smckusick /* fall into ... */ 35037731Smckusick 35137731Smckusick default: 35237731Smckusick return (ENOTTY); 35337731Smckusick 35440284Smckusick case VFIFO: 35537731Smckusick case VCHR: 35637731Smckusick case VBLK: 35748030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 35839564Smarc if (error == 0 && com == TIOCSCTTY) { 35947540Skarels p->p_session->s_ttyvp = vp; 36039564Smarc VREF(vp); 36139564Smarc } 36239564Smarc return (error); 36318Sbill } 36437731Smckusick } 36537731Smckusick 36637731Smckusick /* 36750164Smckusick * File table vnode select routine. 36837731Smckusick */ 36948030Smckusick vn_select(fp, which, p) 37037731Smckusick struct file *fp; 37137731Smckusick int which; 37248030Smckusick struct proc *p; 37337731Smckusick { 37447540Skarels 37540707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 37650164Smckusick fp->f_cred, p)); 37737731Smckusick } 37837731Smckusick 37937731Smckusick /* 38050164Smckusick * File table vnode close routine. 38137731Smckusick */ 38250164Smckusick vn_closefile(fp, p) 38350164Smckusick struct file *fp; 38448030Smckusick struct proc *p; 38537731Smckusick { 38637731Smckusick 38750164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 38850164Smckusick fp->f_cred, p)); 38937731Smckusick } 39037731Smckusick 39137731Smckusick /* 39237731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 39337731Smckusick * - look up fsid in mount list (if not found ret error) 39437731Smckusick * - get vp by calling VFS_FHTOVP() macro 39537731Smckusick * - if lockflag lock it with VOP_LOCK() 39618Sbill */ 39737731Smckusick vn_fhtovp(fhp, lockflag, vpp) 39837731Smckusick fhandle_t *fhp; 39937731Smckusick int lockflag; 40037731Smckusick struct vnode **vpp; 40118Sbill { 40237731Smckusick register struct mount *mp; 40318Sbill 40437731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 40537731Smckusick return (ESTALE); 406*52191Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) 40738146Smckusick return (ESTALE); 40838146Smckusick if (!lockflag) 40938146Smckusick VOP_UNLOCK(*vpp); 41037731Smckusick return (0); 41137731Smckusick } 412