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*68321Scgd * @(#)vfs_vnops.c 8.7 (Berkeley) 02/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; 5967655Smckusick VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE); 6052310Smckusick if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 6152310Smckusick &ndp->ni_cnd, vap)) 6237731Smckusick return (error); 6349943Smckusick fmode &= ~O_TRUNC; 6437731Smckusick vp = ndp->ni_vp; 6537731Smckusick } else { 6652230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 6739761Smckusick if (ndp->ni_dvp == ndp->ni_vp) 6839761Smckusick vrele(ndp->ni_dvp); 6943343Smckusick else 7039761Smckusick vput(ndp->ni_dvp); 7139761Smckusick ndp->ni_dvp = NULL; 7237731Smckusick vp = ndp->ni_vp; 7349943Smckusick if (fmode & O_EXCL) { 7437731Smckusick error = EEXIST; 7537731Smckusick goto bad; 7637731Smckusick } 7749943Smckusick fmode &= ~O_CREAT; 7837731Smckusick } 7937731Smckusick } else { 8052310Smckusick ndp->ni_cnd.cn_nameiop = LOOKUP; 8152310Smckusick ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 8252310Smckusick if (error = namei(ndp)) 8337731Smckusick return (error); 8437731Smckusick vp = ndp->ni_vp; 8537731Smckusick } 8637731Smckusick if (vp->v_type == VSOCK) { 8737731Smckusick error = EOPNOTSUPP; 8837731Smckusick goto bad; 8937731Smckusick } 9049943Smckusick if ((fmode & O_CREAT) == 0) { 9137731Smckusick if (fmode & FREAD) { 9248030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 9337731Smckusick goto bad; 9437731Smckusick } 9549943Smckusick if (fmode & (FWRITE | O_TRUNC)) { 9637731Smckusick if (vp->v_type == VDIR) { 9737731Smckusick error = EISDIR; 9837731Smckusick goto bad; 9937731Smckusick } 10038401Smckusick if ((error = vn_writechk(vp)) || 10148030Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 10238401Smckusick goto bad; 10337731Smckusick } 10437731Smckusick } 10549943Smckusick if (fmode & O_TRUNC) { 10659381Smckusick VOP_UNLOCK(vp); /* XXX */ 10767655Smckusick VOP_LEASE(vp, p, cred, LEASE_WRITE); 10859381Smckusick VOP_LOCK(vp); /* XXX */ 10941362Smckusick VATTR_NULL(vap); 11037731Smckusick vap->va_size = 0; 11148030Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 11237731Smckusick goto bad; 11337731Smckusick } 11450110Smckusick if (error = VOP_OPEN(vp, fmode, cred, p)) 11550110Smckusick goto bad; 11650110Smckusick if (fmode & FWRITE) 11750110Smckusick vp->v_writecount++; 11850110Smckusick return (0); 11937731Smckusick bad: 12037731Smckusick vput(vp); 12140707Skarels return (error); 12237731Smckusick } 12337731Smckusick 12437731Smckusick /* 12538401Smckusick * Check for write permissions on the specified vnode. 12638401Smckusick * The read-only status of the file system is checked. 12738401Smckusick * Also, prototype text segments cannot be written. 12837731Smckusick */ 12938401Smckusick vn_writechk(vp) 13037731Smckusick register struct vnode *vp; 13118Sbill { 13218Sbill 13338401Smckusick /* 13438401Smckusick * Disallow write attempts on read-only file systems; 13538401Smckusick * unless the file is a socket or a block or character 13638401Smckusick * device resident on the file system. 13738401Smckusick */ 13845060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 13945060Smckusick switch (vp->v_type) { 14045060Smckusick case VREG: case VDIR: case VLNK: 14145060Smckusick return (EROFS); 14245060Smckusick } 14345060Smckusick } 14438401Smckusick /* 14538401Smckusick * If there's shared text associated with 14638401Smckusick * the vnode, try to free it up once. If 14738401Smckusick * we fail, we can't allow writing. 14838401Smckusick */ 14945744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 15038401Smckusick return (ETXTBSY); 15138401Smckusick return (0); 15237731Smckusick } 15337731Smckusick 15437731Smckusick /* 15550164Smckusick * Vnode close call 15637731Smckusick */ 15750164Smckusick vn_close(vp, flags, cred, p) 15850164Smckusick register struct vnode *vp; 15950164Smckusick int flags; 16050164Smckusick struct ucred *cred; 16150164Smckusick struct proc *p; 16250164Smckusick { 16350164Smckusick int error; 16450164Smckusick 16550164Smckusick if (flags & FWRITE) 16650164Smckusick vp->v_writecount--; 16750164Smckusick error = VOP_CLOSE(vp, flags, cred, p); 16850164Smckusick vrele(vp); 16950164Smckusick return (error); 17050164Smckusick } 17150164Smckusick 17250164Smckusick /* 17350164Smckusick * Package up an I/O request on a vnode into a uio and do it. 17450164Smckusick */ 17548030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 17637731Smckusick enum uio_rw rw; 17737731Smckusick struct vnode *vp; 17837731Smckusick caddr_t base; 17937731Smckusick int len; 18037731Smckusick off_t offset; 18137731Smckusick enum uio_seg segflg; 18237731Smckusick int ioflg; 18337731Smckusick struct ucred *cred; 18437731Smckusick int *aresid; 18548030Smckusick struct proc *p; 18637731Smckusick { 18737731Smckusick struct uio auio; 18837731Smckusick struct iovec aiov; 18937731Smckusick int error; 19037731Smckusick 19139590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 19239590Smckusick VOP_LOCK(vp); 19337731Smckusick auio.uio_iov = &aiov; 19437731Smckusick auio.uio_iovcnt = 1; 19537731Smckusick aiov.iov_base = base; 19637731Smckusick aiov.iov_len = len; 19737731Smckusick auio.uio_resid = len; 19837731Smckusick auio.uio_offset = offset; 19937731Smckusick auio.uio_segflg = segflg; 20037731Smckusick auio.uio_rw = rw; 20148030Smckusick auio.uio_procp = p; 20252191Smckusick if (rw == UIO_READ) { 20339590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 20452191Smckusick } else { 20539590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 20652191Smckusick } 20737731Smckusick if (aresid) 20837731Smckusick *aresid = auio.uio_resid; 20937731Smckusick else 21037731Smckusick if (auio.uio_resid && error == 0) 21137731Smckusick error = EIO; 21239590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 21339590Smckusick VOP_UNLOCK(vp); 21437731Smckusick return (error); 21537731Smckusick } 21637731Smckusick 21750164Smckusick /* 21850164Smckusick * File table vnode read routine. 21950164Smckusick */ 22037731Smckusick vn_read(fp, uio, cred) 22137731Smckusick struct file *fp; 22237731Smckusick struct uio *uio; 22337731Smckusick struct ucred *cred; 22437731Smckusick { 22539590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 22639590Smckusick int count, error; 22737731Smckusick 22867655Smckusick VOP_LEASE(vp, uio->uio_procp, cred, LEASE_READ); 22939590Smckusick VOP_LOCK(vp); 23039590Smckusick uio->uio_offset = fp->f_offset; 23139590Smckusick count = uio->uio_resid; 23249943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 23349943Smckusick cred); 23439590Smckusick fp->f_offset += count - uio->uio_resid; 23539590Smckusick VOP_UNLOCK(vp); 23639590Smckusick return (error); 23737731Smckusick } 23837731Smckusick 23950164Smckusick /* 24050164Smckusick * File table vnode write routine. 24150164Smckusick */ 24237731Smckusick vn_write(fp, uio, cred) 24337731Smckusick struct file *fp; 24437731Smckusick struct uio *uio; 24537731Smckusick struct ucred *cred; 24637731Smckusick { 24737731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 24868064Smckusick int count, error, ioflag = IO_UNIT; 24937731Smckusick 25049943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 25137731Smckusick ioflag |= IO_APPEND; 25249943Smckusick if (fp->f_flag & FNONBLOCK) 25337731Smckusick ioflag |= IO_NDELAY; 25467655Smckusick VOP_LEASE(vp, uio->uio_procp, cred, LEASE_WRITE); 25539590Smckusick VOP_LOCK(vp); 25639590Smckusick uio->uio_offset = fp->f_offset; 25739590Smckusick count = uio->uio_resid; 25839590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 25939590Smckusick if (ioflag & IO_APPEND) 26039590Smckusick fp->f_offset = uio->uio_offset; 26139590Smckusick else 26239590Smckusick fp->f_offset += count - uio->uio_resid; 26339590Smckusick VOP_UNLOCK(vp); 26439590Smckusick return (error); 26537731Smckusick } 26637731Smckusick 26737731Smckusick /* 26850164Smckusick * File table vnode stat routine. 26937731Smckusick */ 27048030Smckusick vn_stat(vp, sb, p) 27137731Smckusick struct vnode *vp; 27237731Smckusick register struct stat *sb; 27348030Smckusick struct proc *p; 27437731Smckusick { 27537731Smckusick struct vattr vattr; 27637731Smckusick register struct vattr *vap; 27737731Smckusick int error; 27837731Smckusick u_short mode; 27937731Smckusick 28037731Smckusick vap = &vattr; 28148030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 28237731Smckusick if (error) 28337731Smckusick return (error); 28437731Smckusick /* 28537731Smckusick * Copy from vattr table 28637731Smckusick */ 28737731Smckusick sb->st_dev = vap->va_fsid; 28837731Smckusick sb->st_ino = vap->va_fileid; 28937731Smckusick mode = vap->va_mode; 29037731Smckusick switch (vp->v_type) { 29137731Smckusick case VREG: 29239382Smckusick mode |= S_IFREG; 29337731Smckusick break; 29437731Smckusick case VDIR: 29539382Smckusick mode |= S_IFDIR; 29637731Smckusick break; 29737731Smckusick case VBLK: 29839382Smckusick mode |= S_IFBLK; 29937731Smckusick break; 30037731Smckusick case VCHR: 30139382Smckusick mode |= S_IFCHR; 30237731Smckusick break; 30337731Smckusick case VLNK: 30439382Smckusick mode |= S_IFLNK; 30537731Smckusick break; 30637731Smckusick case VSOCK: 30739382Smckusick mode |= S_IFSOCK; 30837731Smckusick break; 30940284Smckusick case VFIFO: 31040284Smckusick mode |= S_IFIFO; 31140284Smckusick break; 31237731Smckusick default: 31337731Smckusick return (EBADF); 31437731Smckusick }; 31537731Smckusick sb->st_mode = mode; 31637731Smckusick sb->st_nlink = vap->va_nlink; 31737731Smckusick sb->st_uid = vap->va_uid; 31837731Smckusick sb->st_gid = vap->va_gid; 31937731Smckusick sb->st_rdev = vap->va_rdev; 32037731Smckusick sb->st_size = vap->va_size; 32154100Smckusick sb->st_atimespec = vap->va_atime; 322*68321Scgd sb->st_mtimespec = vap->va_mtime; 32354100Smckusick sb->st_ctimespec = vap->va_ctime; 32437731Smckusick sb->st_blksize = vap->va_blocksize; 32538257Smckusick sb->st_flags = vap->va_flags; 32638257Smckusick sb->st_gen = vap->va_gen; 32738769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 32837731Smckusick return (0); 32937731Smckusick } 33037731Smckusick 33137731Smckusick /* 33250164Smckusick * File table vnode ioctl routine. 33337731Smckusick */ 33448030Smckusick vn_ioctl(fp, com, data, p) 33537731Smckusick struct file *fp; 33668171Scgd u_long com; 33737731Smckusick caddr_t data; 33848030Smckusick struct proc *p; 33937731Smckusick { 34037731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 34137731Smckusick struct vattr vattr; 34237731Smckusick int error; 34337731Smckusick 34437731Smckusick switch (vp->v_type) { 34537731Smckusick 34637731Smckusick case VREG: 34737731Smckusick case VDIR: 34837731Smckusick if (com == FIONREAD) { 34948030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 35037731Smckusick return (error); 35154772Storek *(int *)data = vattr.va_size - fp->f_offset; 35237731Smckusick return (0); 35318Sbill } 35437731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 35537731Smckusick return (0); /* XXX */ 35637731Smckusick /* fall into ... */ 35737731Smckusick 35837731Smckusick default: 35937731Smckusick return (ENOTTY); 36037731Smckusick 36140284Smckusick case VFIFO: 36237731Smckusick case VCHR: 36337731Smckusick case VBLK: 36448030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 36539564Smarc if (error == 0 && com == TIOCSCTTY) { 36667686Smckusick if (p->p_session->s_ttyvp) 36767686Smckusick vrele(p->p_session->s_ttyvp); 36847540Skarels p->p_session->s_ttyvp = vp; 36939564Smarc VREF(vp); 37039564Smarc } 37139564Smarc return (error); 37218Sbill } 37337731Smckusick } 37437731Smckusick 37537731Smckusick /* 37650164Smckusick * File table vnode select routine. 37737731Smckusick */ 37848030Smckusick vn_select(fp, which, p) 37937731Smckusick struct file *fp; 38037731Smckusick int which; 38148030Smckusick struct proc *p; 38237731Smckusick { 38347540Skarels 38440707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 38550164Smckusick fp->f_cred, p)); 38637731Smckusick } 38737731Smckusick 38837731Smckusick /* 38950164Smckusick * File table vnode close routine. 39037731Smckusick */ 39150164Smckusick vn_closefile(fp, p) 39250164Smckusick struct file *fp; 39348030Smckusick struct proc *p; 39437731Smckusick { 39537731Smckusick 39650164Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 39750164Smckusick fp->f_cred, p)); 39837731Smckusick } 399