1b5970980Smckusick /* 2760e73c7Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3760e73c7Smckusick * All rights reserved. 4b5970980Smckusick * 573a8e095Sbostic * %sccs.include.redist.c% 6760e73c7Smckusick * 7*552d28cbSmckusick * @(#)vfs_vnops.c 7.31 (Berkeley) 05/30/91 8b5970980Smckusick */ 982e77ef7Ssam 10ecd0bebeSbloom #include "param.h" 11ecd0bebeSbloom #include "systm.h" 12760e73c7Smckusick #include "kernel.h" 13ecd0bebeSbloom #include "file.h" 14760e73c7Smckusick #include "stat.h" 15760e73c7Smckusick #include "buf.h" 16760e73c7Smckusick #include "proc.h" 17760e73c7Smckusick #include "mount.h" 182d8de7e9Smckusick #include "namei.h" 19760e73c7Smckusick #include "vnode.h" 20760e73c7Smckusick #include "ioctl.h" 21760e73c7Smckusick #include "tty.h" 221d37f34bSbill 23760e73c7Smckusick struct fileops vnops = 24760e73c7Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; 25ae1aeb7bSmckusick 261d37f34bSbill /* 27760e73c7Smckusick * Common code for vnode open operations. 28760e73c7Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 291d37f34bSbill */ 300b0833e3Skarels vn_open(ndp, p, fmode, cmode) 31760e73c7Smckusick register struct nameidata *ndp; 320b0833e3Skarels struct proc *p; 33760e73c7Smckusick int fmode, cmode; 341d37f34bSbill { 35760e73c7Smckusick register struct vnode *vp; 360b0833e3Skarels register struct ucred *cred = p->p_ucred; 37760e73c7Smckusick struct vattr vat; 38760e73c7Smckusick struct vattr *vap = &vat; 39760e73c7Smckusick int error; 401d37f34bSbill 41*552d28cbSmckusick if (fmode & O_CREAT) { 42760e73c7Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 43*552d28cbSmckusick if ((fmode & O_EXCL) == 0) 44760e73c7Smckusick ndp->ni_nameiop |= FOLLOW; 450b0833e3Skarels if (error = namei(ndp, p)) 46760e73c7Smckusick return (error); 47760e73c7Smckusick if (ndp->ni_vp == NULL) { 489a8d5e2aSmckusick VATTR_NULL(vap); 49760e73c7Smckusick vap->va_type = VREG; 50760e73c7Smckusick vap->va_mode = cmode; 512d8de7e9Smckusick if (error = VOP_CREATE(ndp, vap, p)) 52760e73c7Smckusick return (error); 53*552d28cbSmckusick fmode &= ~O_TRUNC; 54760e73c7Smckusick vp = ndp->ni_vp; 55760e73c7Smckusick } else { 56ebdb0513Smckusick VOP_ABORTOP(ndp); 5783225eaeSmckusick if (ndp->ni_dvp == ndp->ni_vp) 5883225eaeSmckusick vrele(ndp->ni_dvp); 59e8a20c25Smckusick else 6083225eaeSmckusick vput(ndp->ni_dvp); 6183225eaeSmckusick ndp->ni_dvp = NULL; 62760e73c7Smckusick vp = ndp->ni_vp; 63*552d28cbSmckusick if (fmode & O_EXCL) { 64760e73c7Smckusick error = EEXIST; 65760e73c7Smckusick goto bad; 66760e73c7Smckusick } 67*552d28cbSmckusick fmode &= ~O_CREAT; 68760e73c7Smckusick } 69760e73c7Smckusick } else { 70760e73c7Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 710b0833e3Skarels if (error = namei(ndp, p)) 72760e73c7Smckusick return (error); 73760e73c7Smckusick vp = ndp->ni_vp; 74760e73c7Smckusick } 75760e73c7Smckusick if (vp->v_type == VSOCK) { 76760e73c7Smckusick error = EOPNOTSUPP; 77760e73c7Smckusick goto bad; 78760e73c7Smckusick } 79*552d28cbSmckusick if ((fmode & O_CREAT) == 0) { 80760e73c7Smckusick if (fmode & FREAD) { 812d8de7e9Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p)) 82760e73c7Smckusick goto bad; 83760e73c7Smckusick } 84*552d28cbSmckusick if (fmode & (FWRITE | O_TRUNC)) { 85760e73c7Smckusick if (vp->v_type == VDIR) { 86760e73c7Smckusick error = EISDIR; 87760e73c7Smckusick goto bad; 88760e73c7Smckusick } 89a597f5e9Smckusick if ((error = vn_writechk(vp)) || 902d8de7e9Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))) 91a597f5e9Smckusick goto bad; 92760e73c7Smckusick } 93760e73c7Smckusick } 94*552d28cbSmckusick if (fmode & O_TRUNC) { 959a8d5e2aSmckusick VATTR_NULL(vap); 96760e73c7Smckusick vap->va_size = 0; 972d8de7e9Smckusick if (error = VOP_SETATTR(vp, vap, cred, p)) 98760e73c7Smckusick goto bad; 99760e73c7Smckusick } 100*552d28cbSmckusick if ((error = VOP_OPEN(vp, fmode, cred, p)) == 0) 101*552d28cbSmckusick return (0); 102760e73c7Smckusick bad: 103760e73c7Smckusick vput(vp); 104760e73c7Smckusick return (error); 105760e73c7Smckusick } 106760e73c7Smckusick 10745db6fc1Ssam /* 108a597f5e9Smckusick * Check for write permissions on the specified vnode. 109a597f5e9Smckusick * The read-only status of the file system is checked. 110a597f5e9Smckusick * Also, prototype text segments cannot be written. 11145db6fc1Ssam */ 112a597f5e9Smckusick vn_writechk(vp) 113760e73c7Smckusick register struct vnode *vp; 114760e73c7Smckusick { 115760e73c7Smckusick 116760e73c7Smckusick /* 117760e73c7Smckusick * Disallow write attempts on read-only file systems; 118760e73c7Smckusick * unless the file is a socket or a block or character 119760e73c7Smckusick * device resident on the file system. 120760e73c7Smckusick */ 1219fc842b5Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 1229fc842b5Smckusick switch (vp->v_type) { 1239fc842b5Smckusick case VREG: case VDIR: case VLNK: 124760e73c7Smckusick return (EROFS); 1259fc842b5Smckusick } 1269fc842b5Smckusick } 12745db6fc1Ssam /* 12845db6fc1Ssam * If there's shared text associated with 129a597f5e9Smckusick * the vnode, try to free it up once. If 13045db6fc1Ssam * we fail, we can't allow writing. 13145db6fc1Ssam */ 1323065037bSmckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 133760e73c7Smckusick return (ETXTBSY); 134a597f5e9Smckusick return (0); 1351d37f34bSbill } 1361d37f34bSbill 1371d37f34bSbill /* 138760e73c7Smckusick * Vnode version of rdwri() for calls on file systems. 1391d37f34bSbill */ 1402d8de7e9Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 141760e73c7Smckusick enum uio_rw rw; 142760e73c7Smckusick struct vnode *vp; 143760e73c7Smckusick caddr_t base; 144760e73c7Smckusick int len; 145760e73c7Smckusick off_t offset; 146760e73c7Smckusick enum uio_seg segflg; 147760e73c7Smckusick int ioflg; 148760e73c7Smckusick struct ucred *cred; 149760e73c7Smckusick int *aresid; 1502d8de7e9Smckusick struct proc *p; 1511d37f34bSbill { 152760e73c7Smckusick struct uio auio; 153760e73c7Smckusick struct iovec aiov; 154760e73c7Smckusick int error; 1551d37f34bSbill 1562a601dc3Smckusick if ((ioflg & IO_NODELOCKED) == 0) 1572a601dc3Smckusick VOP_LOCK(vp); 158760e73c7Smckusick auio.uio_iov = &aiov; 159760e73c7Smckusick auio.uio_iovcnt = 1; 160760e73c7Smckusick aiov.iov_base = base; 161760e73c7Smckusick aiov.iov_len = len; 162760e73c7Smckusick auio.uio_resid = len; 163760e73c7Smckusick auio.uio_offset = offset; 164760e73c7Smckusick auio.uio_segflg = segflg; 165760e73c7Smckusick auio.uio_rw = rw; 1662d8de7e9Smckusick auio.uio_procp = p; 167760e73c7Smckusick if (rw == UIO_READ) 1682a601dc3Smckusick error = VOP_READ(vp, &auio, ioflg, cred); 169760e73c7Smckusick else 1702a601dc3Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred); 171760e73c7Smckusick if (aresid) 172760e73c7Smckusick *aresid = auio.uio_resid; 173760e73c7Smckusick else 174760e73c7Smckusick if (auio.uio_resid && error == 0) 175760e73c7Smckusick error = EIO; 1762a601dc3Smckusick if ((ioflg & IO_NODELOCKED) == 0) 1772a601dc3Smckusick VOP_UNLOCK(vp); 178760e73c7Smckusick return (error); 1792510f0cdSmckusick } 1801d37f34bSbill 181760e73c7Smckusick vn_read(fp, uio, cred) 182760e73c7Smckusick struct file *fp; 183760e73c7Smckusick struct uio *uio; 184760e73c7Smckusick struct ucred *cred; 1851d37f34bSbill { 1862a601dc3Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 1872a601dc3Smckusick int count, error; 1881d37f34bSbill 1892a601dc3Smckusick VOP_LOCK(vp); 1902a601dc3Smckusick uio->uio_offset = fp->f_offset; 1912a601dc3Smckusick count = uio->uio_resid; 192*552d28cbSmckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 193*552d28cbSmckusick cred); 1942a601dc3Smckusick fp->f_offset += count - uio->uio_resid; 1952a601dc3Smckusick VOP_UNLOCK(vp); 1962a601dc3Smckusick return (error); 197760e73c7Smckusick } 198760e73c7Smckusick 199760e73c7Smckusick vn_write(fp, uio, cred) 200760e73c7Smckusick struct file *fp; 201760e73c7Smckusick struct uio *uio; 202760e73c7Smckusick struct ucred *cred; 203760e73c7Smckusick { 204760e73c7Smckusick register struct vnode *vp = (struct vnode *)fp->f_data; 2052a601dc3Smckusick int count, error, ioflag = 0; 206760e73c7Smckusick 207*552d28cbSmckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 208760e73c7Smckusick ioflag |= IO_APPEND; 209*552d28cbSmckusick if (fp->f_flag & FNONBLOCK) 210760e73c7Smckusick ioflag |= IO_NDELAY; 2112a601dc3Smckusick VOP_LOCK(vp); 2122a601dc3Smckusick uio->uio_offset = fp->f_offset; 2132a601dc3Smckusick count = uio->uio_resid; 2142a601dc3Smckusick error = VOP_WRITE(vp, uio, ioflag, cred); 2152a601dc3Smckusick if (ioflag & IO_APPEND) 2162a601dc3Smckusick fp->f_offset = uio->uio_offset; 2172a601dc3Smckusick else 2182a601dc3Smckusick fp->f_offset += count - uio->uio_resid; 2192a601dc3Smckusick VOP_UNLOCK(vp); 2202a601dc3Smckusick return (error); 221760e73c7Smckusick } 222760e73c7Smckusick 223760e73c7Smckusick /* 224760e73c7Smckusick * Get stat info for a vnode. 225760e73c7Smckusick */ 2262d8de7e9Smckusick vn_stat(vp, sb, p) 227760e73c7Smckusick struct vnode *vp; 228760e73c7Smckusick register struct stat *sb; 2292d8de7e9Smckusick struct proc *p; 230760e73c7Smckusick { 231760e73c7Smckusick struct vattr vattr; 232760e73c7Smckusick register struct vattr *vap; 233760e73c7Smckusick int error; 234760e73c7Smckusick u_short mode; 235760e73c7Smckusick 236760e73c7Smckusick vap = &vattr; 2372d8de7e9Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p); 238760e73c7Smckusick if (error) 239760e73c7Smckusick return (error); 240760e73c7Smckusick /* 241760e73c7Smckusick * Copy from vattr table 242760e73c7Smckusick */ 243760e73c7Smckusick sb->st_dev = vap->va_fsid; 244760e73c7Smckusick sb->st_ino = vap->va_fileid; 245760e73c7Smckusick mode = vap->va_mode; 246760e73c7Smckusick switch (vp->v_type) { 247760e73c7Smckusick case VREG: 2486357f7baSmckusick mode |= S_IFREG; 249760e73c7Smckusick break; 250760e73c7Smckusick case VDIR: 2516357f7baSmckusick mode |= S_IFDIR; 252760e73c7Smckusick break; 253760e73c7Smckusick case VBLK: 2546357f7baSmckusick mode |= S_IFBLK; 255760e73c7Smckusick break; 256760e73c7Smckusick case VCHR: 2576357f7baSmckusick mode |= S_IFCHR; 258760e73c7Smckusick break; 259760e73c7Smckusick case VLNK: 2606357f7baSmckusick mode |= S_IFLNK; 261760e73c7Smckusick break; 262760e73c7Smckusick case VSOCK: 2636357f7baSmckusick mode |= S_IFSOCK; 264760e73c7Smckusick break; 265920ab10fSmckusick case VFIFO: 266920ab10fSmckusick mode |= S_IFIFO; 267920ab10fSmckusick break; 268760e73c7Smckusick default: 269760e73c7Smckusick return (EBADF); 270760e73c7Smckusick }; 271760e73c7Smckusick sb->st_mode = mode; 272760e73c7Smckusick sb->st_nlink = vap->va_nlink; 273760e73c7Smckusick sb->st_uid = vap->va_uid; 274760e73c7Smckusick sb->st_gid = vap->va_gid; 275760e73c7Smckusick sb->st_rdev = vap->va_rdev; 276760e73c7Smckusick sb->st_size = vap->va_size; 277760e73c7Smckusick sb->st_atime = vap->va_atime.tv_sec; 278760e73c7Smckusick sb->st_spare1 = 0; 279760e73c7Smckusick sb->st_mtime = vap->va_mtime.tv_sec; 280760e73c7Smckusick sb->st_spare2 = 0; 281760e73c7Smckusick sb->st_ctime = vap->va_ctime.tv_sec; 282760e73c7Smckusick sb->st_spare3 = 0; 283760e73c7Smckusick sb->st_blksize = vap->va_blocksize; 28418b27549Smckusick sb->st_flags = vap->va_flags; 28518b27549Smckusick sb->st_gen = vap->va_gen; 286aa6f7503Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE; 2871d37f34bSbill return (0); 2881d37f34bSbill } 289760e73c7Smckusick 290760e73c7Smckusick /* 291760e73c7Smckusick * Vnode ioctl call 292760e73c7Smckusick */ 2932d8de7e9Smckusick vn_ioctl(fp, com, data, p) 294760e73c7Smckusick struct file *fp; 295760e73c7Smckusick int com; 296760e73c7Smckusick caddr_t data; 2972d8de7e9Smckusick struct proc *p; 298760e73c7Smckusick { 299760e73c7Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data); 300760e73c7Smckusick struct vattr vattr; 301760e73c7Smckusick int error; 302760e73c7Smckusick 303760e73c7Smckusick switch (vp->v_type) { 304760e73c7Smckusick 305760e73c7Smckusick case VREG: 306760e73c7Smckusick case VDIR: 307760e73c7Smckusick if (com == FIONREAD) { 3082d8de7e9Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 309760e73c7Smckusick return (error); 310760e73c7Smckusick *(off_t *)data = vattr.va_size - fp->f_offset; 311760e73c7Smckusick return (0); 312760e73c7Smckusick } 313760e73c7Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */ 314760e73c7Smckusick return (0); /* XXX */ 315760e73c7Smckusick /* fall into ... */ 316760e73c7Smckusick 317760e73c7Smckusick default: 318760e73c7Smckusick return (ENOTTY); 319760e73c7Smckusick 320920ab10fSmckusick case VFIFO: 321760e73c7Smckusick case VCHR: 322760e73c7Smckusick case VBLK: 3232d8de7e9Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 324e79e4887Smarc if (error == 0 && com == TIOCSCTTY) { 3250b0833e3Skarels p->p_session->s_ttyvp = vp; 326e79e4887Smarc VREF(vp); 327e79e4887Smarc } 328e79e4887Smarc return (error); 329760e73c7Smckusick } 330760e73c7Smckusick } 331760e73c7Smckusick 332760e73c7Smckusick /* 333760e73c7Smckusick * Vnode select call 334760e73c7Smckusick */ 3352d8de7e9Smckusick vn_select(fp, which, p) 336760e73c7Smckusick struct file *fp; 337760e73c7Smckusick int which; 3382d8de7e9Smckusick struct proc *p; 339760e73c7Smckusick { 3400b0833e3Skarels 341920ab10fSmckusick return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 3422d8de7e9Smckusick p->p_ucred, p)); 343760e73c7Smckusick } 344760e73c7Smckusick 345760e73c7Smckusick /* 346760e73c7Smckusick * Vnode close call 347760e73c7Smckusick */ 3482d8de7e9Smckusick vn_close(fp, p) 349760e73c7Smckusick register struct file *fp; 3502d8de7e9Smckusick struct proc *p; 351760e73c7Smckusick { 352760e73c7Smckusick struct vnode *vp = ((struct vnode *)fp->f_data); 353760e73c7Smckusick int error; 354760e73c7Smckusick 355760e73c7Smckusick /* 356760e73c7Smckusick * Must delete vnode reference from this file entry 357760e73c7Smckusick * before VOP_CLOSE, so that only other references 358760e73c7Smckusick * will prevent close. 359760e73c7Smckusick */ 360760e73c7Smckusick fp->f_data = (caddr_t) 0; 3612d8de7e9Smckusick error = VOP_CLOSE(vp, fp->f_flag, fp->f_cred, p); 362760e73c7Smckusick vrele(vp); 363760e73c7Smckusick return (error); 364760e73c7Smckusick } 365760e73c7Smckusick 366760e73c7Smckusick /* 367760e73c7Smckusick * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 368760e73c7Smckusick * - look up fsid in mount list (if not found ret error) 369760e73c7Smckusick * - get vp by calling VFS_FHTOVP() macro 370760e73c7Smckusick * - if lockflag lock it with VOP_LOCK() 371760e73c7Smckusick */ 372760e73c7Smckusick vn_fhtovp(fhp, lockflag, vpp) 373760e73c7Smckusick fhandle_t *fhp; 374760e73c7Smckusick int lockflag; 375760e73c7Smckusick struct vnode **vpp; 376760e73c7Smckusick { 377760e73c7Smckusick register struct mount *mp; 378760e73c7Smckusick 379760e73c7Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 380760e73c7Smckusick return (ESTALE); 381229daf47Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 382229daf47Smckusick return (ESTALE); 383229daf47Smckusick if (!lockflag) 384229daf47Smckusick VOP_UNLOCK(*vpp); 385760e73c7Smckusick return (0); 386760e73c7Smckusick } 387