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*50164Smckusick * @(#)vfs_vnops.c 7.33 (Berkeley) 06/27/91 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 = 24*50164Smckusick { 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; 5148030Smckusick if (error = VOP_CREATE(ndp, vap, p)) 5237731Smckusick return (error); 5349943Smckusick fmode &= ~O_TRUNC; 5437731Smckusick vp = ndp->ni_vp; 5537731Smckusick } else { 5649732Smckusick VOP_ABORTOP(ndp); 5739761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 5839761Smckusick vrele(ndp->ni_dvp); 5943343Smckusick else 6039761Smckusick vput(ndp->ni_dvp); 6139761Smckusick ndp->ni_dvp = NULL; 6237731Smckusick vp = ndp->ni_vp; 6349943Smckusick if (fmode & O_EXCL) { 6437731Smckusick error = EEXIST; 6537731Smckusick goto bad; 6637731Smckusick } 6749943Smckusick fmode &= ~O_CREAT; 6837731Smckusick } 6937731Smckusick } else { 7037731Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 7147540Skarels if (error = namei(ndp, p)) 7237731Smckusick return (error); 7337731Smckusick vp = ndp->ni_vp; 7437731Smckusick } 7537731Smckusick if (vp->v_type == VSOCK) { 7637731Smckusick error = EOPNOTSUPP; 7737731Smckusick goto bad; 7837731Smckusick } 7949943Smckusick if ((fmode & O_CREAT) == 0) { 8037731Smckusick if (fmode & FREAD) { 8148030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 8237731Smckusick goto bad; 8337731Smckusick } 8449943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 8537731Smckusick if (vp->v_type == VDIR) { 8637731Smckusick error = EISDIR; 8737731Smckusick goto bad; 8837731Smckusick } 8938401Smckusick if ((error = vn_writechk(vp)) || 9048030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 9138401Smckusick goto bad; 9237731Smckusick } 9337731Smckusick } 9449943Smckusick if (fmode & O_TRUNC) { 9541362Smckusick VATTR_NULL(vap); 9637731Smckusick vap->va_size = 0; 9748030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 9837731Smckusick goto bad; 9937731Smckusick } 10050110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 10150110Smckusick goto bad; 10250110Smckusick if (fmode & FWRITE) 10350110Smckusick vp->v_writecount++; 10450110Smckusick return (0); 10537731Smckusick bad: 10637731Smckusick vput(vp); 10740707Skarels return (error); 10837731Smckusick } 10937731Smckusick 11037731Smckusick /* 11138401Smckusick * Check for write permissions on the specified vnode. 11238401Smckusick * The read-only status of the file system is checked. 11338401Smckusick * Also, prototype text segments cannot be written. 11437731Smckusick */ 11538401Smckusick vn_writechk(vp) 11637731Smckusick register struct vnode *vp; 11718Sbill { 11818Sbill 11938401Smckusick /* 12038401Smckusick * Disallow write attempts on read-only file systems; 12138401Smckusick * unless the file is a socket or a block or character 12238401Smckusick * device resident on the file system. 12338401Smckusick */ 12445060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 12545060Smckusick switch (vp->v_type) { 12645060Smckusick case VREG: case VDIR: case VLNK: 12745060Smckusick return (EROFS); 12845060Smckusick } 12945060Smckusick } 13038401Smckusick /* 13138401Smckusick * If there's shared text associated with 13238401Smckusick * the vnode, try to free it up once. If 13338401Smckusick * we fail, we can't allow writing. 13438401Smckusick */ 13545744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 13638401Smckusick return (ETXTBSY); 13738401Smckusick return (0); 13837731Smckusick } 13937731Smckusick 14037731Smckusick /* 141*50164Smckusick * Vnode close call 14237731Smckusick */ 143*50164Smckusick vn_close(vp, flags, cred, p) 144*50164Smckusick register struct vnode *vp; 145*50164Smckusick int flags; 146*50164Smckusick struct ucred *cred; 147*50164Smckusick struct proc *p; 148*50164Smckusick { 149*50164Smckusick int error; 150*50164Smckusick 151*50164Smckusick if (flags & FWRITE) 152*50164Smckusick vp->v_writecount--; 153*50164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 154*50164Smckusick vrele(vp); 155*50164Smckusick return (error); 156*50164Smckusick } 157*50164Smckusick 158*50164Smckusick /* 159*50164Smckusick * Package up an I/O request on a vnode into a uio and do it. 160*50164Smckusick */ 16148030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 16237731Smckusick enum uio_rw rw; 16337731Smckusick struct vnode *vp; 16437731Smckusick caddr_t base; 16537731Smckusick int len; 16637731Smckusick off_t offset; 16737731Smckusick enum uio_seg segflg; 16837731Smckusick int ioflg; 16937731Smckusick struct ucred *cred; 17037731Smckusick int *aresid; 17148030Smckusick struct proc *p; 17237731Smckusick { 17337731Smckusick struct uio auio; 17437731Smckusick struct iovec aiov; 17537731Smckusick int error; 17637731Smckusick 17739590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 17839590Smckusick VOP_LOCK(vp); 17937731Smckusick auio.uio_iov = &aiov; 18037731Smckusick auio.uio_iovcnt = 1; 18137731Smckusick aiov.iov_base = base; 18237731Smckusick aiov.iov_len = len; 18337731Smckusick auio.uio_resid = len; 18437731Smckusick auio.uio_offset = offset; 18537731Smckusick auio.uio_segflg = segflg; 18637731Smckusick auio.uio_rw = rw; 18748030Smckusick auio.uio_procp = p; 18837731Smckusick if (rw == UIO_READ) 18939590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 19037731Smckusick else 19139590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 19237731Smckusick if (aresid) 19337731Smckusick *aresid = auio.uio_resid; 19437731Smckusick else 19537731Smckusick if (auio.uio_resid && error == 0) 19637731Smckusick error = EIO; 19739590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 19839590Smckusick VOP_UNLOCK(vp); 19937731Smckusick return (error); 20037731Smckusick } 20137731Smckusick 202*50164Smckusick /* 203*50164Smckusick * File table vnode read routine. 204*50164Smckusick */ 20537731Smckusick vn_read(fp, uio, cred) 20637731Smckusick struct file *fp; 20737731Smckusick struct uio *uio; 20837731Smckusick struct ucred *cred; 20937731Smckusick { 21039590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 21139590Smckusick int count, error; 21237731Smckusick 21339590Smckusick VOP_LOCK(vp); 21439590Smckusick uio->uio_offset = fp->f_offset; 21539590Smckusick count = uio->uio_resid; 21649943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 21749943Smckusick cred); 21839590Smckusick fp->f_offset += count - uio->uio_resid; 21939590Smckusick VOP_UNLOCK(vp); 22039590Smckusick return (error); 22137731Smckusick } 22237731Smckusick 223*50164Smckusick /* 224*50164Smckusick * File table vnode write routine. 225*50164Smckusick */ 22637731Smckusick vn_write(fp, uio, cred) 22737731Smckusick struct file *fp; 22837731Smckusick struct uio *uio; 22937731Smckusick struct ucred *cred; 23037731Smckusick { 23137731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 23239590Smckusick int count, error, ioflag = 0; 23337731Smckusick 23449943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 23537731Smckusick ioflag |= IO_APPEND; 23649943Smckusick if (fp->f_flag & FNONBLOCK) 23737731Smckusick ioflag |= IO_NDELAY; 23839590Smckusick VOP_LOCK(vp); 23939590Smckusick uio->uio_offset = fp->f_offset; 24039590Smckusick count = uio->uio_resid; 24139590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 24239590Smckusick if (ioflag & IO_APPEND) 24339590Smckusick fp->f_offset = uio->uio_offset; 24439590Smckusick else 24539590Smckusick fp->f_offset += count - uio->uio_resid; 24639590Smckusick VOP_UNLOCK(vp); 24739590Smckusick return (error); 24837731Smckusick } 24937731Smckusick 25037731Smckusick /* 251*50164Smckusick * File table vnode stat routine. 25237731Smckusick */ 25348030Smckusick vn_stat(vp, sb, p) 25437731Smckusick struct vnode *vp; 25537731Smckusick register struct stat *sb; 25648030Smckusick struct proc *p; 25737731Smckusick { 25837731Smckusick struct vattr vattr; 25937731Smckusick register struct vattr *vap; 26037731Smckusick int error; 26137731Smckusick u_short mode; 26237731Smckusick 26337731Smckusick vap = &vattr; 26448030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 26537731Smckusick if (error) 26637731Smckusick return (error); 26737731Smckusick /* 26837731Smckusick * Copy from vattr table 26937731Smckusick */ 27037731Smckusick sb->st_dev = vap->va_fsid; 27137731Smckusick sb->st_ino = vap->va_fileid; 27237731Smckusick mode = vap->va_mode; 27337731Smckusick switch (vp->v_type) { 27437731Smckusick case VREG: 27539382Smckusick mode |= S_IFREG; 27637731Smckusick break; 27737731Smckusick case VDIR: 27839382Smckusick mode |= S_IFDIR; 27937731Smckusick break; 28037731Smckusick case VBLK: 28139382Smckusick mode |= S_IFBLK; 28237731Smckusick break; 28337731Smckusick case VCHR: 28439382Smckusick mode |= S_IFCHR; 28537731Smckusick break; 28637731Smckusick case VLNK: 28739382Smckusick mode |= S_IFLNK; 28837731Smckusick break; 28937731Smckusick case VSOCK: 29039382Smckusick mode |= S_IFSOCK; 29137731Smckusick break; 29240284Smckusick case VFIFO: 29340284Smckusick mode |= S_IFIFO; 29440284Smckusick break; 29537731Smckusick default: 29637731Smckusick return (EBADF); 29737731Smckusick }; 29837731Smckusick sb->st_mode = mode; 29937731Smckusick sb->st_nlink = vap->va_nlink; 30037731Smckusick sb->st_uid = vap->va_uid; 30137731Smckusick sb->st_gid = vap->va_gid; 30237731Smckusick sb->st_rdev = vap->va_rdev; 30337731Smckusick sb->st_size = vap->va_size; 30437731Smckusick sb->st_atime = vap->va_atime.tv_sec; 30537731Smckusick sb->st_spare1 = 0; 30637731Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 30737731Smckusick sb->st_spare2 = 0; 30837731Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 30937731Smckusick sb->st_spare3 = 0; 31037731Smckusick sb->st_blksize = vap->va_blocksize; 31138257Smckusick sb->st_flags = vap->va_flags; 31238257Smckusick sb->st_gen = vap->va_gen; 31338769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 31437731Smckusick return (0); 31537731Smckusick } 31637731Smckusick 31737731Smckusick /* 318*50164Smckusick * File table vnode ioctl routine. 31937731Smckusick */ 32048030Smckusick vn_ioctl(fp, com, data, p) 32137731Smckusick struct file *fp; 32237731Smckusick int com; 32337731Smckusick caddr_t data; 32448030Smckusick struct proc *p; 32537731Smckusick { 32637731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 32737731Smckusick struct vattr vattr; 32837731Smckusick int error; 32937731Smckusick 33037731Smckusick switch (vp->v_type) { 33137731Smckusick 33237731Smckusick case VREG: 33337731Smckusick case VDIR: 33437731Smckusick if (com == FIONREAD) { 33548030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 33637731Smckusick return (error); 33737731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 33837731Smckusick return (0); 33918Sbill } 34037731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 34137731Smckusick return (0); /* XXX */ 34237731Smckusick /* fall into ... */ 34337731Smckusick 34437731Smckusick default: 34537731Smckusick return (ENOTTY); 34637731Smckusick 34740284Smckusick case VFIFO: 34837731Smckusick case VCHR: 34937731Smckusick case VBLK: 35048030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 35139564Smarc if (error == 0 && com == TIOCSCTTY) { 35247540Skarels p->p_session->s_ttyvp = vp; 35339564Smarc VREF(vp); 35439564Smarc } 35539564Smarc return (error); 35618Sbill } 35737731Smckusick } 35837731Smckusick 35937731Smckusick /* 360*50164Smckusick * File table vnode select routine. 36137731Smckusick */ 36248030Smckusick vn_select(fp, which, p) 36337731Smckusick struct file *fp; 36437731Smckusick int which; 36548030Smckusick struct proc *p; 36637731Smckusick { 36747540Skarels 36840707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 369*50164Smckusick fp->f_cred, p)); 37037731Smckusick } 37137731Smckusick 37237731Smckusick /* 373*50164Smckusick * File table vnode close routine. 37437731Smckusick */ 375*50164Smckusick vn_closefile(fp, p) 376*50164Smckusick struct file *fp; 37748030Smckusick struct proc *p; 37837731Smckusick { 37937731Smckusick 380*50164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 381*50164Smckusick fp->f_cred, p)); 38237731Smckusick } 38337731Smckusick 38437731Smckusick /* 38537731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 38637731Smckusick * - look up fsid in mount list (if not found ret error) 38737731Smckusick * - get vp by calling VFS_FHTOVP() macro 38837731Smckusick * - if lockflag lock it with VOP_LOCK() 38918Sbill */ 39037731Smckusick vn_fhtovp(fhp, lockflag, vpp) 39137731Smckusick fhandle_t *fhp; 39237731Smckusick int lockflag; 39337731Smckusick struct vnode **vpp; 39418Sbill { 39537731Smckusick register struct mount *mp; 39618Sbill 39737731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 39837731Smckusick return (ESTALE); 39938146Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 40038146Smckusick return (ESTALE); 40138146Smckusick if (!lockflag) 40238146Smckusick VOP_UNLOCK(*vpp); 40337731Smckusick return (0); 40437731Smckusick } 405