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