|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*-
27: * Copyright (c) 1982, 1986, 1989, 1993
28: * The Regents of the University of California. All rights reserved.
29: * (c) UNIX System Laboratories, Inc.
30: * All or some portions of this file are derived from material licensed
31: * to the University of California by American Telephone and Telegraph
32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33: * the permission of UNIX System Laboratories, Inc.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * The NEXTSTEP Software License Agreement specifies the terms
64: * and conditions for redistribution.
65: *
66: * @(#)vfs_bio.c 8.6 (Berkeley) 1/11/94
67: */
68:
69: /*
70: * Some references:
71: * Bach: The Design of the UNIX Operating System (Prentice Hall, 1986)
72: * Leffler, et al.: The Design and Implementation of the 4.3BSD
73: * UNIX Operating System (Addison Welley, 1989)
74: */
75: /*
76: * HISTORY
77: * 17-July-97 Umesh Vaishampayan ([email protected])
78: * Eliminated multiple definition of buffers and buf which are defined in
79: * conf/param.c.
80: * Eliminated multiple definition of nbuf and bufpages which are defined
81: * in machdep/XXX/unix_startup.c
82: *
83: * 11-July-97 Umesh Vaishampayan ([email protected])
84: * Defined global variables for use when tracing is turned on.
85: */
86:
87: #include <mach_nbc.h>
88: #include <sys/param.h>
89: #include <sys/systm.h>
90: #include <sys/proc.h>
91: #include <sys/buf.h>
92: #include <sys/vnode.h>
93: #include <sys/mount.h>
94: #include <sys/trace.h>
95: #include <sys/malloc.h>
96: #include <sys/resourcevar.h>
97: #include <miscfs/specfs/specdev.h>
98:
99: extern void reassignbuf(struct buf *, struct vnode *);
100:
101: extern int nbuf; /* The number of buffer headers */
102: extern int niobuf;
103: extern struct buf *buf; /* The buffer headers. */
104: extern char *buffers; /* The buffer contents. */
105: extern int bufpages; /* Number of memory pages in the buffer pool. */
106: struct buf *swbuf; /* Swap I/O buffer headers. */
107: int nswbuf; /* Number of swap I/O buffer headers. */
108: struct buf bswlist; /* Head of swap I/O buffer headers free list. */
109: struct buf *bclnlist;/* Head of cleaned page list. */
110:
111: #if TRACE
112: struct proc *traceproc;
113: int tracewhich, tracebuf[TRCSIZ];
114: u_int tracex;
115: char traceflags[TR_NFLAGS];
116: #endif /* TRACE */
117:
118: /* Macros to clear/set/test flags. */
119: #define SET(t, f) (t) |= (f)
120: #define CLR(t, f) (t) &= ~(f)
121: #define ISSET(t, f) ((t) & (f))
122:
123: /*
124: * Definitions for the buffer hash lists.
125: */
126: #define BUFHASH(dvp, lbn) \
127: (&bufhashtbl[((long)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
128: LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash;
129: u_long bufhash;
130:
131: /*
132: * Insq/Remq for the buffer hash lists.
133: */
134: #define binshash(bp, dp) LIST_INSERT_HEAD(dp, bp, b_hash)
135: #define bremhash(bp) LIST_REMOVE(bp, b_hash)
136:
137: /*
138: * Definitions for the buffer free lists.
139: */
140: #define BQUEUES 4 /* number of free buffer queues */
141:
142: #define BQ_LOCKED 0 /* super-blocks &c */
143: #define BQ_LRU 1 /* lru, useful buffers */
144: #define BQ_AGE 2 /* rubbish */
145: #define BQ_EMPTY 3 /* buffer headers with no memory */
146:
147: TAILQ_HEAD(ioqueue, buf) iobufqueue;
148: TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
149: int needbuffer;
150:
151: /*
152: * Insq/Remq for the buffer free lists.
153: */
1.1.1.2 ! root 154: #define binsheadfree(bp, dp) do { \
! 155: TAILQ_INSERT_HEAD(dp, bp, b_freelist); \
! 156: (bp)->b_timestamp = time.tv_sec; \
! 157: } while (0)
! 158:
! 159: #define binstailfree(bp, dp) do { \
! 160: TAILQ_INSERT_TAIL(dp, bp, b_freelist); \
! 161: (bp)->b_timestamp = time.tv_sec; \
! 162: } while (0)
! 163:
! 164:
! 165: /* Time in seconds before a buf on a list is considered as a stale buf */
! 166: #define LRU_IS_STALE 120 /* default value for the LRU */
! 167: #define AGE_IS_STALE 60 /* default value for the AGE */
! 168:
! 169: int lru_is_stale = LRU_IS_STALE;
! 170: int age_is_stale = AGE_IS_STALE;
! 171:
! 172:
1.1 root 173:
174: void
175: bremfree(bp)
176: struct buf *bp;
177: {
178: struct bqueues *dp = NULL;
179:
180: /*
181: * We only calculate the head of the freelist when removing
182: * the last element of the list as that is the only time that
183: * it is needed (e.g. to reset the tail pointer).
184: *
185: * NB: This makes an assumption about how tailq's are implemented.
186: */
187: if (bp->b_freelist.tqe_next == NULL) {
188: for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
189: if (dp->tqh_last == &bp->b_freelist.tqe_next)
190: break;
191: if (dp == &bufqueues[BQUEUES])
192: panic("bremfree: lost tail");
193: }
194: TAILQ_REMOVE(dp, bp, b_freelist);
1.1.1.2 ! root 195: bp->b_timestamp = 0;
1.1 root 196: }
197:
198: /*
199: * Initialize buffers and hash links for buffers.
200: */
201: void
202: bufinit()
203: {
204: register struct buf *bp;
205: struct bqueues *dp;
206: register int i;
207: int base, residual;
208:
209: for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
210: TAILQ_INIT(dp);
211: bufhashtbl = hashinit(nbuf, M_CACHE, &bufhash);
212: base = bufpages / nbuf;
213: residual = bufpages % nbuf;
214: for (i = 0; i < nbuf; i++) {
215: bp = &buf[i];
216: bzero((char *)bp, sizeof *bp);
217: bp->b_dev = NODEV;
218: bp->b_rcred = NOCRED;
219: bp->b_wcred = NOCRED;
220: bp->b_vnbufs.le_next = NOLIST;
221: bp->b_data = buffers + i * MAXBSIZE;
222: if (i < residual)
223: bp->b_bufsize = (base + 1) * CLBYTES;
224: else
225: bp->b_bufsize = base * CLBYTES;
226: bp->b_flags = B_INVAL;
227: dp = bp->b_bufsize ? &bufqueues[BQ_AGE] : &bufqueues[BQ_EMPTY];
228: binsheadfree(bp, dp);
229: binshash(bp, &invalhash);
230: }
231: base = (int )(buffers + (i * MAXBSIZE));
232:
233: for (; i < nbuf + niobuf; i++) {
234: bp = &buf[i];
235: bzero((char *)bp, sizeof *bp);
236: bp->b_dev = NODEV;
237: bp->b_rcred = NOCRED;
238: bp->b_wcred = NOCRED;
239: bp->b_vnbufs.le_next = NOLIST;
240: bp->b_data = (char *)base;
241: bp->b_bufsize = 0;
242: bp->b_flags = B_INVAL;
243: binsheadfree(bp, &iobufqueue);
244:
245: base += MAXPHYSIO;
246: }
247: }
248:
249: __inline struct buf *
250: bio_doread(vp, blkno, size, cred, async)
251: struct vnode *vp;
252: daddr_t blkno;
253: int size;
254: struct ucred *cred;
255: int async;
256: {
257: register struct buf *bp;
258: struct proc *p = current_proc();
259:
260: bp = getblk(vp, blkno, size, 0, 0);
261:
262: /*
263: * If buffer does not have data valid, start a read.
264: * Note that if buffer is B_INVAL, getblk() won't return it.
265: * Therefore, it's valid if it's I/O has completed or been delayed.
266: */
267: if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) {
268: /* Start I/O for the buffer (keeping credentials). */
269: SET(bp->b_flags, B_READ | async);
270: if (cred != NOCRED && bp->b_rcred == NOCRED) {
271: crhold(cred);
272: bp->b_rcred = cred;
273: }
274: VOP_STRATEGY(bp);
275:
276: trace(TR_BREADMISS, pack(vp, size), blkno);
277:
278: /* Pay for the read. */
279: if (p && p->p_stats)
280: p->p_stats->p_ru.ru_inblock++; /* XXX */
281: } else if (async) {
282: brelse(bp);
283: }
284:
285: trace(TR_BREADHIT, pack(vp, size), blkno);
286:
287: return (bp);
288: }
289:
290: /*
291: * Read a disk block.
292: * This algorithm described in Bach (p.54).
293: */
294: int
295: bread(vp, blkno, size, cred, bpp)
296: struct vnode *vp;
297: daddr_t blkno;
298: int size;
299: struct ucred *cred;
300: struct buf **bpp;
301: {
302: register struct buf *bp;
303:
304: /* Get buffer for block. */
305: bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
306:
307: /* Wait for the read to complete, and return result. */
308: return (biowait(bp));
309: }
310:
311: /*
312: * Read-ahead multiple disk blocks. The first is sync, the rest async.
313: * Trivial modification to the breada algorithm presented in Bach (p.55).
314: */
315: int
316: breadn(vp, blkno, size, rablks, rasizes, nrablks, cred, bpp)
317: struct vnode *vp;
318: daddr_t blkno; int size;
319: daddr_t rablks[]; int rasizes[];
320: int nrablks;
321: struct ucred *cred;
322: struct buf **bpp;
323: {
324: register struct buf *bp;
325: int i;
326:
327: bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
328:
329: /*
330: * For each of the read-ahead blocks, start a read, if necessary.
331: */
332: for (i = 0; i < nrablks; i++) {
333: /* If it's in the cache, just go on to next one. */
334: if (incore(vp, rablks[i]))
335: continue;
336:
337: /* Get a buffer for the read-ahead block */
338: (void) bio_doread(vp, rablks[i], rasizes[i], cred, B_ASYNC);
339: }
340:
341: /* Otherwise, we had to start a read for it; wait until it's valid. */
342: return (biowait(bp));
343: }
344:
345: /*
346: * Read with single-block read-ahead. Defined in Bach (p.55), but
347: * implemented as a call to breadn().
348: * XXX for compatibility with old file systems.
349: */
350: int
351: breada(vp, blkno, size, rablkno, rabsize, cred, bpp)
352: struct vnode *vp;
353: daddr_t blkno; int size;
354: daddr_t rablkno; int rabsize;
355: struct ucred *cred;
356: struct buf **bpp;
357: {
358:
359: return (breadn(vp, blkno, size, &rablkno, &rabsize, 1, cred, bpp));
360: }
361:
362: /*
363: * Block write. Described in Bach (p.56)
364: */
365: int
366: bwrite(bp)
367: struct buf *bp;
368: {
369: int rv, sync, wasdelayed;
370: struct proc *p = current_proc();
371:
372: /* Remember buffer type, to switch on it later. */
373: sync = !ISSET(bp->b_flags, B_ASYNC);
374: wasdelayed = ISSET(bp->b_flags, B_DELWRI);
375: CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI));
376:
377: if (!sync) {
378: /*
379: * If not synchronous, pay for the I/O operation and make
380: * sure the buf is on the correct vnode queue. We have
381: * to do this now, because if we don't, the vnode may not
382: * be properly notified that its I/O has completed.
383: */
384: if (wasdelayed)
385: reassignbuf(bp, bp->b_vp);
386: else
387: if (p && p->p_stats)
388: p->p_stats->p_ru.ru_oublock++; /* XXX */
389: }
390:
391: trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno);
392:
393: /* Initiate disk write. Make sure the appropriate party is charged. */
394: SET(bp->b_flags, B_WRITEINPROG);
395: bp->b_vp->v_numoutput++;
396: VOP_STRATEGY(bp);
397:
398: if (sync) {
399: /*
400: * If I/O was synchronous, wait for it to complete.
401: */
402: rv = biowait(bp);
403:
404: /*
405: * Pay for the I/O operation, if it's not been paid for, and
406: * make sure it's on the correct vnode queue. (async operatings
407: * were payed for above.)
408: */
409: if (wasdelayed)
410: reassignbuf(bp, bp->b_vp);
411: else
412: if (p && p->p_stats)
413: p->p_stats->p_ru.ru_oublock++; /* XXX */
414:
415: /* Release the buffer. */
416: brelse(bp);
417:
418: return (rv);
419: } else {
420: return (0);
421: }
422: }
423:
424: int
425: vn_bwrite(ap)
426: struct vop_bwrite_args *ap;
427: {
428:
429: return (bwrite(ap->a_bp));
430: }
431:
432: /*
433: * Delayed write.
434: *
435: * The buffer is marked dirty, but is not queued for I/O.
436: * This routine should be used when the buffer is expected
437: * to be modified again soon, typically a small write that
438: * partially fills a buffer.
439: *
440: * NB: magnetic tapes cannot be delayed; they must be
441: * written in the order that the writes are requested.
442: *
443: * Described in Leffler, et al. (pp. 208-213).
444: */
445: void
446: bdwrite(bp)
447: struct buf *bp;
448: {
449: struct proc *p = current_proc();
450:
451: /*
452: * If the block hasn't been seen before:
453: * (1) Mark it as having been seen,
454: * (2) Charge for the write.
455: * (3) Make sure it's on its vnode's correct block list,
456: */
457: if (!ISSET(bp->b_flags, B_DELWRI)) {
458: SET(bp->b_flags, B_DELWRI);
459: if (p && p->p_stats)
460: p->p_stats->p_ru.ru_oublock++; /* XXX */
461: reassignbuf(bp, bp->b_vp);
462: }
463:
464: /* If this is a tape block, write it the block now. */
465: if (ISSET(bp->b_flags, B_TAPE)) {
466: bwrite(bp);
467: return;
468: }
469:
470: /* Otherwise, the "write" is done, so mark and release the buffer. */
471: SET(bp->b_flags, B_DONE);
472: brelse(bp);
473: }
474:
475: /*
476: * Asynchronous block write; just an asynchronous bwrite().
477: */
478: void
479: bawrite(bp)
480: struct buf *bp;
481: {
482:
483: SET(bp->b_flags, B_ASYNC);
484: VOP_BWRITE(bp);
485: }
486:
487: /*
488: * Release a buffer on to the free lists.
489: * Described in Bach (p. 46).
490: */
491: void
492: brelse(bp)
493: struct buf *bp;
494: {
495: struct bqueues *bufq;
496: int s;
497:
498: trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
499:
500: /* Wake up any processes waiting for any buffer to become free. */
501: if (needbuffer) {
502: needbuffer = 0;
503: wakeup(&needbuffer);
504: }
505:
506: /* Wake up any proceeses waiting for _this_ buffer to become free. */
507: if (ISSET(bp->b_flags, B_WANTED)) {
508: CLR(bp->b_flags, B_WANTED);
509: wakeup(bp);
510: }
511:
512: /* Block disk interrupts. */
513: s = splbio();
514:
515: /*
516: * Determine which queue the buffer should be on, then put it there.
517: */
518:
519: /* If it's locked, don't report an error; try again later. */
520: if (ISSET(bp->b_flags, (B_LOCKED|B_ERROR)) == (B_LOCKED|B_ERROR))
521: CLR(bp->b_flags, B_ERROR);
522:
523: /* If it's not cacheable, or an error, mark it invalid. */
524: if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR)))
525: SET(bp->b_flags, B_INVAL);
526:
527: if ((bp->b_bufsize <= 0) || ISSET(bp->b_flags, B_INVAL)) {
528: /*
529: * If it's invalid or empty, dissociate it from its vnode
530: * and put on the head of the appropriate queue.
531: */
532: if (bp->b_vp)
533: brelvp(bp);
534: CLR(bp->b_flags, B_DELWRI);
535: if (bp->b_bufsize <= 0)
536: /* no data */
537: bufq = &bufqueues[BQ_EMPTY];
538: else
539: /* invalid data */
540: bufq = &bufqueues[BQ_AGE];
541: binsheadfree(bp, bufq);
542: } else {
543: /*
544: * It has valid data. Put it on the end of the appropriate
545: * queue, so that it'll stick around for as long as possible.
546: */
547: if (ISSET(bp->b_flags, B_LOCKED))
548: /* locked in core */
549: bufq = &bufqueues[BQ_LOCKED];
550: else if (ISSET(bp->b_flags, B_AGE))
551: /* stale but valid data */
552: bufq = &bufqueues[BQ_AGE];
553: else
554: /* valid data */
555: bufq = &bufqueues[BQ_LRU];
556: binstailfree(bp, bufq);
557: }
558:
559: /* Unlock the buffer. */
560: CLR(bp->b_flags, (B_AGE | B_ASYNC | B_BUSY | B_NOCACHE));
561:
562: /* Allow disk interrupts. */
563: splx(s);
564: }
565:
566: /*
567: * Determine if a block is in the cache.
568: * Just look on what would be its hash chain. If it's there, return
569: * a pointer to it, unless it's marked invalid. If it's marked invalid,
570: * we normally don't return the buffer, unless the caller explicitly
571: * wants us to.
572: */
573: struct buf *
574: incore(vp, blkno)
575: struct vnode *vp;
576: daddr_t blkno;
577: {
578: struct buf *bp;
579:
580: bp = BUFHASH(vp, blkno)->lh_first;
581:
582: /* Search hash chain */
583: for (; bp != NULL; bp = bp->b_hash.le_next) {
584: if (bp->b_lblkno == blkno && bp->b_vp == vp &&
585: !ISSET(bp->b_flags, B_INVAL))
586: return (bp);
587: }
588:
589: return (0);
590: }
591:
592: /*
593: * Get a block of requested size that is associated with
594: * a given vnode and block offset. If it is found in the
595: * block cache, mark it as having been found, make it busy
596: * and return it. Otherwise, return an empty block of the
597: * correct size. It is up to the caller to insure that the
598: * cached blocks be of the correct size.
599: */
600: struct buf *
601: getblk(vp, blkno, size, slpflag, slptimeo)
602: register struct vnode *vp;
603: daddr_t blkno;
604: int size, slpflag, slptimeo;
605: {
606: struct buf *bp;
607: int s, err;
608:
609: start:
610: s = splbio();
611: if (bp = incore(vp, blkno)) { /* XXX NFS VOP_BWRITE foolishness */
612: if (ISSET(bp->b_flags, B_BUSY)) {
613: SET(bp->b_flags, B_WANTED);
614: err = tsleep(bp, slpflag | (PRIBIO + 1), "getblk",
615: slptimeo);
616: splx(s);
617: if (err)
618: return (NULL);
619: goto start;
620: }
621: SET(bp->b_flags, (B_BUSY | B_CACHE));
622: bremfree(bp);
623: splx(s);
624: allocbuf(bp, size);
625: } else {
626: splx(s);
627: if ((bp = getnewbuf(slpflag, slptimeo)) == NULL)
628: goto start;
629: binshash(bp, BUFHASH(vp, blkno));
630: allocbuf(bp, size);
631: bp->b_blkno = bp->b_lblkno = blkno;
632: s = splbio();
633: bgetvp(vp, bp);
634: splx(s);
635: }
636: return (bp);
637: }
638:
639: /*
640: * Get an empty, disassociated buffer of given size.
641: */
642: struct buf *
643: geteblk(size)
644: int size;
645: {
646: struct buf *bp;
647:
648: while ((bp = getnewbuf(0, 0)) == 0)
649: ;
650: SET(bp->b_flags, B_INVAL);
651: binshash(bp, &invalhash);
652: allocbuf(bp, size);
653:
654: return (bp);
655: }
656:
657: /*
658: * Expand or contract the actual memory allocated to a buffer.
659: *
660: * If the buffer shrinks, data is lost, so it's up to the
661: * caller to have written it out *first*; this routine will not
662: * start a write. If the buffer grows, it's the callers
663: * responsibility to fill out the buffer's additional contents.
664: */
665: int
666: allocbuf(bp, size)
667: struct buf *bp;
668: int size;
669: {
670: struct buf *nbp;
671: vm_size_t desired_size;
672: int s;
673:
674: desired_size = roundup(size, CLBYTES);
675: if (desired_size > MAXBSIZE)
676: panic("allocbuf: buffer larger than MAXBSIZE requested");
677:
678: if (bp->b_bufsize == desired_size)
679: goto out;
680:
681: /*
682: * If the buffer is smaller than the desired size, we need to snarf
683: * it from other buffers. Get buffers (via getnewbuf()), and
684: * steal their pages.
685: */
686: while (bp->b_bufsize < desired_size) {
687: int amt;
688:
689: /* find a buffer */
690: while ((nbp = getnewbuf(0, 0)) == NULL)
691: ;
692: SET(nbp->b_flags, B_INVAL);
693: binshash(nbp, &invalhash);
694:
695: /* and steal its pages, up to the amount we need */
696: amt = min(nbp->b_bufsize, (desired_size - bp->b_bufsize));
697: pagemove((nbp->b_data + nbp->b_bufsize - amt),
698: bp->b_data + bp->b_bufsize, amt);
699: bp->b_bufsize += amt;
700: nbp->b_bufsize -= amt;
701:
702: /* reduce transfer count if we stole some data */
703: if (nbp->b_bcount > nbp->b_bufsize)
704: nbp->b_bcount = nbp->b_bufsize;
705:
706: #if DIAGNOSTIC
707: if (nbp->b_bufsize < 0)
708: panic("allocbuf: negative bufsize");
709: #endif
710:
711: brelse(nbp);
712: }
713:
714: /*
715: * If we want a buffer smaller than the current size,
716: * shrink this buffer. Grab a buf head from the EMPTY queue,
717: * move a page onto it, and put it on front of the AGE queue.
718: * If there are no free buffer headers, leave the buffer alone.
719: */
720: if (bp->b_bufsize > desired_size) {
721: s = splbio();
722: if ((nbp = bufqueues[BQ_EMPTY].tqh_first) == NULL) {
723: /* No free buffer head */
724: splx(s);
725: goto out;
726: }
727: bremfree(nbp);
728: SET(nbp->b_flags, B_BUSY);
729: splx(s);
730:
731: /* move the page to it and note this change */
732: pagemove(bp->b_data + desired_size,
733: nbp->b_data, bp->b_bufsize - desired_size);
734: nbp->b_bufsize = bp->b_bufsize - desired_size;
735: bp->b_bufsize = desired_size;
736: nbp->b_bcount = 0;
737: SET(nbp->b_flags, B_INVAL);
738:
739: /* release the newly-filled buffer and leave */
740: brelse(nbp);
741: }
742:
743: out:
744: bp->b_bcount = size;
745: }
746:
747: /*
748: * Find a buffer which is available for use.
749: * Select something from a free list.
750: * Preference is to AGE list, then LRU list.
751: */
752: struct buf *
753: getnewbuf(slpflag, slptimeo)
754: int slpflag, slptimeo;
755: {
756: register struct buf *bp;
1.1.1.2 ! root 757: register struct buf *lru_bp;
! 758: register struct buf *age_bp;
! 759: register int age_time, lru_time;
1.1 root 760: int s;
761: struct ucred *cred;
762:
763: start:
764: s = splbio();
1.1.1.2 ! root 765:
! 766: age_bp = bufqueues[BQ_AGE].tqh_first;
! 767: lru_bp = bufqueues[BQ_LRU].tqh_first;
! 768:
! 769: if (age_bp == NULL && lru_bp == NULL) {
1.1 root 770: /* wait for a free buffer of any kind */
771: needbuffer = 1;
772: tsleep(&needbuffer, slpflag|(PRIBIO+1), "getnewbuf", slptimeo);
773: splx(s);
774: return (0);
775: }
1.1.1.2 ! root 776: if (age_bp == NULL)
! 777: bp = lru_bp;
! 778: else if (lru_bp == NULL)
! 779: bp = age_bp;
! 780: else {
! 781: if (((age_time = (time.tv_sec - age_bp->b_timestamp)) < 0) ||
! 782: ((lru_time = (time.tv_sec - lru_bp->b_timestamp)) < 0)) {
! 783: /* time was set backwards */
! 784: bp = age_bp;
! 785: /*
! 786: * we should probably re-timestamp eveything in the queues
! 787: * at this point with the current time
! 788: */
! 789: } else {
! 790: if (lru_time >= lru_is_stale && age_time < age_is_stale)
! 791: bp = lru_bp;
! 792: else
! 793: bp = age_bp;
! 794: }
! 795: }
! 796: bremfree(bp);
1.1 root 797:
798: /* Buffer is no longer on free lists. */
799: SET(bp->b_flags, B_BUSY);
800: splx(s);
801:
802: /* If buffer was a delayed write, start it, and go back to the top. */
803: if (ISSET(bp->b_flags, B_DELWRI)) {
804: bawrite (bp);
805: goto start;
806: }
807:
808: trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
809:
810: /* disassociate us from our vnode, if we had one... */
811: s = splbio();
812: if (bp->b_vp)
813: brelvp(bp);
814: splx(s);
815:
816: /* clear out various other fields */
817: bp->b_flags = B_BUSY;
818: bp->b_dev = NODEV;
819: bp->b_blkno = bp->b_lblkno = 0;
820: bp->b_iodone = 0;
821: bp->b_error = 0;
822: bp->b_resid = 0;
823: bp->b_bcount = 0;
824: bp->b_dirtyoff = bp->b_dirtyend = 0;
825: bp->b_validoff = bp->b_validend = 0;
826:
827: /* nuke any credentials we were holding */
828: cred = bp->b_rcred;
829: if (cred != NOCRED) {
830: bp->b_rcred = NOCRED;
831: crfree(cred);
832: }
833: cred = bp->b_wcred;
834: if (cred != NOCRED) {
835: bp->b_wcred = NOCRED;
836: crfree(cred);
837: }
838:
839: bremhash(bp);
840: return (bp);
841: }
842:
843: /*
844: * Wait for operations on the buffer to complete.
845: * When they do, extract and return the I/O's error value.
846: */
847: int
848: biowait(bp)
849: struct buf *bp;
850: {
851: int s;
852:
853: s = splbio();
854: while (!ISSET(bp->b_flags, B_DONE))
855: tsleep(bp, PRIBIO + 1, "biowait", 0);
856: splx(s);
857:
858: /* check for interruption of I/O (e.g. via NFS), then errors. */
859: if (ISSET(bp->b_flags, B_EINTR)) {
860: CLR(bp->b_flags, B_EINTR);
861: return (EINTR);
862: } else if (ISSET(bp->b_flags, B_ERROR))
863: return (bp->b_error ? bp->b_error : EIO);
864: else
865: return (0);
866: }
867:
868: /*
869: * Mark I/O complete on a buffer.
870: *
871: * If a callback has been requested, e.g. the pageout
872: * daemon, do so. Otherwise, awaken waiting processes.
873: *
874: * [ Leffler, et al., says on p.247:
875: * "This routine wakes up the blocked process, frees the buffer
876: * for an asynchronous write, or, for a request by the pagedaemon
877: * process, invokes a procedure specified in the buffer structure" ]
878: *
879: * In real life, the pagedaemon (or other system processes) wants
880: * to do async stuff to, and doesn't want the buffer brelse()'d.
881: * (for swap pager, that puts swap buffers on the free lists (!!!),
882: * for the vn device, that puts malloc'd buffers on the free lists!)
883: */
884: void
885: biodone(bp)
886: struct buf *bp;
887: {
888: if (ISSET(bp->b_flags, B_DONE))
889: panic("biodone already");
890: SET(bp->b_flags, B_DONE); /* note that it's done */
891:
892: if (!ISSET(bp->b_flags, B_READ) && !ISSET(bp->b_flags, B_RAW)) /* wake up reader */
893: vwakeup(bp);
894:
895: if (ISSET(bp->b_flags, B_CALL)) { /* if necessary, call out */
896: CLR(bp->b_flags, B_CALL); /* but note callout done */
897: (*bp->b_iodone)(bp);
898: } else if (ISSET(bp->b_flags, B_ASYNC)) /* if async, release it */
899: brelse(bp);
900: else { /* or just wakeup the buffer */
901: CLR(bp->b_flags, B_WANTED);
902: wakeup(bp);
903: }
904: }
905:
906: /*
907: * Return a count of buffers on the "locked" queue.
908: */
909: int
910: count_lock_queue()
911: {
912: register struct buf *bp;
913: register int n = 0;
914:
915: for (bp = bufqueues[BQ_LOCKED].tqh_first; bp;
916: bp = bp->b_freelist.tqe_next)
917: n++;
918: return (n);
919: }
920:
921: #if MACH_NBC
922: #include <ufs/ufs/quota.h>
923: #include <ufs/ufs/inode.h>
924:
925: #define btodevblk(b) ((b) / devBlocksize)
926: void
927: blkflush(struct vnode *vp, daddr_t blkno, vm_size_t size)
928: {
929: register struct buf *ep, *nbp;
930: daddr_t start, last;
931: int s,err;
932: struct inode *ip= VTOI(vp);
933: int devBlocksize=1024;
934:
935: #if 1
936: VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlocksize);
937: #endif
938:
939:
940: start = blkno;
941: last = start + btodb(size, devBlocksize) - 1;
942: loop:
943: for(ep = vp->v_dirtyblkhd.lh_first; ep; ep = nbp) {
944: nbp = ep->b_vnbufs.le_next;
945: if (ep->b_vp != vp || ISSET(ep->b_flags, B_INVAL))
946: continue;
947: /* look for overlap */
948: if (ep->b_bcount == 0 || ep->b_blkno > last ||
949: ep->b_blkno + btodevblk(ep->b_bcount) <= start)
950: continue;
951: s = splbio();
952: if (ISSET(ep->b_flags, B_BUSY)) {
953: SET(ep->b_flags, B_WANTED);
954: err = tsleep(ep, (PRIBIO + 1), "blkflush",
955: 0);
956: splx(s);
957: goto loop;
958: }
959: if(ISSET(ep->b_flags, B_DELWRI)) {
960: bremfree(ep);
961: SET(ep->b_flags, B_BUSY);
962: (void) splx(s);
963: bwrite(ep);
964: goto loop;
965: }
966: (void) splx(s);
967: }
968:
969: }
970: #endif /* MACH_NBC */
971: #if DIAGNOSTIC
972: /*
973: * Print out statistics on the current allocation of the buffer pool.
974: * Can be enabled to print out on every ``sync'' by setting "syncprt"
975: * in vfs_syscalls.c using sysctl.
976: */
977: void
978: vfs_bufstats()
979: {
980: int s, i, j, count;
981: register struct buf *bp;
982: register struct bqueues *dp;
983: int counts[MAXBSIZE/CLBYTES+1];
984: static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
985:
986: for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) {
987: count = 0;
988: for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
989: counts[j] = 0;
990: s = splbio();
991: for (bp = dp->tqh_first; bp; bp = bp->b_freelist.tqe_next) {
992: counts[bp->b_bufsize/CLBYTES]++;
993: count++;
994: }
995: splx(s);
996: printf("%s: total-%d", bname[i], count);
997: for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
998: if (counts[j] != 0)
999: printf(", %d-%d", j * CLBYTES, counts[j]);
1000: printf("\n");
1001: }
1002: }
1003: #endif /* DIAGNOSTIC */
1004:
1005:
1006: struct buf *
1007: alloc_io_buf(vp)
1008: struct vnode *vp;
1009: { register struct buf *bp;
1010: int s;
1011:
1012: s = splbio();
1013:
1014: if ((bp = iobufqueue.tqh_first) == NULL) {
1015: splx(s);
1016: return (NULL);
1017: }
1018: TAILQ_REMOVE(&iobufqueue, bp, b_freelist);
1.1.1.2 ! root 1019: bp->b_timestamp = 0;
1.1 root 1020:
1021: /* clear out various fields */
1022: bp->b_flags = (B_BUSY | B_RAW);
1023: bp->b_blkno = bp->b_lblkno = 0;
1024: bp->b_iodone = 0;
1025: bp->b_error = 0;
1026: bp->b_resid = 0;
1027: bp->b_bcount = 0;
1028: bp->b_bufsize = 0;
1029: bp->b_vp = vp;
1030:
1031: if (vp->v_type == VBLK || vp->v_type == VCHR)
1032: bp->b_dev = vp->v_rdev;
1033: else
1034: bp->b_dev = NODEV;
1035: splx(s);
1036:
1037: return (bp);
1038: }
1039:
1040: void
1041: free_io_buf(bp)
1042: struct buf *bp;
1043: {
1044: int s;
1045:
1046: s = splbio();
1047: /*
1048: * put buffer back on the head of the iobufqueue
1049: */
1050: bp->b_vp = NULL;
1051: bp->b_flags = B_INVAL;
1052:
1053: binsheadfree(bp, &iobufqueue);
1054:
1055: splx(s);
1056: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.