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*52310Smckusick * @(#)vfs_vnops.c 7.36 (Berkeley) 02/03/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 */ 30*52310Smckusick vn_open(ndp, fmode, cmode) 3137731Smckusick register struct nameidata *ndp; 3237731Smckusick int fmode, cmode; 3337731Smckusick { 3437731Smckusick register struct vnode *vp; 35*52310Smckusick register struct proc *p = ndp->ni_cnd.cn_proc; 36*52310Smckusick register struct ucred *cred = ndp->ni_cnd.cn_cred; 3737731Smckusick struct vattr vat; 3837731Smckusick struct vattr *vap = &vat; 3937731Smckusick int error; 4037731Smckusick 4149943Smckusick if (fmode & O_CREAT) { 42*52310Smckusick ndp->ni_cnd.cn_nameiop = CREATE; 43*52310Smckusick ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 4449943Smckusick if ((fmode & O_EXCL) == 0) 45*52310Smckusick ndp->ni_cnd.cn_flags |= FOLLOW; 46*52310Smckusick if (error = namei(ndp)) 4737731Smckusick return (error); 4837731Smckusick if (ndp->ni_vp == NULL) { 4941362Smckusick VATTR_NULL(vap); 5037731Smckusick vap->va_type = VREG; 5137731Smckusick vap->va_mode = cmode; 5252191Smckusick LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE); 53*52310Smckusick if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 54*52310Smckusick &ndp->ni_cnd, vap)) 5537731Smckusick return (error); 5649943Smckusick fmode &= ~O_TRUNC; 5737731Smckusick vp = ndp->ni_vp; 5837731Smckusick } else { 5952230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 6039761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 6139761Smckusick vrele(ndp->ni_dvp); 6243343Smckusick else 6339761Smckusick vput(ndp->ni_dvp); 6439761Smckusick ndp->ni_dvp = NULL; 6537731Smckusick vp = ndp->ni_vp; 6649943Smckusick if (fmode & O_EXCL) { 6737731Smckusick error = EEXIST; 6837731Smckusick goto bad; 6937731Smckusick } 7049943Smckusick fmode &= ~O_CREAT; 7137731Smckusick } 7237731Smckusick } else { 73*52310Smckusick ndp->ni_cnd.cn_nameiop = LOOKUP; 74*52310Smckusick ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 75*52310Smckusick if (error = namei(ndp)) 7637731Smckusick return (error); 7737731Smckusick vp = ndp->ni_vp; 7837731Smckusick } 7937731Smckusick if (vp->v_type == VSOCK) { 8037731Smckusick error = EOPNOTSUPP; 8137731Smckusick goto bad; 8237731Smckusick } 8349943Smckusick if ((fmode & O_CREAT) == 0) { 8437731Smckusick if (fmode & FREAD) { 8548030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 8637731Smckusick goto bad; 8737731Smckusick } 8849943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 8937731Smckusick if (vp->v_type == VDIR) { 9037731Smckusick error = EISDIR; 9137731Smckusick goto bad; 9237731Smckusick } 9338401Smckusick if ((error = vn_writechk(vp)) || 9448030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 9538401Smckusick goto bad; 9637731Smckusick } 9737731Smckusick } 9849943Smckusick if (fmode & O_TRUNC) { 9941362Smckusick VATTR_NULL(vap); 10037731Smckusick vap->va_size = 0; 10152191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 10248030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 10337731Smckusick goto bad; 10437731Smckusick } 10550110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 10650110Smckusick goto bad; 10750110Smckusick if (fmode & FWRITE) 10850110Smckusick vp->v_writecount++; 10950110Smckusick return (0); 11037731Smckusick bad: 11137731Smckusick vput(vp); 11240707Skarels return (error); 11337731Smckusick } 11437731Smckusick 11537731Smckusick /* 11638401Smckusick * Check for write permissions on the specified vnode. 11738401Smckusick * The read-only status of the file system is checked. 11838401Smckusick * Also, prototype text segments cannot be written. 11937731Smckusick */ 12038401Smckusick vn_writechk(vp) 12137731Smckusick register struct vnode *vp; 12218Sbill { 12318Sbill 12438401Smckusick /* 12538401Smckusick * Disallow write attempts on read-only file systems; 12638401Smckusick * unless the file is a socket or a block or character 12738401Smckusick * device resident on the file system. 12838401Smckusick */ 12945060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 13045060Smckusick switch (vp->v_type) { 13145060Smckusick case VREG: case VDIR: case VLNK: 13245060Smckusick return (EROFS); 13345060Smckusick } 13445060Smckusick } 13538401Smckusick /* 13638401Smckusick * If there's shared text associated with 13738401Smckusick * the vnode, try to free it up once. If 13838401Smckusick * we fail, we can't allow writing. 13938401Smckusick */ 14045744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 14138401Smckusick return (ETXTBSY); 14238401Smckusick return (0); 14337731Smckusick } 14437731Smckusick 14537731Smckusick /* 14650164Smckusick * Vnode close call 14737731Smckusick */ 14850164Smckusick vn_close(vp, flags, cred, p) 14950164Smckusick register struct vnode *vp; 15050164Smckusick int flags; 15150164Smckusick struct ucred *cred; 15250164Smckusick struct proc *p; 15350164Smckusick { 15450164Smckusick int error; 15550164Smckusick 15650164Smckusick if (flags & FWRITE) 15750164Smckusick vp->v_writecount--; 15850164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 15950164Smckusick vrele(vp); 16050164Smckusick return (error); 16150164Smckusick } 16250164Smckusick 16350164Smckusick /* 16450164Smckusick * Package up an I/O request on a vnode into a uio and do it. 16550164Smckusick */ 16648030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 16737731Smckusick enum uio_rw rw; 16837731Smckusick struct vnode *vp; 16937731Smckusick caddr_t base; 17037731Smckusick int len; 17137731Smckusick off_t offset; 17237731Smckusick enum uio_seg segflg; 17337731Smckusick int ioflg; 17437731Smckusick struct ucred *cred; 17537731Smckusick int *aresid; 17648030Smckusick struct proc *p; 17737731Smckusick { 17837731Smckusick struct uio auio; 17937731Smckusick struct iovec aiov; 18037731Smckusick int error; 18137731Smckusick 18239590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 18339590Smckusick VOP_LOCK(vp); 18437731Smckusick auio.uio_iov = &aiov; 18537731Smckusick auio.uio_iovcnt = 1; 18637731Smckusick aiov.iov_base = base; 18737731Smckusick aiov.iov_len = len; 18837731Smckusick auio.uio_resid = len; 18937731Smckusick auio.uio_offset = offset; 19037731Smckusick auio.uio_segflg = segflg; 19137731Smckusick auio.uio_rw = rw; 19248030Smckusick auio.uio_procp = p; 19352191Smckusick if (rw == UIO_READ) { 19452191Smckusick LEASE_CHECK(vp, p, cred, LEASE_READ); 19539590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 19652191Smckusick } else { 19752191Smckusick LEASE_CHECK(vp, p, cred, LEASE_WRITE); 19839590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 19952191Smckusick } 20037731Smckusick if (aresid) 20137731Smckusick *aresid = auio.uio_resid; 20237731Smckusick else 20337731Smckusick if (auio.uio_resid && error == 0) 20437731Smckusick error = EIO; 20539590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 20639590Smckusick VOP_UNLOCK(vp); 20737731Smckusick return (error); 20837731Smckusick } 20937731Smckusick 21050164Smckusick /* 21150164Smckusick * File table vnode read routine. 21250164Smckusick */ 21337731Smckusick vn_read(fp, uio, cred) 21437731Smckusick struct file *fp; 21537731Smckusick struct uio *uio; 21637731Smckusick struct ucred *cred; 21737731Smckusick { 21839590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 21939590Smckusick int count, error; 22037731Smckusick 22139590Smckusick VOP_LOCK(vp); 22239590Smckusick uio->uio_offset = fp->f_offset; 22339590Smckusick count = uio->uio_resid; 22452191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ); 22549943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 22649943Smckusick cred); 22739590Smckusick fp->f_offset += count - uio->uio_resid; 22839590Smckusick VOP_UNLOCK(vp); 22939590Smckusick return (error); 23037731Smckusick } 23137731Smckusick 23250164Smckusick /* 23350164Smckusick * File table vnode write routine. 23450164Smckusick */ 23537731Smckusick vn_write(fp, uio, cred) 23637731Smckusick struct file *fp; 23737731Smckusick struct uio *uio; 23837731Smckusick struct ucred *cred; 23937731Smckusick { 24037731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 24139590Smckusick int count, error, ioflag = 0; 24237731Smckusick 24349943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 24437731Smckusick ioflag |= IO_APPEND; 24549943Smckusick if (fp->f_flag & FNONBLOCK) 24637731Smckusick ioflag |= IO_NDELAY; 24739590Smckusick VOP_LOCK(vp); 24839590Smckusick uio->uio_offset = fp->f_offset; 24939590Smckusick count = uio->uio_resid; 25052191Smckusick LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE); 25139590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 25239590Smckusick if (ioflag & IO_APPEND) 25339590Smckusick fp->f_offset = uio->uio_offset; 25439590Smckusick else 25539590Smckusick fp->f_offset += count - uio->uio_resid; 25639590Smckusick VOP_UNLOCK(vp); 25739590Smckusick return (error); 25837731Smckusick } 25937731Smckusick 26037731Smckusick /* 26150164Smckusick * File table vnode stat routine. 26237731Smckusick */ 26348030Smckusick vn_stat(vp, sb, p) 26437731Smckusick struct vnode *vp; 26537731Smckusick register struct stat *sb; 26648030Smckusick struct proc *p; 26737731Smckusick { 26837731Smckusick struct vattr vattr; 26937731Smckusick register struct vattr *vap; 27037731Smckusick int error; 27137731Smckusick u_short mode; 27237731Smckusick 27337731Smckusick vap = &vattr; 27448030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 27537731Smckusick if (error) 27637731Smckusick return (error); 27737731Smckusick /* 27837731Smckusick * Copy from vattr table 27937731Smckusick */ 28037731Smckusick sb->st_dev = vap->va_fsid; 28137731Smckusick sb->st_ino = vap->va_fileid; 28237731Smckusick mode = vap->va_mode; 28337731Smckusick switch (vp->v_type) { 28437731Smckusick case VREG: 28539382Smckusick mode |= S_IFREG; 28637731Smckusick break; 28737731Smckusick case VDIR: 28839382Smckusick mode |= S_IFDIR; 28937731Smckusick break; 29037731Smckusick case VBLK: 29139382Smckusick mode |= S_IFBLK; 29237731Smckusick break; 29337731Smckusick case VCHR: 29439382Smckusick mode |= S_IFCHR; 29537731Smckusick break; 29637731Smckusick case VLNK: 29739382Smckusick mode |= S_IFLNK; 29837731Smckusick break; 29937731Smckusick case VSOCK: 30039382Smckusick mode |= S_IFSOCK; 30137731Smckusick break; 30240284Smckusick case VFIFO: 30340284Smckusick mode |= S_IFIFO; 30440284Smckusick break; 30537731Smckusick default: 30637731Smckusick return (EBADF); 30737731Smckusick }; 30837731Smckusick sb->st_mode = mode; 30937731Smckusick sb->st_nlink = vap->va_nlink; 31037731Smckusick sb->st_uid = vap->va_uid; 31137731Smckusick sb->st_gid = vap->va_gid; 31237731Smckusick sb->st_rdev = vap->va_rdev; 31337731Smckusick sb->st_size = vap->va_size; 31437731Smckusick sb->st_atime = vap->va_atime.tv_sec; 31537731Smckusick sb->st_spare1 = 0; 31637731Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 31737731Smckusick sb->st_spare2 = 0; 31837731Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 31937731Smckusick sb->st_spare3 = 0; 32037731Smckusick sb->st_blksize = vap->va_blocksize; 32138257Smckusick sb->st_flags = vap->va_flags; 32238257Smckusick sb->st_gen = vap->va_gen; 32338769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 32437731Smckusick return (0); 32537731Smckusick } 32637731Smckusick 32737731Smckusick /* 32850164Smckusick * File table vnode ioctl routine. 32937731Smckusick */ 33048030Smckusick vn_ioctl(fp, com, data, p) 33137731Smckusick struct file *fp; 33237731Smckusick int com; 33337731Smckusick caddr_t data; 33448030Smckusick struct proc *p; 33537731Smckusick { 33637731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 33737731Smckusick struct vattr vattr; 33837731Smckusick int error; 33937731Smckusick 34037731Smckusick switch (vp->v_type) { 34137731Smckusick 34237731Smckusick case VREG: 34337731Smckusick case VDIR: 34437731Smckusick if (com == FIONREAD) { 34548030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 34637731Smckusick return (error); 34737731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 34837731Smckusick return (0); 34918Sbill } 35037731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 35137731Smckusick return (0); /* XXX */ 35237731Smckusick /* fall into ... */ 35337731Smckusick 35437731Smckusick default: 35537731Smckusick return (ENOTTY); 35637731Smckusick 35740284Smckusick case VFIFO: 35837731Smckusick case VCHR: 35937731Smckusick case VBLK: 36048030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 36139564Smarc if (error == 0 && com == TIOCSCTTY) { 36247540Skarels p->p_session->s_ttyvp = vp; 36339564Smarc VREF(vp); 36439564Smarc } 36539564Smarc return (error); 36618Sbill } 36737731Smckusick } 36837731Smckusick 36937731Smckusick /* 37050164Smckusick * File table vnode select routine. 37137731Smckusick */ 37248030Smckusick vn_select(fp, which, p) 37337731Smckusick struct file *fp; 37437731Smckusick int which; 37548030Smckusick struct proc *p; 37637731Smckusick { 37747540Skarels 37840707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 37950164Smckusick fp->f_cred, p)); 38037731Smckusick } 38137731Smckusick 38237731Smckusick /* 38350164Smckusick * File table vnode close routine. 38437731Smckusick */ 38550164Smckusick vn_closefile(fp, p) 38650164Smckusick struct file *fp; 38748030Smckusick struct proc *p; 38837731Smckusick { 38937731Smckusick 39050164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 39150164Smckusick fp->f_cred, p)); 39237731Smckusick } 39337731Smckusick 39437731Smckusick /* 39537731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 39637731Smckusick * - look up fsid in mount list (if not found ret error) 39737731Smckusick * - get vp by calling VFS_FHTOVP() macro 39837731Smckusick * - if lockflag lock it with VOP_LOCK() 39918Sbill */ 40037731Smckusick vn_fhtovp(fhp, lockflag, vpp) 40137731Smckusick fhandle_t *fhp; 40237731Smckusick int lockflag; 40337731Smckusick struct vnode **vpp; 40418Sbill { 40537731Smckusick register struct mount *mp; 40618Sbill 40737731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 40837731Smckusick return (ESTALE); 40952191Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) 41038146Smckusick return (ESTALE); 41138146Smckusick if (!lockflag) 41238146Smckusick VOP_UNLOCK(*vpp); 41337731Smckusick return (0); 41437731Smckusick } 415