|
|
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: */
1.1.1.2 ! root 49: static char rcsid[] = "$Header: /cvsroot/src/sys/kern/Attic/vfs_bio.old.c,v 1.1.1.1 1993/03/21 09:46:36 cgd Exp $";
1.1 root 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: #ifdef notyet
59: #include "vm/vm.h"
60: #include "vm/vm_kern.h"
61: #endif /* notyet */
62: #include "resourcevar.h"
63:
64: /*
65: * Initialize buffer headers and related structures.
66: */
67: void bufinit()
68: {
69: struct bufhd *bh;
70: struct buf *bp;
71:
72: /* first, make a null hash table */
73: for(bh = bufhash; bh < bufhash + BUFHSZ; bh++) {
74: bh->b_flags = 0;
75: bh->b_forw = (struct buf *)bh;
76: bh->b_back = (struct buf *)bh;
77: }
78:
79: /* next, make a null set of free lists */
80: for(bp = bfreelist; bp < bfreelist + BQUEUES; bp++) {
81: bp->b_flags = 0;
82: bp->av_forw = bp;
83: bp->av_back = bp;
84: bp->b_forw = bp;
85: bp->b_back = bp;
86: }
87:
88: /* finally, initialize each buffer header and stick on empty q */
89: for(bp = buf; bp < buf + nbuf ; bp++) {
90: bp->b_flags = B_HEAD | B_INVAL; /* we're just an empty header */
91: bp->b_dev = NODEV;
92: bp->b_vp = 0;
93: binstailfree(bp, bfreelist + BQ_EMPTY);
94: binshash(bp, bfreelist + BQ_EMPTY);
95: }
96: }
97:
98: /*
99: * Find the block in the buffer pool.
100: * If the buffer is not present, allocate a new buffer and load
101: * its contents according to the filesystem fill routine.
102: */
103: bread(vp, blkno, size, cred, bpp)
104: struct vnode *vp;
105: daddr_t blkno;
106: int size;
107: struct ucred *cred;
108: struct buf **bpp;
109: {
110: struct buf *bp;
111: int rv = 0;
112:
113: bp = getblk (vp, blkno, size);
114:
115: /* if not found in cache, do some I/O */
116: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
117: bp->b_flags |= B_READ;
118: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
119: bp->b_rcred = cred;
120: VOP_STRATEGY(bp);
121: rv = biowait (bp);
122: }
123: *bpp = bp;
124:
125: return (rv);
126: }
127:
128: /*
129: * Operates like bread, but also starts I/O on the specified
130: * read-ahead block. [See page 55 of Bach's Book]
131: */
132: breada(vp, blkno, size, rablkno, rabsize, cred, bpp)
133: struct vnode *vp;
134: daddr_t blkno; int size;
135: daddr_t rablkno; int rabsize;
136: struct ucred *cred;
137: struct buf **bpp;
138: {
139: struct buf *bp, *rabp;
140: int rv = 0, needwait = 0;
141:
142: bp = getblk (vp, blkno, size);
143:
144: /* if not found in cache, do some I/O */
145: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
146: bp->b_flags |= B_READ;
147: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
148: bp->b_rcred = cred;
149: VOP_STRATEGY(bp);
150: needwait++;
151: }
152:
153: rabp = getblk (vp, rablkno, rabsize);
154:
155: /* if not found in cache, do some I/O (overlapped with first) */
156: if ((rabp->b_flags & B_CACHE) == 0 || (rabp->b_flags & B_INVAL) != 0) {
157: rabp->b_flags |= B_READ | B_ASYNC;
158: rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
159: rabp->b_rcred = cred;
160: VOP_STRATEGY(rabp);
161: } else
162: brelse(rabp);
163:
164: /* wait for original I/O */
165: if (needwait)
166: rv = biowait (bp);
167:
168: *bpp = bp;
169: return (rv);
170: }
171:
172: /*
173: * Synchronous write.
174: * Release buffer on completion.
175: */
176: bwrite(bp)
177: register struct buf *bp;
178: {
179: int rv;
180:
181: if(bp->b_flags & B_INVAL) {
182: brelse(bp);
183: return (0);
184: } else {
185: int wasdelayed;
186:
187: if(!(bp->b_flags & B_BUSY))panic("bwrite: not busy");
188: wasdelayed = bp->b_flags & B_DELWRI;
189: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_ASYNC|B_DELWRI);
190: if(wasdelayed) reassignbuf(bp, bp->b_vp);
191: bp->b_flags |= B_DIRTY;
192: bp->b_vp->v_numoutput++;
193: VOP_STRATEGY(bp);
194: rv = biowait(bp);
195: brelse(bp);
196: return (rv);
197: }
198: }
199:
200: /*
201: * Delayed write.
202: *
203: * The buffer is marked dirty, but is not queued for I/O.
204: * This routine should be used when the buffer is expected
205: * to be modified again soon, typically a small write that
206: * partially fills a buffer.
207: *
208: * NB: magnetic tapes cannot be delayed; they must be
209: * written in the order that the writes are requested.
210: */
211: void bdwrite(bp)
212: register struct buf *bp;
213: {
214:
215: if(!(bp->b_flags & B_BUSY))panic("bdwrite: not busy");
216: if(bp->b_flags & B_INVAL) {
217: brelse(bp);
218: }
219: if(bp->b_flags & B_TAPE) {
220: bwrite(bp);
221: return;
222: }
223: bp->b_flags &= ~(B_READ|B_DONE);
224: bp->b_flags |= B_DIRTY|B_DELWRI;
225: reassignbuf(bp, bp->b_vp);
226: brelse(bp);
227: return;
228: }
229:
230: /*
231: * Asynchronous write.
232: * Start I/O on a buffer, but do not wait for it to complete.
233: * The buffer is released when the I/O completes.
234: */
235: bawrite(bp)
236: register struct buf *bp;
237: {
238:
239: if(!(bp->b_flags & B_BUSY))panic("bawrite: not busy");
240: if(bp->b_flags & B_INVAL)
241: brelse(bp);
242: else {
243: int wasdelayed;
244:
245: wasdelayed = bp->b_flags & B_DELWRI;
246: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
247: if(wasdelayed) reassignbuf(bp, bp->b_vp);
248:
249: bp->b_flags |= B_DIRTY | B_ASYNC;
250: bp->b_vp->v_numoutput++;
251: VOP_STRATEGY(bp);
252: }
253: }
254:
255: /*
256: * Release a buffer.
257: * Even if the buffer is dirty, no I/O is started.
258: */
259: brelse(bp)
260: register struct buf *bp;
261: {
262: int x;
263:
264: /* anyone need a "free" block? */
265: x=splbio();
266: if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) {
267: (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED;
268: wakeup(bfreelist);
269: }
270: /* anyone need this very block? */
271: if (bp->b_flags & B_WANTED) {
272: bp->b_flags &= ~B_WANTED;
273: wakeup(bp);
274: }
275:
276: if (bp->b_flags & (B_INVAL|B_ERROR)) {
277: bp->b_flags |= B_INVAL;
278: bp->b_flags &= ~(B_DELWRI|B_CACHE);
279: if(bp->b_vp)
280: brelvp(bp);
281: }
282:
283: /* enqueue */
284: /* just an empty buffer head ... */
285: /*if(bp->b_flags & B_HEAD)
286: binsheadfree(bp, bfreelist + BQ_EMPTY)*/
287: /* buffers with junk contents */
288: /*else*/ if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE))
289: binsheadfree(bp, bfreelist + BQ_AGE)
290: /* buffers with stale but valid contents */
291: else if(bp->b_flags & B_AGE)
292: binstailfree(bp, bfreelist + BQ_AGE)
293: /* buffers with valid and quite potentially reuseable contents */
294: else
295: binstailfree(bp, bfreelist + BQ_LRU)
296:
297: /* unlock */
298: bp->b_flags &= ~B_BUSY;
299: splx(x);
300:
301: return;
302: }
303:
304: int freebufspace;
305: int allocbufspace;
306:
307: /*
308: * Find a buffer which is available for use.
309: * If free memory for buffer space and an empty header from the empty list,
310: * use that. Otherwise, select something from a free list.
311: * Preference is to AGE list, then LRU list.
312: */
313: struct buf *
314: getnewbuf(sz)
315: {
316: struct buf *bp;
317: int x;
318:
319: x = splbio();
320: start:
321: /* can we constitute a new buffer? */
322: if (freebufspace > sz
323: && bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) {
324: caddr_t addr;
325:
326: #ifndef notyet
327: if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;
328: #else /* notyet */
329: /* get new memory buffer */
330: if (round_page(sz) == sz)
331: addr = (caddr_t) kmem_alloc(buffer_map, sz);
332: else
333: addr = (caddr_t) malloc (sz, M_TEMP, M_WAITOK);
334: /*if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;*/
335: #endif /* notyet */
336: freebufspace -= sz;
337: allocbufspace += sz;
338:
339: bp = bfreelist[BQ_EMPTY].av_forw;
340: bp->b_flags = B_BUSY | B_INVAL;
341: bremfree(bp);
342: #ifndef notyet
343: bp->b_un.b_addr = (caddr_t) addr;
344: #else /* notyet */
345: bp->b_un.b_addr = addr;
346: #endif /* notyet */
347: goto fillin;
348: }
349:
350: tryfree:
351: if (bfreelist[BQ_AGE].av_forw != (struct buf *)bfreelist+BQ_AGE) {
352: bp = bfreelist[BQ_AGE].av_forw;
353: bremfree(bp);
354: } else if (bfreelist[BQ_LRU].av_forw != (struct buf *)bfreelist+BQ_LRU) {
355: bp = bfreelist[BQ_LRU].av_forw;
356: bremfree(bp);
357: } else {
358: /* wait for a free buffer of any kind */
359: (bfreelist + BQ_AGE)->b_flags |= B_WANTED;
360: sleep(bfreelist, PRIBIO);
361: splx(x);
362: return (0);
363: }
364:
365: /* if we are a delayed write, convert to an async write! */
366: if (bp->b_flags & B_DELWRI) {
367: /*bp->b_flags &= ~B_DELWRI;*/
368: bp->b_flags |= B_BUSY;
369: bawrite (bp);
370: goto start;
371: }
372:
373: /*if (bp->b_flags & (B_INVAL|B_ERROR) == 0) {
374: bremhash(bp);
375: }*/
376:
377: if(bp->b_vp)
378: brelvp(bp);
379:
380: /* we are not free, nor do we contain interesting data */
381: bp->b_flags = B_BUSY;
382: fillin:
383: bremhash(bp);
384: splx(x);
385: bp->b_dev = NODEV;
386: bp->b_vp = NULL;
387: bp->b_blkno = bp->b_lblkno = 0;
388: bp->b_iodone = 0;
389: bp->b_error = 0;
390: bp->b_wcred = bp->b_rcred = NOCRED;
391: if (bp->b_bufsize != sz) allocbuf(bp, sz);
392: bp->b_bcount = bp->b_bufsize = sz;
393: bp->b_dirtyoff = bp->b_dirtyend = 0;
394: return (bp);
395: }
396:
397: /*
398: * Check to see if a block is currently memory resident.
399: */
400: struct buf *incore(vp, blkno)
401: struct vnode *vp;
402: daddr_t blkno;
403: {
404: struct buf *bh;
405: struct buf *bp;
406:
407: bh = BUFHASH(vp, blkno);
408:
409: /* Search hash chain */
410: bp = bh->b_forw;
411: while (bp != (struct buf *) bh) {
412: /* hit */
413: if (bp->b_lblkno == blkno && bp->b_vp == vp
414: && (bp->b_flags & B_INVAL) == 0)
415: return (bp);
416: bp = bp->b_forw;
417: }
418:
419: return(0);
420: }
421:
422: /*
423: * Get a block of requested size that is associated with
424: * a given vnode and block offset. If it is found in the
425: * block cache, mark it as having been found, make it busy
426: * and return it. Otherwise, return an empty block of the
427: * correct size. It is up to the caller to insure that the
428: * cached blocks be of the correct size.
429: */
430: struct buf *
431: getblk(vp, blkno, size)
432: register struct vnode *vp;
433: daddr_t blkno;
434: int size;
435: {
436: struct buf *bp, *bh;
437: int x;
438:
439: for (;;) {
440: if (bp = incore(vp, blkno)) {
441: x = splbio();
442: if (bp->b_flags & B_BUSY) {
443: bp->b_flags |= B_WANTED;
444: sleep (bp, PRIBIO);
445: splx(x);
446: continue;
447: }
448: bp->b_flags |= B_BUSY | B_CACHE;
449: bremfree(bp);
450: if (size > bp->b_bufsize)
451: panic("now what do we do?");
452: /* if (bp->b_bufsize != size) allocbuf(bp, size); */
453: } else {
454:
455: if((bp = getnewbuf(size)) == 0) continue;
456: bp->b_blkno = bp->b_lblkno = blkno;
457: bgetvp(vp, bp);
458: x = splbio();
459: bh = BUFHASH(vp, blkno);
460: binshash(bp, bh);
461: bp->b_flags = B_BUSY;
462: }
463: splx(x);
464: return (bp);
465: }
466: }
467:
468: /*
469: * Get an empty, disassociated buffer of given size.
470: */
471: struct buf *
472: geteblk(size)
473: int size;
474: {
475: struct buf *bp;
476: int x;
477:
478: while ((bp = getnewbuf(size)) == 0)
479: ;
480: x = splbio();
481: binshash(bp, bfreelist + BQ_AGE);
482: splx(x);
483:
484: return (bp);
485: }
486:
487: /*
488: * Exchange a buffer's underlying buffer storage for one of different
489: * size, taking care to maintain contents appropriately. When buffer
490: * increases in size, caller is responsible for filling out additional
491: * contents. When buffer shrinks in size, data is lost, so caller must
492: * first return it to backing store before shrinking the buffer, as
493: * no implied I/O will be done.
494: *
495: * Expanded buffer is returned as value.
496: */
497: void
498: allocbuf(bp, size)
499: register struct buf *bp;
500: int size;
501: {
502: caddr_t newcontents;
503:
504: /* get new memory buffer */
505: #ifndef notyet
506: newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK);
507: #else /* notyet */
508: if (round_page(size) == size)
509: newcontents = (caddr_t) kmem_alloc(buffer_map, size);
510: else
511: newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK);
512: #endif /* notyet */
513:
514: /* copy the old into the new, up to the maximum that will fit */
515: bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size));
516:
517: /* return old contents to free heap */
518: #ifndef notyet
519: free (bp->b_un.b_addr, M_TEMP);
520: #else /* notyet */
521: if (round_page(bp->b_bufsize) == bp->b_bufsize)
522: kmem_free(buffer_map, bp->b_un.b_addr, bp->b_bufsize);
523: else
524: free (bp->b_un.b_addr, M_TEMP);
525: #endif /* notyet */
526:
527: /* adjust buffer cache's idea of memory allocated to buffer contents */
528: freebufspace -= size - bp->b_bufsize;
529: allocbufspace += size - bp->b_bufsize;
530:
531: /* update buffer header */
532: bp->b_un.b_addr = newcontents;
533: bp->b_bcount = bp->b_bufsize = size;
534: }
535:
536: /*
537: * Patiently await operations to complete on this buffer.
538: * When they do, extract error value and return it.
539: * Extract and return any errors associated with the I/O.
540: * If an invalid block, force it off the lookup hash chains.
541: */
542: biowait(bp)
543: register struct buf *bp;
544: {
545: int x;
546:
547: x = splbio();
548: while ((bp->b_flags & B_DONE) == 0)
549: sleep((caddr_t)bp, PRIBIO);
550: if((bp->b_flags & B_ERROR) || bp->b_error) {
551: if ((bp->b_flags & B_INVAL) == 0) {
552: bp->b_flags |= B_INVAL;
553: bremhash(bp);
554: binshash(bp, bfreelist + BQ_AGE);
555: }
556: if (!bp->b_error)
557: bp->b_error = EIO;
558: else
559: bp->b_flags |= B_ERROR;
560: splx(x);
561: return (bp->b_error);
562: } else {
563: splx(x);
564: return (0);
565: }
566: }
567:
568: /*
569: * Finish up operations on a buffer, calling an optional
570: * function (if requested), and releasing the buffer if
571: * marked asynchronous. Then mark this buffer done so that
572: * others biowait()'ing for it will notice when they are
573: * woken up from sleep().
574: */
575: biodone(bp)
576: register struct buf *bp;
577: {
578: int x;
579:
580: x = splbio();
581: if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp);
582: bp->b_flags &= ~B_CALL;
583: if ((bp->b_flags & (B_READ|B_DIRTY)) == B_DIRTY) {
584: bp->b_flags &= ~B_DIRTY;
585: vwakeup(bp);
586: }
587: if (bp->b_flags & B_ASYNC)
588: brelse(bp);
589: bp->b_flags &= ~B_ASYNC;
590: bp->b_flags |= B_DONE;
591: wakeup(bp);
592: splx(x);
593: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.