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