|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)vfs_vnops.c 7.23 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "kernel.h" ! 27: #include "file.h" ! 28: #include "stat.h" ! 29: #include "buf.h" ! 30: #include "proc.h" ! 31: #include "uio.h" ! 32: #include "socket.h" ! 33: #include "socketvar.h" ! 34: #include "mount.h" ! 35: #include "vnode.h" ! 36: #include "ioctl.h" ! 37: #include "tty.h" ! 38: ! 39: int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close(); ! 40: struct fileops vnops = ! 41: { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; ! 42: ! 43: /* ! 44: * Common code for vnode open operations. ! 45: * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. ! 46: */ ! 47: vn_open(ndp, fmode, cmode) ! 48: register struct nameidata *ndp; ! 49: int fmode, cmode; ! 50: { ! 51: register struct vnode *vp; ! 52: struct vattr vat; ! 53: struct vattr *vap = &vat; ! 54: int error; ! 55: ! 56: if (fmode & FCREAT) { ! 57: ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; ! 58: if ((fmode & FEXCL) == 0) ! 59: ndp->ni_nameiop |= FOLLOW; ! 60: if (error = namei(ndp)) ! 61: return (error); ! 62: if (ndp->ni_vp == NULL) { ! 63: VATTR_NULL(vap); ! 64: vap->va_type = VREG; ! 65: vap->va_mode = cmode; ! 66: if (error = VOP_CREATE(ndp, vap)) ! 67: return (error); ! 68: fmode &= ~FTRUNC; ! 69: vp = ndp->ni_vp; ! 70: } else { ! 71: if (ndp->ni_dvp == ndp->ni_vp) ! 72: vrele(ndp->ni_dvp); ! 73: else ! 74: vput(ndp->ni_dvp); ! 75: ndp->ni_dvp = NULL; ! 76: vp = ndp->ni_vp; ! 77: if (fmode & FEXCL) { ! 78: error = EEXIST; ! 79: goto bad; ! 80: } ! 81: fmode &= ~FCREAT; ! 82: } ! 83: } else { ! 84: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 85: if (error = namei(ndp)) ! 86: return (error); ! 87: vp = ndp->ni_vp; ! 88: } ! 89: if (vp->v_type == VSOCK) { ! 90: error = EOPNOTSUPP; ! 91: goto bad; ! 92: } ! 93: if ((fmode & FCREAT) == 0) { ! 94: if (fmode & FREAD) { ! 95: if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred)) ! 96: goto bad; ! 97: } ! 98: if (fmode & (FWRITE|FTRUNC)) { ! 99: if (vp->v_type == VDIR) { ! 100: error = EISDIR; ! 101: goto bad; ! 102: } ! 103: if ((error = vn_writechk(vp)) || ! 104: (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) ! 105: goto bad; ! 106: } ! 107: } ! 108: if (fmode & FTRUNC) { ! 109: VATTR_NULL(vap); ! 110: vap->va_size = 0; ! 111: if (error = VOP_SETATTR(vp, vap, ndp->ni_cred)) ! 112: goto bad; ! 113: } ! 114: VOP_UNLOCK(vp); ! 115: error = VOP_OPEN(vp, fmode, ndp->ni_cred); ! 116: if (error) ! 117: vrele(vp); ! 118: return (error); ! 119: ! 120: bad: ! 121: vput(vp); ! 122: return (error); ! 123: } ! 124: ! 125: /* ! 126: * Check for write permissions on the specified vnode. ! 127: * The read-only status of the file system is checked. ! 128: * Also, prototype text segments cannot be written. ! 129: */ ! 130: vn_writechk(vp) ! 131: register struct vnode *vp; ! 132: { ! 133: ! 134: /* ! 135: * Disallow write attempts on read-only file systems; ! 136: * unless the file is a socket or a block or character ! 137: * device resident on the file system. ! 138: */ ! 139: if ((vp->v_mount->mnt_flag & MNT_RDONLY) && vp->v_type != VCHR && ! 140: vp->v_type != VBLK && vp->v_type != VSOCK) ! 141: return (EROFS); ! 142: /* ! 143: * If there's shared text associated with ! 144: * the vnode, try to free it up once. If ! 145: * we fail, we can't allow writing. ! 146: */ ! 147: if (vp->v_flag & VTEXT) ! 148: xrele(vp); ! 149: if (vp->v_flag & VTEXT) ! 150: return (ETXTBSY); ! 151: return (0); ! 152: } ! 153: ! 154: /* ! 155: * Vnode version of rdwri() for calls on file systems. ! 156: */ ! 157: vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid) ! 158: enum uio_rw rw; ! 159: struct vnode *vp; ! 160: caddr_t base; ! 161: int len; ! 162: off_t offset; ! 163: enum uio_seg segflg; ! 164: int ioflg; ! 165: struct ucred *cred; ! 166: int *aresid; ! 167: { ! 168: struct uio auio; ! 169: struct iovec aiov; ! 170: int error; ! 171: ! 172: if ((ioflg & IO_NODELOCKED) == 0) ! 173: VOP_LOCK(vp); ! 174: auio.uio_iov = &aiov; ! 175: auio.uio_iovcnt = 1; ! 176: aiov.iov_base = base; ! 177: aiov.iov_len = len; ! 178: auio.uio_resid = len; ! 179: auio.uio_offset = offset; ! 180: auio.uio_segflg = segflg; ! 181: auio.uio_rw = rw; ! 182: if (rw == UIO_READ) ! 183: error = VOP_READ(vp, &auio, ioflg, cred); ! 184: else ! 185: error = VOP_WRITE(vp, &auio, ioflg, cred); ! 186: if (aresid) ! 187: *aresid = auio.uio_resid; ! 188: else ! 189: if (auio.uio_resid && error == 0) ! 190: error = EIO; ! 191: if ((ioflg & IO_NODELOCKED) == 0) ! 192: VOP_UNLOCK(vp); ! 193: return (error); ! 194: } ! 195: ! 196: vn_read(fp, uio, cred) ! 197: struct file *fp; ! 198: struct uio *uio; ! 199: struct ucred *cred; ! 200: { ! 201: register struct vnode *vp = (struct vnode *)fp->f_data; ! 202: int count, error; ! 203: ! 204: VOP_LOCK(vp); ! 205: uio->uio_offset = fp->f_offset; ! 206: count = uio->uio_resid; ! 207: error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred); ! 208: fp->f_offset += count - uio->uio_resid; ! 209: VOP_UNLOCK(vp); ! 210: return (error); ! 211: } ! 212: ! 213: vn_write(fp, uio, cred) ! 214: struct file *fp; ! 215: struct uio *uio; ! 216: struct ucred *cred; ! 217: { ! 218: register struct vnode *vp = (struct vnode *)fp->f_data; ! 219: int count, error, ioflag = 0; ! 220: ! 221: if (vp->v_type == VREG && (fp->f_flag & FAPPEND)) ! 222: ioflag |= IO_APPEND; ! 223: if (fp->f_flag & FNDELAY) ! 224: ioflag |= IO_NDELAY; ! 225: VOP_LOCK(vp); ! 226: uio->uio_offset = fp->f_offset; ! 227: count = uio->uio_resid; ! 228: error = VOP_WRITE(vp, uio, ioflag, cred); ! 229: if (ioflag & IO_APPEND) ! 230: fp->f_offset = uio->uio_offset; ! 231: else ! 232: fp->f_offset += count - uio->uio_resid; ! 233: VOP_UNLOCK(vp); ! 234: return (error); ! 235: } ! 236: ! 237: /* ! 238: * Get stat info for a vnode. ! 239: */ ! 240: vn_stat(vp, sb) ! 241: struct vnode *vp; ! 242: register struct stat *sb; ! 243: { ! 244: struct vattr vattr; ! 245: register struct vattr *vap; ! 246: int error; ! 247: u_short mode; ! 248: ! 249: vap = &vattr; ! 250: error = VOP_GETATTR(vp, vap, u.u_cred); ! 251: if (error) ! 252: return (error); ! 253: /* ! 254: * Copy from vattr table ! 255: */ ! 256: sb->st_dev = vap->va_fsid; ! 257: sb->st_ino = vap->va_fileid; ! 258: mode = vap->va_mode; ! 259: switch (vp->v_type) { ! 260: case VREG: ! 261: mode |= S_IFREG; ! 262: break; ! 263: case VDIR: ! 264: mode |= S_IFDIR; ! 265: break; ! 266: case VBLK: ! 267: mode |= S_IFBLK; ! 268: break; ! 269: case VCHR: ! 270: mode |= S_IFCHR; ! 271: break; ! 272: case VLNK: ! 273: mode |= S_IFLNK; ! 274: break; ! 275: case VSOCK: ! 276: mode |= S_IFSOCK; ! 277: break; ! 278: case VFIFO: ! 279: mode |= S_IFIFO; ! 280: break; ! 281: default: ! 282: return (EBADF); ! 283: }; ! 284: sb->st_mode = mode; ! 285: sb->st_nlink = vap->va_nlink; ! 286: sb->st_uid = vap->va_uid; ! 287: sb->st_gid = vap->va_gid; ! 288: sb->st_rdev = vap->va_rdev; ! 289: sb->st_size = vap->va_size; ! 290: sb->st_atime = vap->va_atime.tv_sec; ! 291: sb->st_spare1 = 0; ! 292: sb->st_mtime = vap->va_mtime.tv_sec; ! 293: sb->st_spare2 = 0; ! 294: sb->st_ctime = vap->va_ctime.tv_sec; ! 295: sb->st_spare3 = 0; ! 296: sb->st_blksize = vap->va_blocksize; ! 297: sb->st_flags = vap->va_flags; ! 298: sb->st_gen = vap->va_gen; ! 299: sb->st_blocks = vap->va_bytes / S_BLKSIZE; ! 300: return (0); ! 301: } ! 302: ! 303: /* ! 304: * Vnode ioctl call ! 305: */ ! 306: vn_ioctl(fp, com, data) ! 307: struct file *fp; ! 308: int com; ! 309: caddr_t data; ! 310: { ! 311: register struct vnode *vp = ((struct vnode *)fp->f_data); ! 312: struct vattr vattr; ! 313: int error; ! 314: ! 315: switch (vp->v_type) { ! 316: ! 317: case VREG: ! 318: case VDIR: ! 319: if (com == FIONREAD) { ! 320: if (error = VOP_GETATTR(vp, &vattr, u.u_cred)) ! 321: return (error); ! 322: *(off_t *)data = vattr.va_size - fp->f_offset; ! 323: return (0); ! 324: } ! 325: if (com == FIONBIO || com == FIOASYNC) /* XXX */ ! 326: return (0); /* XXX */ ! 327: /* fall into ... */ ! 328: ! 329: default: ! 330: return (ENOTTY); ! 331: ! 332: case VFIFO: ! 333: case VCHR: ! 334: case VBLK: ! 335: error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred); ! 336: if (error == 0 && com == TIOCSCTTY) { ! 337: u.u_procp->p_session->s_ttyvp = vp; ! 338: VREF(vp); ! 339: } ! 340: return (error); ! 341: } ! 342: } ! 343: ! 344: /* ! 345: * Vnode select call ! 346: */ ! 347: vn_select(fp, which) ! 348: struct file *fp; ! 349: int which; ! 350: { ! 351: return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, ! 352: u.u_cred)); ! 353: } ! 354: ! 355: /* ! 356: * Vnode close call ! 357: */ ! 358: vn_close(fp) ! 359: register struct file *fp; ! 360: { ! 361: struct vnode *vp = ((struct vnode *)fp->f_data); ! 362: int error; ! 363: ! 364: if (fp->f_flag & (FSHLOCK|FEXLOCK)) ! 365: vn_unlock(fp, FSHLOCK|FEXLOCK); ! 366: /* ! 367: * Must delete vnode reference from this file entry ! 368: * before VOP_CLOSE, so that only other references ! 369: * will prevent close. ! 370: */ ! 371: fp->f_data = (caddr_t) 0; ! 372: error = VOP_CLOSE(vp, fp->f_flag, u.u_cred); ! 373: vrele(vp); ! 374: return (error); ! 375: } ! 376: ! 377: /* ! 378: * Place an advisory lock on a vnode. ! 379: * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries ! 380: */ ! 381: vn_lock(fp, cmd) ! 382: register struct file *fp; ! 383: int cmd; ! 384: { ! 385: register int priority = PLOCK; ! 386: register struct vnode *vp = (struct vnode *)fp->f_data; ! 387: int error = 0; ! 388: static char lockstr[] = "flock"; ! 389: ! 390: if ((cmd & LOCK_EX) == 0) ! 391: priority += 4; ! 392: priority |= PCATCH; ! 393: ! 394: /* ! 395: * If there's a exclusive lock currently applied ! 396: * to the file, then we've gotta wait for the ! 397: * lock with everyone else. ! 398: */ ! 399: again: ! 400: while (vp->v_flag & VEXLOCK) { ! 401: /* ! 402: * If we're holding an exclusive ! 403: * lock, then release it. ! 404: */ ! 405: if (fp->f_flag & FEXLOCK) { ! 406: vn_unlock(fp, FEXLOCK); ! 407: continue; ! 408: } ! 409: if (cmd & LOCK_NB) ! 410: return (EWOULDBLOCK); ! 411: vp->v_flag |= VLWAIT; ! 412: if (error = tsleep((caddr_t)&vp->v_exlockc, priority, ! 413: lockstr, 0)) ! 414: return (error); ! 415: } ! 416: if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) { ! 417: /* ! 418: * Must wait for any shared locks to finish ! 419: * before we try to apply a exclusive lock. ! 420: * ! 421: * If we're holding a shared ! 422: * lock, then release it. ! 423: */ ! 424: if (fp->f_flag & FSHLOCK) { ! 425: vn_unlock(fp, FSHLOCK); ! 426: goto again; ! 427: } ! 428: if (cmd & LOCK_NB) ! 429: return (EWOULDBLOCK); ! 430: vp->v_flag |= VLWAIT; ! 431: if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH, ! 432: lockstr, 0) == 0) ! 433: return (error); ! 434: } ! 435: if (fp->f_flag & FEXLOCK) ! 436: panic("vn_lock"); ! 437: if (cmd & LOCK_EX) { ! 438: cmd &= ~LOCK_SH; ! 439: vp->v_exlockc++; ! 440: vp->v_flag |= VEXLOCK; ! 441: fp->f_flag |= FEXLOCK; ! 442: } ! 443: if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { ! 444: vp->v_shlockc++; ! 445: vp->v_flag |= VSHLOCK; ! 446: fp->f_flag |= FSHLOCK; ! 447: } ! 448: return (0); ! 449: } ! 450: ! 451: /* ! 452: * Unlock a file. ! 453: */ ! 454: vn_unlock(fp, kind) ! 455: register struct file *fp; ! 456: int kind; ! 457: { ! 458: register struct vnode *vp = (struct vnode *)fp->f_data; ! 459: int flags; ! 460: ! 461: kind &= fp->f_flag; ! 462: if (vp == NULL || kind == 0) ! 463: return; ! 464: flags = vp->v_flag; ! 465: if (kind & FSHLOCK) { ! 466: if ((flags & VSHLOCK) == 0) ! 467: panic("vn_unlock: SHLOCK"); ! 468: if (--vp->v_shlockc == 0) { ! 469: vp->v_flag &= ~VSHLOCK; ! 470: if (flags & VLWAIT) ! 471: wakeup((caddr_t)&vp->v_shlockc); ! 472: } ! 473: fp->f_flag &= ~FSHLOCK; ! 474: } ! 475: if (kind & FEXLOCK) { ! 476: if ((flags & VEXLOCK) == 0) ! 477: panic("vn_unlock: EXLOCK"); ! 478: if (--vp->v_exlockc == 0) { ! 479: vp->v_flag &= ~(VEXLOCK|VLWAIT); ! 480: if (flags & VLWAIT) ! 481: wakeup((caddr_t)&vp->v_exlockc); ! 482: } ! 483: fp->f_flag &= ~FEXLOCK; ! 484: } ! 485: } ! 486: ! 487: /* ! 488: * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) ! 489: * - look up fsid in mount list (if not found ret error) ! 490: * - get vp by calling VFS_FHTOVP() macro ! 491: * - if lockflag lock it with VOP_LOCK() ! 492: */ ! 493: vn_fhtovp(fhp, lockflag, vpp) ! 494: fhandle_t *fhp; ! 495: int lockflag; ! 496: struct vnode **vpp; ! 497: { ! 498: register struct mount *mp; ! 499: ! 500: if ((mp = getvfs(&fhp->fh_fsid)) == NULL) ! 501: return (ESTALE); ! 502: if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) ! 503: return (ESTALE); ! 504: if (!lockflag) ! 505: VOP_UNLOCK(*vpp); ! 506: return (0); ! 507: } ! 508: ! 509: /* ! 510: * Noop ! 511: */ ! 512: vfs_noop() ! 513: { ! 514: ! 515: return (ENXIO); ! 516: } ! 517: ! 518: /* ! 519: * Null op ! 520: */ ! 521: vfs_nullop() ! 522: { ! 523: ! 524: return (0); ! 525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.