|
|
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.