|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)sys_inode.c 6.13 (Berkeley) 8/4/85 ! 7: */ ! 8: ! 9: #include "param.h" ! 10: #include "systm.h" ! 11: #include "dir.h" ! 12: #include "user.h" ! 13: #include "inode.h" ! 14: #include "proc.h" ! 15: #include "fs.h" ! 16: #include "conf.h" ! 17: #include "buf.h" ! 18: #include "mount.h" ! 19: #include "file.h" ! 20: #include "uio.h" ! 21: #include "ioctl.h" ! 22: #include "tty.h" ! 23: #include "cmap.h" ! 24: #include "stat.h" ! 25: #include "kernel.h" ! 26: #include "quota.h" ! 27: ! 28: int ino_rw(), ino_ioctl(), ino_select(), ino_close(); ! 29: struct fileops inodeops = ! 30: { ino_rw, ino_ioctl, ino_select, ino_close }; ! 31: ! 32: ino_rw(fp, rw, uio) ! 33: struct file *fp; ! 34: enum uio_rw rw; ! 35: struct uio *uio; ! 36: { ! 37: register struct inode *ip = (struct inode *)fp->f_data; ! 38: int error; ! 39: ! 40: if ((ip->i_mode&IFMT) == IFREG) { ! 41: ILOCK(ip); ! 42: if (fp->f_flag&FAPPEND && rw == UIO_WRITE) ! 43: uio->uio_offset = fp->f_offset = ip->i_size; ! 44: error = rwip(ip, uio, rw); ! 45: IUNLOCK(ip); ! 46: } else ! 47: error = rwip(ip, uio, rw); ! 48: return (error); ! 49: } ! 50: ! 51: rdwri(rw, ip, base, len, offset, segflg, aresid) ! 52: struct inode *ip; ! 53: caddr_t base; ! 54: int len, offset, segflg; ! 55: int *aresid; ! 56: enum uio_rw rw; ! 57: { ! 58: struct uio auio; ! 59: struct iovec aiov; ! 60: int error; ! 61: ! 62: auio.uio_iov = &aiov; ! 63: auio.uio_iovcnt = 1; ! 64: aiov.iov_base = base; ! 65: aiov.iov_len = len; ! 66: auio.uio_resid = len; ! 67: auio.uio_offset = offset; ! 68: auio.uio_segflg = segflg; ! 69: error = rwip(ip, &auio, rw); ! 70: if (aresid) ! 71: *aresid = auio.uio_resid; ! 72: else ! 73: if (auio.uio_resid) ! 74: error = EIO; ! 75: return (error); ! 76: } ! 77: ! 78: rwip(ip, uio, rw) ! 79: register struct inode *ip; ! 80: register struct uio *uio; ! 81: enum uio_rw rw; ! 82: { ! 83: dev_t dev = (dev_t)ip->i_rdev; ! 84: struct buf *bp; ! 85: struct fs *fs; ! 86: daddr_t lbn, bn; ! 87: register int n, on, type; ! 88: int size; ! 89: long bsize; ! 90: extern int mem_no; ! 91: int error = 0; ! 92: ! 93: if (rw != UIO_READ && rw != UIO_WRITE) ! 94: panic("rwip"); ! 95: if (rw == UIO_READ && uio->uio_resid == 0) ! 96: return (0); ! 97: if (uio->uio_offset < 0 && ! 98: ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) ! 99: return (EINVAL); ! 100: if (rw == UIO_READ) ! 101: ip->i_flag |= IACC; ! 102: type = ip->i_mode&IFMT; ! 103: if (type == IFCHR) { ! 104: if (rw == UIO_READ) ! 105: error = (*cdevsw[major(dev)].d_read)(dev, uio); ! 106: else { ! 107: ip->i_flag |= IUPD|ICHG; ! 108: error = (*cdevsw[major(dev)].d_write)(dev, uio); ! 109: } ! 110: return (error); ! 111: } ! 112: if (uio->uio_resid == 0) ! 113: return (0); ! 114: if (rw == UIO_WRITE && type == IFREG && ! 115: uio->uio_offset + uio->uio_resid > ! 116: u.u_rlimit[RLIMIT_FSIZE].rlim_cur) { ! 117: psignal(u.u_procp, SIGXFSZ); ! 118: return (EFBIG); ! 119: } ! 120: if (type != IFBLK) { ! 121: dev = ip->i_dev; ! 122: fs = ip->i_fs; ! 123: bsize = fs->fs_bsize; ! 124: } else ! 125: bsize = BLKDEV_IOSIZE; ! 126: do { ! 127: lbn = uio->uio_offset / bsize; ! 128: on = uio->uio_offset % bsize; ! 129: n = MIN((unsigned)(bsize - on), uio->uio_resid); ! 130: if (type != IFBLK) { ! 131: if (rw == UIO_READ) { ! 132: int diff = ip->i_size - uio->uio_offset; ! 133: if (diff <= 0) ! 134: return (0); ! 135: if (diff < n) ! 136: n = diff; ! 137: } ! 138: bn = fsbtodb(fs, ! 139: bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); ! 140: if (u.u_error || rw == UIO_WRITE && (long)bn<0) ! 141: return (u.u_error); ! 142: if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && ! 143: (type == IFDIR || type == IFREG || type == IFLNK)) ! 144: ip->i_size = uio->uio_offset + n; ! 145: size = blksize(fs, ip, lbn); ! 146: } else { ! 147: bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); ! 148: rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); ! 149: rasize = size = bsize; ! 150: } ! 151: if (rw == UIO_READ) { ! 152: if ((long)bn<0) { ! 153: bp = geteblk(size); ! 154: clrbuf(bp); ! 155: } else if (ip->i_lastr + 1 == lbn) ! 156: bp = breada(dev, bn, size, rablock, rasize); ! 157: else ! 158: bp = bread(dev, bn, size); ! 159: ip->i_lastr = lbn; ! 160: } else { ! 161: int i, count, s; ! 162: extern struct cmap *mfind(); ! 163: ! 164: count = howmany(size, DEV_BSIZE); ! 165: s = splimp(); ! 166: for (i = 0; i < count; i += CLBYTES / DEV_BSIZE) ! 167: if (mfind(dev, bn + i)) ! 168: munhash(dev, bn + i); ! 169: splx(s); ! 170: if (n == bsize) ! 171: bp = getblk(dev, bn, size); ! 172: else ! 173: bp = bread(dev, bn, size); ! 174: } ! 175: n = MIN(n, size - bp->b_resid); ! 176: if (bp->b_flags & B_ERROR) { ! 177: error = EIO; ! 178: brelse(bp); ! 179: goto bad; ! 180: } ! 181: u.u_error = ! 182: uiomove(bp->b_un.b_addr+on, n, rw, uio); ! 183: if (rw == UIO_READ) { ! 184: if (n + on == bsize || uio->uio_offset == ip->i_size) ! 185: bp->b_flags |= B_AGE; ! 186: brelse(bp); ! 187: } else { ! 188: if ((ip->i_mode&IFMT) == IFDIR) ! 189: bwrite(bp); ! 190: else if (n + on == bsize) { ! 191: bp->b_flags |= B_AGE; ! 192: bawrite(bp); ! 193: } else ! 194: bdwrite(bp); ! 195: ip->i_flag |= IUPD|ICHG; ! 196: if (u.u_ruid != 0) ! 197: ip->i_mode &= ~(ISUID|ISGID); ! 198: } ! 199: } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); ! 200: if (error == 0) /* XXX */ ! 201: error = u.u_error; /* XXX */ ! 202: bad: ! 203: return (error); ! 204: } ! 205: ! 206: ino_ioctl(fp, com, data) ! 207: struct file *fp; ! 208: register int com; ! 209: caddr_t data; ! 210: { ! 211: register struct inode *ip = ((struct inode *)fp->f_data); ! 212: register int fmt = ip->i_mode & IFMT; ! 213: dev_t dev; ! 214: ! 215: switch (fmt) { ! 216: ! 217: case IFREG: ! 218: case IFDIR: ! 219: if (com == FIONREAD) { ! 220: *(off_t *)data = ip->i_size - fp->f_offset; ! 221: return (0); ! 222: } ! 223: if (com == FIONBIO || com == FIOASYNC) /* XXX */ ! 224: return (0); /* XXX */ ! 225: /* fall into ... */ ! 226: ! 227: default: ! 228: return (ENOTTY); ! 229: ! 230: case IFCHR: ! 231: dev = ip->i_rdev; ! 232: u.u_r.r_val1 = 0; ! 233: if (setjmp(&u.u_qsave)) { ! 234: if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) ! 235: return(EINTR); ! 236: u.u_eosys = RESTARTSYS; ! 237: return (0); ! 238: } ! 239: return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, ! 240: fp->f_flag)); ! 241: } ! 242: } ! 243: ! 244: ino_select(fp, which) ! 245: struct file *fp; ! 246: int which; ! 247: { ! 248: register struct inode *ip = (struct inode *)fp->f_data; ! 249: register dev_t dev; ! 250: ! 251: switch (ip->i_mode & IFMT) { ! 252: ! 253: default: ! 254: return (1); /* XXX */ ! 255: ! 256: case IFCHR: ! 257: dev = ip->i_rdev; ! 258: return (*cdevsw[major(dev)].d_select)(dev, which); ! 259: } ! 260: } ! 261: ! 262: #ifdef notdef ! 263: ino_clone() ! 264: { ! 265: ! 266: return (EOPNOTSUPP); ! 267: } ! 268: #endif ! 269: ! 270: ino_stat(ip, sb) ! 271: register struct inode *ip; ! 272: register struct stat *sb; ! 273: { ! 274: ! 275: ITIMES(ip, &time, &time); ! 276: /* ! 277: * Copy from inode table ! 278: */ ! 279: sb->st_dev = ip->i_dev; ! 280: sb->st_ino = ip->i_number; ! 281: sb->st_mode = ip->i_mode; ! 282: sb->st_nlink = ip->i_nlink; ! 283: sb->st_uid = ip->i_uid; ! 284: sb->st_gid = ip->i_gid; ! 285: sb->st_rdev = (dev_t)ip->i_rdev; ! 286: sb->st_size = ip->i_size; ! 287: sb->st_atime = ip->i_atime; ! 288: sb->st_spare1 = 0; ! 289: sb->st_mtime = ip->i_mtime; ! 290: sb->st_spare2 = 0; ! 291: sb->st_ctime = ip->i_ctime; ! 292: sb->st_spare3 = 0; ! 293: /* this doesn't belong here */ ! 294: if ((ip->i_mode&IFMT) == IFBLK) ! 295: sb->st_blksize = BLKDEV_IOSIZE; ! 296: else if ((ip->i_mode&IFMT) == IFCHR) ! 297: sb->st_blksize = MAXBSIZE; ! 298: else ! 299: sb->st_blksize = ip->i_fs->fs_bsize; ! 300: sb->st_blocks = ip->i_blocks; ! 301: sb->st_spare4[0] = sb->st_spare4[1] = 0; ! 302: return (0); ! 303: } ! 304: ! 305: ino_close(fp) ! 306: register struct file *fp; ! 307: { ! 308: register struct inode *ip = (struct inode *)fp->f_data; ! 309: register struct mount *mp; ! 310: int flag, mode; ! 311: dev_t dev; ! 312: register int (*cfunc)(); ! 313: ! 314: if (fp->f_flag & (FSHLOCK|FEXLOCK)) ! 315: ino_unlock(fp, FSHLOCK|FEXLOCK); ! 316: flag = fp->f_flag; ! 317: dev = (dev_t)ip->i_rdev; ! 318: mode = ip->i_mode & IFMT; ! 319: ilock(ip); ! 320: iput(ip); ! 321: fp->f_data = (caddr_t) 0; /* XXX */ ! 322: switch (mode) { ! 323: ! 324: case IFCHR: ! 325: cfunc = cdevsw[major(dev)].d_close; ! 326: break; ! 327: ! 328: case IFBLK: ! 329: /* ! 330: * We don't want to really close the device if it is mounted ! 331: */ ! 332: /* MOUNT TABLE SHOULD HOLD INODE */ ! 333: for (mp = mount; mp < &mount[NMOUNT]; mp++) ! 334: if (mp->m_bufp != NULL && mp->m_dev == dev) ! 335: return; ! 336: cfunc = bdevsw[major(dev)].d_close; ! 337: break; ! 338: ! 339: default: ! 340: return; ! 341: } ! 342: ! 343: /* ! 344: * Check that another inode for the same device isn't active. ! 345: * This is because the same device can be referenced by ! 346: * two different inodes. ! 347: */ ! 348: for (fp = file; fp < fileNFILE; fp++) { ! 349: if (fp->f_type != DTYPE_INODE) /* XXX */ ! 350: continue; ! 351: if (fp->f_count && (ip = (struct inode *)fp->f_data) && ! 352: ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) ! 353: return; ! 354: } ! 355: if (mode == IFBLK) { ! 356: /* ! 357: * On last close of a block device (that isn't mounted) ! 358: * we must invalidate any in core blocks, so that ! 359: * we can, for instance, change floppy disks. ! 360: */ ! 361: bflush(dev); ! 362: binval(dev); ! 363: } ! 364: if (setjmp(&u.u_qsave)) { ! 365: /* ! 366: * If device close routine is interrupted, ! 367: * must return so closef can clean up. ! 368: */ ! 369: if (u.u_error == 0) ! 370: u.u_error = EINTR; /* ??? */ ! 371: return; ! 372: } ! 373: (*cfunc)(dev, flag); ! 374: } ! 375: ! 376: /* ! 377: * Place an advisory lock on an inode. ! 378: */ ! 379: ino_lock(fp, cmd) ! 380: register struct file *fp; ! 381: int cmd; ! 382: { ! 383: register int priority = PLOCK; ! 384: register struct inode *ip = (struct inode *)fp->f_data; ! 385: ! 386: if ((cmd & LOCK_EX) == 0) ! 387: priority += 4; ! 388: if (setjmp(&u.u_qsave)) { ! 389: if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) ! 390: return(EINTR); ! 391: u.u_eosys = RESTARTSYS; ! 392: return (0); ! 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 (ip->i_flag & IEXLOCK) { ! 401: /* ! 402: * If we're holding an exclusive ! 403: * lock, then release it. ! 404: */ ! 405: if (fp->f_flag & FEXLOCK) { ! 406: ino_unlock(fp, FEXLOCK); ! 407: continue; ! 408: } ! 409: if (cmd & LOCK_NB) ! 410: return (EWOULDBLOCK); ! 411: ip->i_flag |= ILWAIT; ! 412: sleep((caddr_t)&ip->i_exlockc, priority); ! 413: } ! 414: if ((cmd & LOCK_EX) && (ip->i_flag & ISHLOCK)) { ! 415: /* ! 416: * Must wait for any shared locks to finish ! 417: * before we try to apply a exclusive lock. ! 418: * ! 419: * If we're holding a shared ! 420: * lock, then release it. ! 421: */ ! 422: if (fp->f_flag & FSHLOCK) { ! 423: ino_unlock(fp, FSHLOCK); ! 424: goto again; ! 425: } ! 426: if (cmd & LOCK_NB) ! 427: return (EWOULDBLOCK); ! 428: ip->i_flag |= ILWAIT; ! 429: sleep((caddr_t)&ip->i_shlockc, PLOCK); ! 430: goto again; ! 431: } ! 432: if (fp->f_flag & FEXLOCK) ! 433: panic("ino_lock"); ! 434: if (cmd & LOCK_EX) { ! 435: cmd &= ~LOCK_SH; ! 436: ip->i_exlockc++; ! 437: ip->i_flag |= IEXLOCK; ! 438: fp->f_flag |= FEXLOCK; ! 439: } ! 440: if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { ! 441: ip->i_shlockc++; ! 442: ip->i_flag |= ISHLOCK; ! 443: fp->f_flag |= FSHLOCK; ! 444: } ! 445: return (0); ! 446: } ! 447: ! 448: /* ! 449: * Unlock a file. ! 450: */ ! 451: ino_unlock(fp, kind) ! 452: register struct file *fp; ! 453: int kind; ! 454: { ! 455: register struct inode *ip = (struct inode *)fp->f_data; ! 456: int flags; ! 457: ! 458: kind &= fp->f_flag; ! 459: if (ip == NULL || kind == 0) ! 460: return; ! 461: flags = ip->i_flag; ! 462: if (kind & FSHLOCK) { ! 463: if ((flags & ISHLOCK) == 0) ! 464: panic("ino_unlock: SHLOCK"); ! 465: if (--ip->i_shlockc == 0) { ! 466: ip->i_flag &= ~ISHLOCK; ! 467: if (flags & ILWAIT) ! 468: wakeup((caddr_t)&ip->i_shlockc); ! 469: } ! 470: fp->f_flag &= ~FSHLOCK; ! 471: } ! 472: if (kind & FEXLOCK) { ! 473: if ((flags & IEXLOCK) == 0) ! 474: panic("ino_unlock: EXLOCK"); ! 475: if (--ip->i_exlockc == 0) { ! 476: ip->i_flag &= ~(IEXLOCK|ILWAIT); ! 477: if (flags & ILWAIT) ! 478: wakeup((caddr_t)&ip->i_exlockc); ! 479: } ! 480: fp->f_flag &= ~FEXLOCK; ! 481: } ! 482: } ! 483: ! 484: /* ! 485: * Openi called to allow handler ! 486: * of special files to initialize and ! 487: * validate before actual IO. ! 488: */ ! 489: openi(ip, mode) ! 490: register struct inode *ip; ! 491: { ! 492: dev_t dev = (dev_t)ip->i_rdev; ! 493: register int maj = major(dev); ! 494: int minnum = minor(dev); ! 495: register int error; ! 496: ! 497: switch (ip->i_mode&IFMT) { ! 498: ! 499: case IFCHR: ! 500: if ((u_int)maj >= nchrdev) ! 501: return (ENXIO); ! 502: error = (*cdevsw[maj].d_open)(dev, mode, &minnum); ! 503: ! 504: /* ! 505: * Test for new minor device inode allocation ! 506: */ ! 507: if ((error == 0) && (minnum != minor(dev))) { ! 508: register struct inode *nip; ! 509: ! 510: /* ! 511: * Allocate new inode with new minor device ! 512: * Release old inode. Set vpp to point to new one. ! 513: * This inode will go away when the last reference ! 514: * to it goes away. ! 515: * Warning: if you stat this, and try to match it ! 516: * with a name in the filesystem you will fail, ! 517: * unless you had previously put names in that match. ! 518: */ ! 519: nip = ialloc(ip, dirpref(ip->i_fs), (int)ip->i_mode); ! 520: if (nip == (struct inode *)0) { ! 521: /* ! 522: * Give driver a chance to clean up; ! 523: * this is iffy since other instances ! 524: * of this device could be active. ! 525: */ ! 526: cdevsw[maj].d_close(makedev(maj, minnum), ! 527: mode&FMASK); ! 528: return (ENXIO); ! 529: } ! 530: nip->i_flag |= IACC|IUPD|ICHG; ! 531: nip->i_mode = ip->i_mode; ! 532: nip->i_nlink = 0; ! 533: nip->i_uid = ip->i_uid; ! 534: nip->i_gid = ip->i_gid; ! 535: nip->i_rdev = makedev(maj, minnum); ! 536: #ifdef QUOTA ! 537: nip->i_dquot = inoquota(nip); ! 538: #endif ! 539: irele(ip); ! 540: ip = nip; ! 541: iunlock(ip); ! 542: /* ! 543: * This next line depends on the way copen() ! 544: * works; it's a kludge. ! 545: */ ! 546: u.u_ofile[u.u_r.r_val1]->f_data = (caddr_t)ip; ! 547: } ! 548: return(error); ! 549: ! 550: case IFBLK: ! 551: if ((u_int)maj >= nblkdev) ! 552: return (ENXIO); ! 553: return ((*bdevsw[maj].d_open)(dev, mode)); ! 554: } ! 555: return (0); ! 556: } ! 557: ! 558: /* ! 559: * Revoke access the current tty by all processes. ! 560: * Used only by the super-user in init ! 561: * to give ``clean'' terminals at login. ! 562: */ ! 563: vhangup() ! 564: { ! 565: ! 566: if (!suser()) ! 567: return; ! 568: if (u.u_ttyp == NULL) ! 569: return; ! 570: forceclose(u.u_ttyd); ! 571: if ((u.u_ttyp->t_state) & TS_ISOPEN) ! 572: gsignal(u.u_ttyp->t_pgrp, SIGHUP); ! 573: } ! 574: ! 575: forceclose(dev) ! 576: dev_t dev; ! 577: { ! 578: register struct file *fp; ! 579: register struct inode *ip; ! 580: ! 581: for (fp = file; fp < fileNFILE; fp++) { ! 582: if (fp->f_count == 0) ! 583: continue; ! 584: if (fp->f_type != DTYPE_INODE) ! 585: continue; ! 586: ip = (struct inode *)fp->f_data; ! 587: if (ip == 0) ! 588: continue; ! 589: if ((ip->i_mode & IFMT) != IFCHR) ! 590: continue; ! 591: if (ip->i_rdev != dev) ! 592: continue; ! 593: fp->f_flag &= ~(FREAD|FWRITE); ! 594: } ! 595: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.