|
|
1.1 ! root 1: /* $Header: /src386/STREAMS/coh.386/RCS/fs3.c,v 2.3 93/08/09 13:35:38 bin Exp Locker: bin $ */ ! 2: /* (lgl- ! 3: * The information contained herein is a trade secret of Mark Williams ! 4: * Company, and is confidential information. It is provided under a ! 5: * license agreement, and may be copied or disclosed only under the ! 6: * terms of that agreement. Any reproduction or disclosure of this ! 7: * material without the express written authorization of Mark Williams ! 8: * Company or persuant to the license agreement is unlawful. ! 9: * ! 10: * COHERENT Version 2.3.37 ! 11: * Copyright (c) 1982, 1983, 1984. ! 12: * An unpublished work by Mark Williams Company, Chicago. ! 13: * All rights reserved. ! 14: -lgl) */ ! 15: /* ! 16: * Coherent. ! 17: * Filesystem (I/O). ! 18: * ! 19: * $Log: fs3.c,v $ ! 20: * Revision 2.3 93/08/09 13:35:38 bin ! 21: * Kernel 82 changes ! 22: * ! 23: * Revision 2.2 93/07/26 14:28:33 nigel ! 24: * Nigel's R80 ! 25: * ! 26: * Revision 1.5 93/04/14 10:06:33 root ! 27: * r75 ! 28: * ! 29: * Revision 1.2 92/01/06 11:59:34 hal ! 30: * Compile with cc.mwc. ! 31: * ! 32: * Revision 1.1 88/03/24 16:13:54 src ! 33: * Initial revision ! 34: * ! 35: * 87/11/25 Allan Cornish /usr/src/sys/coh/fs3.c ! 36: * vaddr_t bp->b_vaddr --> faddr_t bp->b_faddr. ! 37: * ! 38: * 86/02/01 Allan Cornish ! 39: * Added code to fwrite() to avoid needless writing of pipe blocks. ! 40: * Throughput on 6 Mhz AT rose from 30 Kbytes/sec to 79 Kbytes/sec. ! 41: */ ! 42: ! 43: #include <common/_tricks.h> ! 44: #include <sys/debug.h> ! 45: #include <sys/coherent.h> ! 46: #include <sys/buf.h> ! 47: #include <canon.h> ! 48: #include <sys/con.h> ! 49: #include <sys/errno.h> ! 50: #include <sys/filsys.h> ! 51: #include <sys/mount.h> ! 52: #include <sys/io.h> ! 53: #include <sys/ino.h> ! 54: #include <sys/inode.h> ! 55: #include <sys/stat.h> ! 56: #include <sys/file.h> ! 57: ! 58: /* ! 59: * Given an inode, open it. ! 60: */ ! 61: iopen(ip, mode) ! 62: register INODE *ip; ! 63: { ! 64: register int type; ! 65: ! 66: type = ip->i_mode & IFMT; ! 67: switch (type) { ! 68: case IFCHR: ! 69: case IFBLK: ! 70: iunlock(ip); ! 71: dopen(ip->i_a.i_rdev, mode, type==IFCHR ? DFCHR : DFBLK); ! 72: ilock(ip); ! 73: break; ! 74: case IFDIR: ! 75: if (mode & IPW) { ! 76: ! 77: /* Return (EISDIR) if not superuser. */ ! 78: if (super() == 0) { ! 79: /* Override EPERM set when super() failed. */ ! 80: u.u_error = EISDIR; ! 81: return; ! 82: } ! 83: ! 84: /* ! 85: * Opening a directory O_WRONLY is insane, even ! 86: * if you are superuser! ! 87: */ ! 88: if (mode == IPW) { ! 89: u.u_error = EISDIR; ! 90: return; ! 91: } ! 92: } ! 93: break; ! 94: case IFPIPE: ! 95: popen(ip, mode); ! 96: break; ! 97: } ! 98: } ! 99: ! 100: /* ! 101: * Given an inode, close it. ! 102: * ! 103: * NIGEL: Modified for new dclose (). ! 104: */ ! 105: iclose(ip, mode) ! 106: register INODE *ip; ! 107: { ! 108: register int type; ! 109: ! 110: ilock(ip); ! 111: switch (type = ip->i_mode&IFMT) { ! 112: case IFBLK: ! 113: bflush(ip->i_a.i_rdev); ! 114: /* FALL THROUGH */ ! 115: case IFCHR: ! 116: iunlock(ip); ! 117: dclose(ip->i_a.i_rdev, mode, type==IFCHR ? DFCHR : DFBLK); ! 118: ilock(ip); ! 119: break; ! 120: ! 121: case IFPIPE: ! 122: pclose(ip, mode); ! 123: break; ! 124: } ! 125: idetach(ip); ! 126: } ! 127: ! 128: /* ! 129: * Read from a file described by an inode and an io strucuture. ! 130: */ ! 131: iread(ip, iop) ! 132: register INODE *ip; ! 133: register IO *iop; ! 134: { ! 135: if (iop->io_ioc == 0) ! 136: return; ! 137: ! 138: switch (ip->i_mode & IFMT) { ! 139: case IFCHR: ! 140: dread (ip->i_a.i_rdev, iop); ! 141: break; ! 142: ! 143: case IFBLK: ! 144: case IFREG: ! 145: case IFDIR: ! 146: fread (ip, iop); ! 147: break; ! 148: ! 149: case IFPIPE: ! 150: pread (ip, iop); ! 151: break; ! 152: ! 153: default: ! 154: u.u_error = ENXIO; ! 155: break; ! 156: } ! 157: } ! 158: ! 159: /* ! 160: * Write to a file described by an inode and io structure. ! 161: */ ! 162: iwrite(ip, iop) ! 163: register INODE *ip; ! 164: register IO *iop; ! 165: { ! 166: imod (ip); /* write - mtime */ ! 167: icrt (ip); /* write - ctime */ ! 168: if (iop->io_ioc == 0) ! 169: return; ! 170: ! 171: switch (ip->i_mode & IFMT) { ! 172: case IFCHR: ! 173: dwrite (ip->i_a.i_rdev, iop); ! 174: break; ! 175: ! 176: case IFBLK: ! 177: fwrite (ip, iop); ! 178: break; ! 179: ! 180: case IFREG: ! 181: case IFDIR: ! 182: if (getment (ip->i_dev, 1) == NULL) ! 183: return; ! 184: fwrite (ip, iop); ! 185: break; ! 186: ! 187: case IFPIPE: ! 188: pwrite (ip, iop); ! 189: break; ! 190: ! 191: default: ! 192: u.u_error = ENXIO; ! 193: break; ! 194: } ! 195: } ! 196: ! 197: /* ! 198: * Given a block number, `b', store the offsets for the indirect blocks ! 199: * backwards in the array, `lp', and return a pointer just after the ! 200: * position where the first offset is stored. ! 201: */ ! 202: ! 203: static int * ! 204: lmap (b, lp, numblocks) ! 205: register daddr_t b; ! 206: register int *lp; ! 207: int * numblocks; ! 208: { ! 209: register int n; ! 210: ! 211: if ((n = ND - b) > 0) { ! 212: /* ! 213: * Just the one direct block, and further blocks up to the end ! 214: * of the block list in the inode. ! 215: */ ! 216: * lp ++ = b; ! 217: * numblocks = n; ! 218: return lp; ! 219: } ! 220: b -= ND; ! 221: ! 222: /* ! 223: * First, the initial indirect block, followed by as many further ! 224: * layers of indirection as we need. ! 225: */ ! 226: ! 227: n = nbnrem (b); ! 228: * numblocks = NBN - n; ! 229: * lp ++ = n; ! 230: ! 231: if ((b = nbndiv (b)) == 0) { ! 232: * lp ++ = ND; ! 233: return lp; ! 234: } ! 235: ! 236: ! 237: #if NI > 1 ! 238: b --; /* Make offset in next indirect block zero-based */ ! 239: ! 240: * lp ++ = nbnrem (b); ! 241: if ((b = nbndiv (b)) == 0) { ! 242: * lp ++ = ND + 1; ! 243: return lp; ! 244: } ! 245: ! 246: #if NI > 2 ! 247: b --; /* Make offset in next indirect block zero-based */ ! 248: ! 249: * lp ++ = nbnrem (b); ! 250: if ((b = nbndiv (b)) == 0) { ! 251: * lp ++ = ND + 2; ! 252: return lp; ! 253: } ! 254: #endif ! 255: #endif ! 256: SET_U_ERROR (EFBIG, "lmap"); ! 257: return NULL; ! 258: } ! 259: ! 260: int t_groupmode = 0; ! 261: ! 262: /* ! 263: * Convert the given virtual block to a physical block for the given inode. ! 264: * If the block does not map onto a physical block because the file is sparse ! 265: * but it does exist, 0 is returned. If an error is encountered, -1 is ! 266: * returned. ! 267: */ ! 268: ! 269: static int ! 270: vmap (ip, lb, count, blocklist, allocflag) ! 271: register INODE *ip; ! 272: daddr_t lb; ! 273: int count; ! 274: daddr_t * blocklist; ! 275: int allocflag; ! 276: { ! 277: daddr_t pb; ! 278: int list [1 + NI]; ! 279: int nblocks; ! 280: daddr_t * outlist; ! 281: BUF * buf; ! 282: int * lp; ! 283: int resid = count; ! 284: ! 285: more: ! 286: if ((lp = lmap (lb, list, & nblocks)) == NULL) ! 287: return -1; ! 288: ! 289: if (nblocks > resid) ! 290: nblocks = resid; ! 291: resid -= nblocks; ! 292: lb += nblocks; ! 293: ! 294: outlist = ip->i_a.i_addr; ! 295: buf = NULL; ! 296: ! 297: while (-- lp != list) { ! 298: if ((pb = outlist [* lp]) == 0) { ! 299: /* ! 300: * If an indirect block is not present, then this ! 301: * implies that at least the next "nblocks" leaf ! 302: * blocks are also not present. ! 303: */ ! 304: ! 305: do ! 306: * blocklist ++ = -1; ! 307: while (-- nblocks > 0); ! 308: goto done; ! 309: } ! 310: ! 311: if (buf != NULL) { ! 312: brelease (buf); ! 313: candaddr (pb); ! 314: } ! 315: ! 316: if ((buf = bread (ip->i_dev, pb, BUF_SYNC)) == NULL) ! 317: return -1; ! 318: ! 319: outlist = (daddr_t *) buf->b_vaddr; ! 320: } ! 321: ! 322: do { ! 323: if ((pb = outlist [list [0] ++]) == 0) ! 324: pb = -1; ! 325: else if (buf != NULL) ! 326: candaddr (pb); ! 327: * blocklist ++ = pb; ! 328: } while (-- nblocks > 0); ! 329: ! 330: done: ! 331: if (buf != NULL) ! 332: brelease (buf); ! 333: ! 334: if (t_groupmode && resid > 0) ! 335: goto more; ! 336: ! 337: return count - resid; ! 338: } ! 339: ! 340: int t_readahead = 0; ! 341: #define READGROUP 16 /* ! 342: * Maximum # of blocks to read as a ! 343: * single normal group. ! 344: */ ! 345: #define READAHEAD 8 /* ! 346: * Maximum # of blocks to read ahead. ! 347: */ ! 348: ! 349: /* ! 350: * Read from a regular or block special file. ! 351: */ ! 352: fread(ip, iop) ! 353: INODE *ip; ! 354: register IO *iop; ! 355: { ! 356: register int n; ! 357: register unsigned i; ! 358: register off_t res; ! 359: register unsigned off; ! 360: register dev_t dev; ! 361: register daddr_t lbn; ! 362: register daddr_t pbn; ! 363: register daddr_t abn; ! 364: register daddr_t zbn; ! 365: register BUF *bp; ! 366: register int blk; ! 367: daddr_t list [READGROUP + READAHEAD]; ! 368: int do_readahead; ! 369: ! 370: if ((ip->i_mode & IFMT) == IFBLK) { ! 371: blk = 1; ! 372: dev = ip->i_a.i_rdev; ! 373: } else { ! 374: blk = 0; ! 375: dev = ip->i_dev; ! 376: } ! 377: abn = 0; ! 378: zbn = 0; ! 379: lbn = blockn (iop->io_seek); ! 380: off = blocko (iop->io_seek); ! 381: ! 382: /* ! 383: * NIGEL: The commented-out code talks about a mysterious "unsigned ! 384: * prob" which does not in reality exist. All this really wants to ! 385: * do is pick the minimum of the remaining size and the requested ! 386: * size. ! 387: */ ! 388: ! 389: #if 0 ! 390: res = ip->i_size - iop->io_seek; ! 391: ! 392: if (blk != 0 || (res > 0 && res > iop->io_ioc)) ! 393: res = iop->io_ioc; /* unsigned prob with io_ioc */ ! 394: if (res <= 0) ! 395: return; ! 396: #endif ! 397: ! 398: if (blk) ! 399: res = iop->io_ioc; ! 400: else if ((res = ip->i_size - iop->io_seek) > iop->io_ioc) ! 401: res = iop->io_ioc; ! 402: ! 403: if (res == 0) ! 404: return; ! 405: ! 406: /* ! 407: * NIGEL: Test whether we want readahead based on whether this access ! 408: * immediately follows some previous access... this does not apply to ! 409: * inodes made from pipes, because there readahead will make us seek ! 410: * beyond the space that is legal (pipes store funky data where a ! 411: * normal file has indirect block pointers). ! 412: */ ! 413: ! 414: if ((lbn == ip->i_lastblock + 1) && (ip->i_mode & IFMT) != IFPIPE) { ! 415: if ((do_readahead = t_readahead) < 0) ! 416: do_readahead = 0; ! 417: } else ! 418: do_readahead = 0; ! 419: ! 420: do { ! 421: if (lbn >= zbn) { ! 422: if ((n = blockn (res + BSIZE - 1) + do_readahead) > ! 423: __ARRAY_LENGTH (list)) ! 424: n = __ARRAY_LENGTH (list); ! 425: ! 426: ASSERT (n > do_readahead); ! 427: ! 428: if (blk == 0 && (n = vmap (ip, lbn, n, list, 0)) < 0) ! 429: return; ! 430: ! 431: abn = lbn; ! 432: for (i = 0, zbn = lbn ; i < n ; i ++, zbn ++) { ! 433: if (blk != 0) ! 434: list [i] = pbn = zbn; ! 435: else if ((pbn = list [i]) == 0) ! 436: continue; ! 437: ! 438: if (t_readahead != -1) ! 439: (void) bread (dev, pbn, BUF_ASYNC); ! 440: } ! 441: } ! 442: ! 443: if (res < (n = BSIZE - off)) ! 444: n = res; ! 445: ! 446: if ((pbn = list [lbn - abn]) < 0) ! 447: ioclear (iop, n); ! 448: else { ! 449: if ((bp = bread (dev, pbn, BUF_SYNC)) == NULL) ! 450: return; ! 451: iowrite (iop, bp->b_vaddr + off, n); ! 452: brelease (bp); ! 453: } ! 454: ! 455: if (u.u_error) ! 456: return; ! 457: lbn ++; ! 458: off = 0; ! 459: } while ((res -= n) > 0); ! 460: ! 461: ip->i_lastblock = lbn - 1; ! 462: } ! 463: ! 464: int t_writemode = 0; ! 465: ! 466: /* ! 467: * Write to a regular or block special file. ! 468: */ ! 469: fwrite(ip, iop) ! 470: INODE *ip; ! 471: register IO *iop; ! 472: { ! 473: register unsigned n; ! 474: register unsigned off; ! 475: register daddr_t lbn; ! 476: register BUF *bp; ! 477: register int blk; ! 478: register int com; ! 479: ! 480: lbn = blockn(iop->io_seek); ! 481: off = blocko(iop->io_seek); ! 482: blk = (ip->i_mode & IFMT) == IFBLK; ! 483: while (iop->io_ioc > 0) { ! 484: n = BSIZE - off; ! 485: n = iop->io_ioc > n ? n : iop->io_ioc; ! 486: com = off == 0 && n == BSIZE; ! 487: if (blk == 0) ! 488: bp = aread (ip, lbn, com); ! 489: else { ! 490: if (com) ! 491: bp = bclaim (ip->i_a.i_rdev, lbn, BUF_SYNC); ! 492: else ! 493: bp = bread (ip->i_a.i_rdev, lbn, BUF_SYNC); ! 494: } ! 495: if (bp == NULL) ! 496: return; ! 497: ioread (iop, bp->b_vaddr + off, n); ! 498: bp->b_flag |= BFMOD; ! 499: if (com && (ip->i_mode & IFMT) != IFPIPE) { ! 500: bwrite (bp, t_writemode); ! 501: if (t_writemode) ! 502: brelease (bp); ! 503: } else ! 504: brelease (bp); ! 505: if (u.u_error) ! 506: return; ! 507: lbn ++; ! 508: off = 0; ! 509: if ((iop->io_seek += n) > ip->i_size) ! 510: if (blk == 0) ! 511: ip->i_size = iop->io_seek; ! 512: } ! 513: } ! 514: ! 515: /* ! 516: * Given an inode pointer, read the requested virtual block and return ! 517: * a buffer with the data. ! 518: */ ! 519: BUF * ! 520: vread(ip, lb) ! 521: register INODE *ip; ! 522: daddr_t lb; ! 523: { ! 524: daddr_t pb; ! 525: register BUF *bp; ! 526: ! 527: if (vmap (ip, lb, 1, & pb, 0) < 0) ! 528: return NULL; ! 529: if (pb != -1) ! 530: return bread (ip->i_dev, pb, BUF_SYNC); ! 531: bp = bclaim (NODEV, (daddr_t) 0, BUF_SYNC); ! 532: kclear (bp->b_vaddr, BSIZE); ! 533: return bp; ! 534: } ! 535: ! 536: /* ! 537: * Given an inode pointer, read the requested virtual block and return a ! 538: * buffer with the data. In sparse files, the necessary blocks are allocated. ! 539: * If the flag, `fflag' is set, the final buffer is just claimed rather than ! 540: * read as we are going to change it's contents completely. ! 541: */ ! 542: ! 543: BUF * ! 544: aread (ip, lb, fflag) ! 545: register INODE *ip; ! 546: daddr_t lb; ! 547: { ! 548: register BUF *bp; ! 549: register int *lp; ! 550: register dev_t dev; ! 551: register int l; ! 552: register int aflag; ! 553: register int lflag; ! 554: daddr_t * dp; ! 555: daddr_t pb; ! 556: int list[1+NI]; ! 557: int nblocks; ! 558: ! 559: if ((lp = lmap (lb, list, & nblocks)) == NULL) ! 560: return (NULL); ! 561: aflag = 0; ! 562: dev = ip->i_dev; ! 563: pb = ip->i_a.i_addr [l = * -- lp]; ! 564: if (pb == 0) { ! 565: aflag = 1; ! 566: if ((pb = balloc (dev)) == 0) ! 567: return NULL; ! 568: ip->i_a.i_addr [l] = pb; ! 569: } ! 570: for (;;) { ! 571: lflag = lp == list; ! 572: /* ! 573: * If we are not allocating a new block and the caller is ! 574: * going to preserve any of the data that we are going to ! 575: * return, then read in the previous block contents. ! 576: */ ! 577: if (! (aflag || (fflag && lflag))) { ! 578: if ((bp = bread (dev, pb, BUF_SYNC)) == NULL) ! 579: return NULL; ! 580: } else { ! 581: bp = bclaim (dev, pb, BUF_SYNC); ! 582: ! 583: /* ! 584: * If this is the last block and the caller is just ! 585: * going to overwrite it, don't zero-fill. ! 586: */ ! 587: ! 588: if (! (fflag && lflag)) ! 589: kclear (bp->b_vaddr, BSIZE); ! 590: bp->b_flag |= BFMOD; ! 591: } ! 592: if (lflag) ! 593: return bp; ! 594: ! 595: aflag = 0; ! 596: dp = bp->b_vaddr; ! 597: pb = dp [l = * -- lp]; ! 598: candaddr (pb); ! 599: if (pb == 0) { ! 600: aflag = 1; ! 601: if ((pb = balloc (dev)) == 0) { ! 602: brelease(bp); ! 603: return (NULL); ! 604: } ! 605: dp [l] = pb; ! 606: candaddr (dp [l]); ! 607: bp->b_flag |= BFMOD; ! 608: } ! 609: brelease (bp); ! 610: } ! 611: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.