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*49943Smckusick * @(#)vfs_vnops.c 7.31 (Berkeley) 05/30/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 = 2437731Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; 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 41*49943Smckusick if (fmode & O_CREAT) { 4237731Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 43*49943Smckusick 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); 53*49943Smckusick 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; 63*49943Smckusick if (fmode & O_EXCL) { 6437731Smckusick error = EEXIST; 6537731Smckusick goto bad; 6637731Smckusick } 67*49943Smckusick 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 } 79*49943Smckusick if ((fmode & O_CREAT) == 0) { 8037731Smckusick if (fmode & FREAD) { 8148030Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 8237731Smckusick goto bad; 8337731Smckusick } 84*49943Smckusick 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 } 94*49943Smckusick 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 } 100*49943Smckusick if ((error = VOP_OPEN(vp, fmode, cred, p)) == 0) 101*49943Smckusick return (0); 10237731Smckusick bad: 10337731Smckusick vput(vp); 10440707Skarels return (error); 10537731Smckusick } 10637731Smckusick 10737731Smckusick /* 10838401Smckusick * Check for write permissions on the specified vnode. 10938401Smckusick * The read-only status of the file system is checked. 11038401Smckusick * Also, prototype text segments cannot be written. 11137731Smckusick */ 11238401Smckusick vn_writechk(vp) 11337731Smckusick register struct vnode *vp; 11418Sbill { 11518Sbill 11638401Smckusick /* 11738401Smckusick * Disallow write attempts on read-only file systems; 11838401Smckusick * unless the file is a socket or a block or character 11938401Smckusick * device resident on the file system. 12038401Smckusick */ 12145060Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 12245060Smckusick switch (vp->v_type) { 12345060Smckusick case VREG: case VDIR: case VLNK: 12445060Smckusick return (EROFS); 12545060Smckusick } 12645060Smckusick } 12738401Smckusick /* 12838401Smckusick * If there's shared text associated with 12938401Smckusick * the vnode, try to free it up once. If 13038401Smckusick * we fail, we can't allow writing. 13138401Smckusick */ 13245744Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 13338401Smckusick return (ETXTBSY); 13438401Smckusick return (0); 13537731Smckusick } 13637731Smckusick 13737731Smckusick /* 13837731Smckusick * Vnode version of rdwri() for calls on file systems. 13937731Smckusick */ 14048030Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 14137731Smckusick enum uio_rw rw; 14237731Smckusick struct vnode *vp; 14337731Smckusick caddr_t base; 14437731Smckusick int len; 14537731Smckusick off_t offset; 14637731Smckusick enum uio_seg segflg; 14737731Smckusick int ioflg; 14837731Smckusick struct ucred *cred; 14937731Smckusick int *aresid; 15048030Smckusick struct proc *p; 15137731Smckusick { 15237731Smckusick struct uio auio; 15337731Smckusick struct iovec aiov; 15437731Smckusick int error; 15537731Smckusick 15639590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 15739590Smckusick VOP_LOCK(vp); 15837731Smckusick auio.uio_iov = &aiov; 15937731Smckusick auio.uio_iovcnt = 1; 16037731Smckusick aiov.iov_base = base; 16137731Smckusick aiov.iov_len = len; 16237731Smckusick auio.uio_resid = len; 16337731Smckusick auio.uio_offset = offset; 16437731Smckusick auio.uio_segflg = segflg; 16537731Smckusick auio.uio_rw = rw; 16648030Smckusick auio.uio_procp = p; 16737731Smckusick if (rw == UIO_READ) 16839590Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 16937731Smckusick else 17039590Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 17137731Smckusick if (aresid) 17237731Smckusick *aresid = auio.uio_resid; 17337731Smckusick else 17437731Smckusick if (auio.uio_resid && error == 0) 17537731Smckusick error = EIO; 17639590Smckusick if ((ioflg & IO_NODELOCKED) == 0) 17739590Smckusick VOP_UNLOCK(vp); 17837731Smckusick return (error); 17937731Smckusick } 18037731Smckusick 18137731Smckusick vn_read(fp, uio, cred) 18237731Smckusick struct file *fp; 18337731Smckusick struct uio *uio; 18437731Smckusick struct ucred *cred; 18537731Smckusick { 18639590Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 18739590Smckusick int count, error; 18837731Smckusick 18939590Smckusick VOP_LOCK(vp); 19039590Smckusick uio->uio_offset = fp->f_offset; 19139590Smckusick count = uio->uio_resid; 192*49943Smckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 193*49943Smckusick cred); 19439590Smckusick fp->f_offset += count - uio->uio_resid; 19539590Smckusick VOP_UNLOCK(vp); 19639590Smckusick return (error); 19737731Smckusick } 19837731Smckusick 19937731Smckusick vn_write(fp, uio, cred) 20037731Smckusick struct file *fp; 20137731Smckusick struct uio *uio; 20237731Smckusick struct ucred *cred; 20337731Smckusick { 20437731Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 20539590Smckusick int count, error, ioflag = 0; 20637731Smckusick 207*49943Smckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 20837731Smckusick ioflag |= IO_APPEND; 209*49943Smckusick if (fp->f_flag & FNONBLOCK) 21037731Smckusick ioflag |= IO_NDELAY; 21139590Smckusick VOP_LOCK(vp); 21239590Smckusick uio->uio_offset = fp->f_offset; 21339590Smckusick count = uio->uio_resid; 21439590Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 21539590Smckusick if (ioflag & IO_APPEND) 21639590Smckusick fp->f_offset = uio->uio_offset; 21739590Smckusick else 21839590Smckusick fp->f_offset += count - uio->uio_resid; 21939590Smckusick VOP_UNLOCK(vp); 22039590Smckusick return (error); 22137731Smckusick } 22237731Smckusick 22337731Smckusick /* 22437731Smckusick * Get stat info for a vnode. 22537731Smckusick */ 22648030Smckusick vn_stat(vp, sb, p) 22737731Smckusick struct vnode *vp; 22837731Smckusick register struct stat *sb; 22948030Smckusick struct proc *p; 23037731Smckusick { 23137731Smckusick struct vattr vattr; 23237731Smckusick register struct vattr *vap; 23337731Smckusick int error; 23437731Smckusick u_short mode; 23537731Smckusick 23637731Smckusick vap = &vattr; 23748030Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 23837731Smckusick if (error) 23937731Smckusick return (error); 24037731Smckusick /* 24137731Smckusick * Copy from vattr table 24237731Smckusick */ 24337731Smckusick sb->st_dev = vap->va_fsid; 24437731Smckusick sb->st_ino = vap->va_fileid; 24537731Smckusick mode = vap->va_mode; 24637731Smckusick switch (vp->v_type) { 24737731Smckusick case VREG: 24839382Smckusick mode |= S_IFREG; 24937731Smckusick break; 25037731Smckusick case VDIR: 25139382Smckusick mode |= S_IFDIR; 25237731Smckusick break; 25337731Smckusick case VBLK: 25439382Smckusick mode |= S_IFBLK; 25537731Smckusick break; 25637731Smckusick case VCHR: 25739382Smckusick mode |= S_IFCHR; 25837731Smckusick break; 25937731Smckusick case VLNK: 26039382Smckusick mode |= S_IFLNK; 26137731Smckusick break; 26237731Smckusick case VSOCK: 26339382Smckusick mode |= S_IFSOCK; 26437731Smckusick break; 26540284Smckusick case VFIFO: 26640284Smckusick mode |= S_IFIFO; 26740284Smckusick break; 26837731Smckusick default: 26937731Smckusick return (EBADF); 27037731Smckusick }; 27137731Smckusick sb->st_mode = mode; 27237731Smckusick sb->st_nlink = vap->va_nlink; 27337731Smckusick sb->st_uid = vap->va_uid; 27437731Smckusick sb->st_gid = vap->va_gid; 27537731Smckusick sb->st_rdev = vap->va_rdev; 27637731Smckusick sb->st_size = vap->va_size; 27737731Smckusick sb->st_atime = vap->va_atime.tv_sec; 27837731Smckusick sb->st_spare1 = 0; 27937731Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 28037731Smckusick sb->st_spare2 = 0; 28137731Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 28237731Smckusick sb->st_spare3 = 0; 28337731Smckusick sb->st_blksize = vap->va_blocksize; 28438257Smckusick sb->st_flags = vap->va_flags; 28538257Smckusick sb->st_gen = vap->va_gen; 28638769Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 28737731Smckusick return (0); 28837731Smckusick } 28937731Smckusick 29037731Smckusick /* 29137731Smckusick * Vnode ioctl call 29237731Smckusick */ 29348030Smckusick vn_ioctl(fp, com, data, p) 29437731Smckusick struct file *fp; 29537731Smckusick int com; 29637731Smckusick caddr_t data; 29748030Smckusick struct proc *p; 29837731Smckusick { 29937731Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 30037731Smckusick struct vattr vattr; 30137731Smckusick int error; 30237731Smckusick 30337731Smckusick switch (vp->v_type) { 30437731Smckusick 30537731Smckusick case VREG: 30637731Smckusick case VDIR: 30737731Smckusick if (com == FIONREAD) { 30848030Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 30937731Smckusick return (error); 31037731Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 31137731Smckusick return (0); 31218Sbill } 31337731Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 31437731Smckusick return (0); /* XXX */ 31537731Smckusick /* fall into ... */ 31637731Smckusick 31737731Smckusick default: 31837731Smckusick return (ENOTTY); 31937731Smckusick 32040284Smckusick case VFIFO: 32137731Smckusick case VCHR: 32237731Smckusick case VBLK: 32348030Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 32439564Smarc if (error == 0 && com == TIOCSCTTY) { 32547540Skarels p->p_session->s_ttyvp = vp; 32639564Smarc VREF(vp); 32739564Smarc } 32839564Smarc return (error); 32918Sbill } 33037731Smckusick } 33137731Smckusick 33237731Smckusick /* 33337731Smckusick * Vnode select call 33437731Smckusick */ 33548030Smckusick vn_select(fp, which, p) 33637731Smckusick struct file *fp; 33737731Smckusick int which; 33848030Smckusick struct proc *p; 33937731Smckusick { 34047540Skarels 34140707Skarels return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 34248030Smckusick p->p_ucred, p)); 34337731Smckusick } 34437731Smckusick 34537731Smckusick /* 34637731Smckusick * Vnode close call 34737731Smckusick */ 34848030Smckusick vn_close(fp, p) 34937731Smckusick register struct file *fp; 35048030Smckusick struct proc *p; 35137731Smckusick { 35237731Smckusick struct vnode *vp = ((struct vnode *)fp->f_data); 35337731Smckusick int error; 35437731Smckusick 35511162Ssam /* 35637731Smckusick * Must delete vnode reference from this file entry 35737731Smckusick * before VOP_CLOSE, so that only other references 35837731Smckusick * will prevent close. 35911162Ssam */ 36037731Smckusick fp->f_data = (caddr_t) 0; 36148030Smckusick error = VOP_CLOSE(vp, fp->f_flag, fp->f_cred, p); 36237731Smckusick vrele(vp); 36337731Smckusick return (error); 36437731Smckusick } 36537731Smckusick 36637731Smckusick /* 36737731Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 36837731Smckusick * - look up fsid in mount list (if not found ret error) 36937731Smckusick * - get vp by calling VFS_FHTOVP() macro 37037731Smckusick * - if lockflag lock it with VOP_LOCK() 37118Sbill */ 37237731Smckusick vn_fhtovp(fhp, lockflag, vpp) 37337731Smckusick fhandle_t *fhp; 37437731Smckusick int lockflag; 37537731Smckusick struct vnode **vpp; 37618Sbill { 37737731Smckusick register struct mount *mp; 37818Sbill 37937731Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 38037731Smckusick return (ESTALE); 38138146Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 38238146Smckusick return (ESTALE); 38338146Smckusick if (!lockflag) 38438146Smckusick VOP_UNLOCK(*vpp); 38537731Smckusick return (0); 38637731Smckusick } 387