|
|
1.1 root 1: /*
2: * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This software is a component of "386BSD" developed by
16: William F. Jolitz, TeleMuse.
17: * 4. Neither the name of the developer nor the name "386BSD"
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
22: * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
23: * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
24: * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
25: * NOT MAKE USE THIS WORK.
26: *
27: * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
28: * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
29: * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
30: * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
31: * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
32: * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
33: * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
34: * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
35: *
36: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
37: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39: * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
40: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46: * SUCH DAMAGE.
47: *
48: */
49: static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/vfs__bio.c,v 1.2 92/01/21 21:30:08 william Exp $";
50:
51: #include "param.h"
52: #include "proc.h"
53: #include "vnode.h"
54: #include "buf.h"
55: #include "specdev.h"
56: #include "mount.h"
57: #include "malloc.h"
58: #include "resourcevar.h"
59:
60: /*
61: * Initialize buffer headers and related structures.
62: */
63: void bufinit()
64: {
65: struct bufhd *bh;
66: struct buf *bp;
67:
68: /* first, make a null hash table */
69: for(bh = bufhash; bh < bufhash + BUFHSZ; bh++) {
70: bh->b_flags = 0;
71: bh->b_forw = (struct buf *)bh;
72: bh->b_back = (struct buf *)bh;
73: }
74:
75: /* next, make a null set of free lists */
76: for(bp = bfreelist; bp < bfreelist + BQUEUES; bp++) {
77: bp->b_flags = 0;
78: bp->av_forw = bp;
79: bp->av_back = bp;
80: bp->b_forw = bp;
81: bp->b_back = bp;
82: }
83:
84: /* finally, initialize each buffer header and stick on empty q */
85: for(bp = buf; bp < buf + nbuf ; bp++) {
86: bp->b_flags = B_HEAD | B_INVAL; /* we're just an empty header */
87: bp->b_dev = NODEV;
88: bp->b_vp = 0;
89: binstailfree(bp, bfreelist + BQ_EMPTY);
90: binshash(bp, bfreelist + BQ_EMPTY);
91: }
92: }
93:
94: /*
95: * Find the block in the buffer pool.
96: * If the buffer is not present, allocate a new buffer and load
97: * its contents according to the filesystem fill routine.
98: */
99: bread(vp, blkno, size, cred, bpp)
100: struct vnode *vp;
101: daddr_t blkno;
102: int size;
103: struct ucred *cred;
104: struct buf **bpp;
105: {
106: struct buf *bp;
107: int rv = 0;
108:
109: bp = getblk (vp, blkno, size);
110:
111: /* if not found in cache, do some I/O */
112: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
113: bp->b_flags |= B_READ;
114: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
115: VOP_STRATEGY(bp);
116: rv = biowait (bp);
117: }
118: *bpp = bp;
119:
120: return (rv);
121: }
122:
123: /*
124: * Operates like bread, but also starts I/O on the specified
125: * read-ahead block. [See page 55 of Bach's Book]
126: */
127: breada(vp, blkno, size, rablkno, rabsize, cred, bpp)
128: struct vnode *vp;
129: daddr_t blkno; int size;
130: daddr_t rablkno; int rabsize;
131: struct ucred *cred;
132: struct buf **bpp;
133: {
134: struct buf *bp, *rabp;
135: int rv = 0, needwait = 0;
136:
137: bp = getblk (vp, blkno, size);
138:
139: /* if not found in cache, do some I/O */
140: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
141: bp->b_flags |= B_READ;
142: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
143: VOP_STRATEGY(bp);
144: needwait++;
145: }
146:
147: rabp = getblk (vp, rablkno, rabsize);
148:
149: /* if not found in cache, do some I/O (overlapped with first) */
150: if ((rabp->b_flags & B_CACHE) == 0 || (rabp->b_flags & B_INVAL) != 0) {
151: rabp->b_flags |= B_READ | B_ASYNC;
152: rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
153: VOP_STRATEGY(rabp);
154: } else
155: brelse(rabp);
156:
157: /* wait for original I/O */
158: if (needwait)
159: rv = biowait (bp);
160:
161: *bpp = bp;
162: return (rv);
163: }
164:
165: /*
166: * Synchronous write.
167: * Release buffer on completion.
168: */
169: bwrite(bp)
170: register struct buf *bp;
171: {
172: int rv;
173:
174: if(bp->b_flags & B_INVAL) {
175: brelse(bp);
176: return (0);
177: } else {
178: int wasdelayed;
179:
180: if(!(bp->b_flags & B_BUSY))panic("bwrite: not busy");
181: wasdelayed = bp->b_flags & B_DELWRI;
182: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_ASYNC|B_DELWRI);
183: if(wasdelayed) reassignbuf(bp, bp->b_vp);
184: bp->b_flags |= B_DIRTY;
185: VOP_STRATEGY(bp);
186: rv = biowait(bp);
187: if (!rv)
188: bp->b_flags &= ~B_DIRTY;
189: brelse(bp);
190: return (rv);
191: }
192: }
193:
194: /*
195: * Delayed write.
196: *
197: * The buffer is marked dirty, but is not queued for I/O.
198: * This routine should be used when the buffer is expected
199: * to be modified again soon, typically a small write that
200: * partially fills a buffer.
201: *
202: * NB: magnetic tapes cannot be delayed; they must be
203: * written in the order that the writes are requested.
204: */
205: void bdwrite(bp)
206: register struct buf *bp;
207: {
208:
209: if(!(bp->b_flags & B_BUSY))panic("bdwrite: not busy");
210: if(bp->b_flags & B_INVAL) {
211: brelse(bp);
212: }
213: if(bp->b_flags & B_TAPE) {
214: bwrite(bp);
215: return;
216: }
217: bp->b_flags &= ~(B_READ|B_DONE);
218: bp->b_flags |= B_DIRTY|B_DELWRI;
219: reassignbuf(bp, bp->b_vp);
220: brelse(bp);
221: return;
222: }
223:
224: /*
225: * Asynchronous write.
226: * Start I/O on a buffer, but do not wait for it to complete.
227: * The buffer is released when the I/O completes.
228: */
229: bawrite(bp)
230: register struct buf *bp;
231: {
232:
233: if(!(bp->b_flags & B_BUSY))panic("bawrite: not busy");
234: if(bp->b_flags & B_INVAL)
235: brelse(bp);
236: else {
237: int wasdelayed;
238:
239: wasdelayed = bp->b_flags & B_DELWRI;
240: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
241: if(wasdelayed) reassignbuf(bp, bp->b_vp);
242:
243: bp->b_flags |= B_DIRTY | B_ASYNC;
244: VOP_STRATEGY(bp);
245: }
246: }
247:
248: /*
249: * Release a buffer.
250: * Even if the buffer is dirty, no I/O is started.
251: */
252: brelse(bp)
253: register struct buf *bp;
254: {
255: int x;
256:
257: /* anyone need a "free" block? */
258: x=splbio();
259: if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) {
260: (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED;
261: wakeup(bfreelist);
262: }
263: /* anyone need this very block? */
264: if (bp->b_flags & B_WANTED) {
265: bp->b_flags &= ~B_WANTED;
266: wakeup(bp);
267: }
268:
269: if (bp->b_flags & (B_INVAL|B_ERROR)) {
270: bp->b_flags |= B_INVAL;
271: bp->b_flags &= ~(B_DELWRI|B_CACHE);
272: if(bp->b_vp)
273: brelvp(bp);
274: }
275:
276: /* enqueue */
277: /* just an empty buffer head ... */
278: /*if(bp->b_flags & B_HEAD)
279: binsheadfree(bp, bfreelist + BQ_EMPTY)*/
280: /* buffers with junk contents */
281: /*else*/ if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE))
282: binsheadfree(bp, bfreelist + BQ_AGE)
283: /* buffers with stale but valid contents */
284: else if(bp->b_flags & B_AGE)
285: binstailfree(bp, bfreelist + BQ_AGE)
286: /* buffers with valid and quite potentially reuseable contents */
287: else
288: binstailfree(bp, bfreelist + BQ_LRU)
289:
290: /* unlock */
291: bp->b_flags &= ~B_BUSY;
292: splx(x);
293:
294: return;
295: }
296:
297: int freebufspace = 20*NBPG;
298: int allocbufspace;
299:
300: /*
301: * Find a buffer which is available for use.
302: * If free memory for buffer space and an empty header from the empty list,
303: * use that. Otherwise, select something from a free list.
304: * Preference is to AGE list, then LRU list.
305: */
306: struct buf *
307: getnewbuf(sz)
308: {
309: struct buf *bp;
310: int x;
311:
312: x = splbio();
313: start:
314: /* can we constitute a new buffer? */
315: if (freebufspace > sz
316: && bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) {
317: caddr_t addr;
318:
319: if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;
320: freebufspace -= sz;
321: allocbufspace += sz;
322:
323: bp = bfreelist[BQ_EMPTY].av_forw;
324: bp->b_flags = B_BUSY | B_INVAL;
325: bremfree(bp);
326: bp->b_un.b_addr = (caddr_t) addr;
327: goto fillin;
328: }
329:
330: tryfree:
331: if (bfreelist[BQ_AGE].av_forw != (struct buf *)bfreelist+BQ_AGE) {
332: bp = bfreelist[BQ_AGE].av_forw;
333: bremfree(bp);
334: } else if (bfreelist[BQ_LRU].av_forw != (struct buf *)bfreelist+BQ_LRU) {
335: bp = bfreelist[BQ_LRU].av_forw;
336: bremfree(bp);
337: } else {
338: /* wait for a free buffer of any kind */
339: (bfreelist + BQ_AGE)->b_flags |= B_WANTED;
340: sleep(bfreelist, PRIBIO);
341: splx(x);
342: return (0);
343: }
344:
345: /* if we are a delayed write, convert to an async write! */
346: if (bp->b_flags & B_DELWRI) {
347: /*bp->b_flags &= ~B_DELWRI;*/
348: bp->b_flags |= B_BUSY;
349: bawrite (bp);
350: goto start;
351: }
352:
353: /*if (bp->b_flags & (B_INVAL|B_ERROR) == 0) {
354: bremhash(bp);
355: }*/
356:
357: if(bp->b_vp)
358: brelvp(bp);
359:
360: /* we are not free, nor do we contain interesting data */
361: bp->b_flags = B_BUSY;
362: fillin:
363: bremhash(bp);
364: splx(x);
365: bp->b_dev = NODEV;
366: bp->b_vp = NULL;
367: bp->b_blkno = bp->b_lblkno = 0;
368: bp->b_iodone = 0;
369: bp->b_error = 0;
370: bp->b_wcred = bp->b_rcred = NOCRED;
371: if (bp->b_bufsize != sz) allocbuf(bp, sz);
372: bp->b_bcount = bp->b_bufsize = sz;
373: bp->b_dirtyoff = bp->b_dirtyend = 0;
374: return (bp);
375: }
376:
377: /*
378: * Check to see if a block is currently memory resident.
379: */
380: struct buf *incore(vp, blkno)
381: struct vnode *vp;
382: daddr_t blkno;
383: {
384: struct buf *bh;
385: struct buf *bp;
386:
387: bh = BUFHASH(vp, blkno);
388:
389: /* Search hash chain */
390: bp = bh->b_forw;
391: while (bp != (struct buf *) bh) {
392: /* hit */
393: if (bp->b_lblkno == blkno && bp->b_vp == vp
394: && (bp->b_flags & B_INVAL) == 0)
395: return (bp);
396: bp = bp->b_forw;
397: }
398:
399: return(0);
400: }
401:
402: /*
403: * Get a block of requested size that is associated with
404: * a given vnode and block offset. If it is found in the
405: * block cache, mark it as having been found, make it busy
406: * and return it. Otherwise, return an empty block of the
407: * correct size. It is up to the caller to insure that the
408: * cached blocks be of the correct size.
409: */
410: struct buf *
411: getblk(vp, blkno, size)
412: register struct vnode *vp;
413: daddr_t blkno;
414: int size;
415: {
416: struct buf *bp, *bh;
417: int x;
418:
419: for (;;) {
420: if (bp = incore(vp, blkno)) {
421: x = splbio();
422: if (bp->b_flags & B_BUSY) {
423: bp->b_flags |= B_WANTED;
424: sleep (bp, PRIBIO);
425: continue;
426: }
427: bp->b_flags |= B_BUSY | B_CACHE;
428: bremfree(bp);
429: if (size > bp->b_bufsize)
430: panic("now what do we do?");
431: /* if (bp->b_bufsize != size) allocbuf(bp, size); */
432: } else {
433:
434: if((bp = getnewbuf(size)) == 0) continue;
435: bp->b_blkno = bp->b_lblkno = blkno;
436: bgetvp(vp, bp);
437: x = splbio();
438: bh = BUFHASH(vp, blkno);
439: binshash(bp, bh);
440: bp->b_flags = B_BUSY;
441: }
442: splx(x);
443: return (bp);
444: }
445: }
446:
447: /*
448: * Get an empty, disassociated buffer of given size.
449: */
450: struct buf *
451: geteblk(size)
452: int size;
453: {
454: struct buf *bp;
455: int x;
456:
457: while ((bp = getnewbuf(size)) == 0)
458: ;
459: x = splbio();
460: binshash(bp, bfreelist + BQ_AGE);
461: splx(x);
462:
463: return (bp);
464: }
465:
466: /*
467: * Exchange a buffer's underlying buffer storage for one of different
468: * size, taking care to maintain contents appropriately. When buffer
469: * increases in size, caller is responsible for filling out additional
470: * contents. When buffer shrinks in size, data is lost, so caller must
471: * first return it to backing store before shrinking the buffer, as
472: * no implied I/O will be done.
473: *
474: * Expanded buffer is returned as value.
475: */
476: struct buf *
477: allocbuf(bp, size)
478: register struct buf *bp;
479: int size;
480: {
481: caddr_t newcontents;
482:
483: /* get new memory buffer */
484: newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK);
485:
486: /* copy the old into the new, up to the maximum that will fit */
487: bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size));
488:
489: /* return old contents to free heap */
490: free (bp->b_un.b_addr, M_TEMP);
491:
492: /* adjust buffer cache's idea of memory allocated to buffer contents */
493: freebufspace -= size - bp->b_bufsize;
494: allocbufspace += size - bp->b_bufsize;
495:
496: /* update buffer header */
497: bp->b_un.b_addr = newcontents;
498: bp->b_bcount = bp->b_bufsize = size;
499:
500: return(bp);
501: }
502:
503: /*
504: * Patiently await operations to complete on this buffer.
505: * When they do, extract error value and return it.
506: * Extract and return any errors associated with the I/O.
507: * If an invalid block, force it off the lookup hash chains.
508: */
509: biowait(bp)
510: register struct buf *bp;
511: {
512: int x;
513:
514: x = splbio();
515: while ((bp->b_flags & B_DONE) == 0)
516: sleep((caddr_t)bp, PRIBIO);
517: if((bp->b_flags & B_ERROR) || bp->b_error) {
518: if ((bp->b_flags & B_INVAL) == 0) {
519: bp->b_flags |= B_INVAL;
520: bremhash(bp);
521: binshash(bp, bfreelist + BQ_AGE);
522: }
523: if (!bp->b_error)
524: bp->b_error = EIO;
525: else
526: bp->b_flags |= B_ERROR;
527: splx(x);
528: return (bp->b_error);
529: } else {
530: splx(x);
531: return (0);
532: }
533: }
534:
535: /*
536: * Finish up operations on a buffer, calling an optional
537: * function (if requested), and releasing the buffer if
538: * marked asynchronous. Then mark this buffer done so that
539: * others biowait()'ing for it will notice when they are
540: * woken up from sleep().
541: */
542: biodone(bp)
543: register struct buf *bp;
544: {
545: int x;
546:
547: x = splbio();
548: if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp);
549: bp->b_flags &= ~B_CALL;
550: if (bp->b_flags & B_ASYNC) brelse(bp);
551: bp->b_flags &= ~B_ASYNC;
552: bp->b_flags |= B_DONE;
553: wakeup(bp);
554: splx(x);
555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.