xref: /original-bsd/sys/kern/vfs_bio.c (revision 0997b878)
1 /*-
2  * Copyright (c) 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Berkeley Software Design Inc.
12  *
13  * %sccs.include.redist.c%
14  *
15  *	@(#)vfs_bio.c	8.11 (Berkeley) 01/09/95
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/proc.h>
21 #include <sys/buf.h>
22 #include <sys/vnode.h>
23 #include <sys/mount.h>
24 #include <sys/trace.h>
25 #include <sys/malloc.h>
26 #include <sys/resourcevar.h>
27 
28 /*
29  * Definitions for the buffer hash lists.
30  */
31 #define	BUFHASH(dvp, lbn)	\
32 	(&bufhashtbl[((int)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
33 LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash;
34 u_long	bufhash;
35 
36 /*
37  * Insq/Remq for the buffer hash lists.
38  */
39 #define	binshash(bp, dp)	LIST_INSERT_HEAD(dp, bp, b_hash)
40 #define	bremhash(bp)		LIST_REMOVE(bp, b_hash)
41 
42 /*
43  * Definitions for the buffer free lists.
44  */
45 #define	BQUEUES		4		/* number of free buffer queues */
46 
47 #define	BQ_LOCKED	0		/* super-blocks &c */
48 #define	BQ_LRU		1		/* lru, useful buffers */
49 #define	BQ_AGE		2		/* rubbish */
50 #define	BQ_EMPTY	3		/* buffer headers with no memory */
51 
52 TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
53 int needbuffer;
54 
55 /*
56  * Insq/Remq for the buffer free lists.
57  */
58 #define	binsheadfree(bp, dp)	TAILQ_INSERT_HEAD(dp, bp, b_freelist)
59 #define	binstailfree(bp, dp)	TAILQ_INSERT_TAIL(dp, bp, b_freelist)
60 
61 void
62 bremfree(bp)
63 	struct buf *bp;
64 {
65 	struct bqueues *dp = NULL;
66 
67 	/*
68 	 * We only calculate the head of the freelist when removing
69 	 * the last element of the list as that is the only time that
70 	 * it is needed (e.g. to reset the tail pointer).
71 	 *
72 	 * NB: This makes an assumption about how tailq's are implemented.
73 	 */
74 	if (bp->b_freelist.tqe_next == NULL) {
75 		for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
76 			if (dp->tqh_last == &bp->b_freelist.tqe_next)
77 				break;
78 		if (dp == &bufqueues[BQUEUES])
79 			panic("bremfree: lost tail");
80 	}
81 	TAILQ_REMOVE(dp, bp, b_freelist);
82 }
83 
84 /*
85  * Initialize buffers and hash links for buffers.
86  */
87 void
88 bufinit()
89 {
90 	register struct buf *bp;
91 	struct bqueues *dp;
92 	register int i;
93 	int base, residual;
94 
95 	for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
96 		TAILQ_INIT(dp);
97 	bufhashtbl = hashinit(nbuf, M_CACHE, &bufhash);
98 	base = bufpages / nbuf;
99 	residual = bufpages % nbuf;
100 	for (i = 0; i < nbuf; i++) {
101 		bp = &buf[i];
102 		bzero((char *)bp, sizeof *bp);
103 		bp->b_dev = NODEV;
104 		bp->b_rcred = NOCRED;
105 		bp->b_wcred = NOCRED;
106 		bp->b_vnbufs.le_next = NOLIST;
107 		bp->b_data = buffers + i * MAXBSIZE;
108 		if (i < residual)
109 			bp->b_bufsize = (base + 1) * CLBYTES;
110 		else
111 			bp->b_bufsize = base * CLBYTES;
112 		bp->b_flags = B_INVAL;
113 		dp = bp->b_bufsize ? &bufqueues[BQ_AGE] : &bufqueues[BQ_EMPTY];
114 		binsheadfree(bp, dp);
115 		binshash(bp, &invalhash);
116 	}
117 }
118 
119 /*
120  * Find the block in the buffer pool.
121  * If the buffer is not present, allocate a new buffer and load
122  * its contents according to the filesystem fill routine.
123  */
124 bread(vp, blkno, size, cred, bpp)
125 	struct vnode *vp;
126 	daddr_t blkno;
127 	int size;
128 	struct ucred *cred;
129 	struct buf **bpp;
130 {
131 	struct proc *p = curproc;		/* XXX */
132 	register struct buf *bp;
133 
134 	if (size == 0)
135 		panic("bread: size 0");
136 	*bpp = bp = getblk(vp, blkno, size, 0, 0);
137 	if (bp->b_flags & (B_DONE | B_DELWRI)) {
138 		trace(TR_BREADHIT, pack(vp, size), blkno);
139 		return (0);
140 	}
141 	bp->b_flags |= B_READ;
142 	if (bp->b_bcount > bp->b_bufsize)
143 		panic("bread");
144 	if (bp->b_rcred == NOCRED && cred != NOCRED) {
145 		crhold(cred);
146 		bp->b_rcred = cred;
147 	}
148 	VOP_STRATEGY(bp);
149 	trace(TR_BREADMISS, pack(vp, size), blkno);
150 	p->p_stats->p_ru.ru_inblock++;		/* pay for read */
151 	return (biowait(bp));
152 }
153 
154 /*
155  * Operates like bread, but also starts I/O on the N specified
156  * read-ahead blocks.
157  */
158 breadn(vp, blkno, size, rablkno, rabsize, num, cred, bpp)
159 	struct vnode *vp;
160 	daddr_t blkno; int size;
161 	daddr_t rablkno[]; int rabsize[];
162 	int num;
163 	struct ucred *cred;
164 	struct buf **bpp;
165 {
166 	struct proc *p = curproc;		/* XXX */
167 	register struct buf *bp, *rabp;
168 	register int i;
169 
170 	bp = NULL;
171 	/*
172 	 * If the block is not memory resident,
173 	 * allocate a buffer and start I/O.
174 	 */
175 	if (!incore(vp, blkno)) {
176 		*bpp = bp = getblk(vp, blkno, size, 0, 0);
177 		if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) {
178 			bp->b_flags |= B_READ;
179 			if (bp->b_bcount > bp->b_bufsize)
180 				panic("breadn");
181 			if (bp->b_rcred == NOCRED && cred != NOCRED) {
182 				crhold(cred);
183 				bp->b_rcred = cred;
184 			}
185 			VOP_STRATEGY(bp);
186 			trace(TR_BREADMISS, pack(vp, size), blkno);
187 			p->p_stats->p_ru.ru_inblock++;	/* pay for read */
188 		} else {
189 			trace(TR_BREADHIT, pack(vp, size), blkno);
190 		}
191 	}
192 
193 	/*
194 	 * If there's read-ahead block(s), start I/O
195 	 * on them also (as above).
196 	 */
197 	for (i = 0; i < num; i++) {
198 		if (incore(vp, rablkno[i]))
199 			continue;
200 		rabp = getblk(vp, rablkno[i], rabsize[i], 0, 0);
201 		if (rabp->b_flags & (B_DONE | B_DELWRI)) {
202 			brelse(rabp);
203 			trace(TR_BREADHITRA, pack(vp, rabsize[i]), rablkno[i]);
204 		} else {
205 			rabp->b_flags |= B_ASYNC | B_READ;
206 			if (rabp->b_bcount > rabp->b_bufsize)
207 				panic("breadrabp");
208 			if (rabp->b_rcred == NOCRED && cred != NOCRED) {
209 				crhold(cred);
210 				rabp->b_rcred = cred;
211 			}
212 			VOP_STRATEGY(rabp);
213 			trace(TR_BREADMISSRA, pack(vp, rabsize[i]), rablkno[i]);
214 			p->p_stats->p_ru.ru_inblock++;	/* pay in advance */
215 		}
216 	}
217 
218 	/*
219 	 * If block was memory resident, let bread get it.
220 	 * If block was not memory resident, the read was
221 	 * started above, so just wait for the read to complete.
222 	 */
223 	if (bp == NULL)
224 		return (bread(vp, blkno, size, cred, bpp));
225 	return (biowait(bp));
226 }
227 
228 /*
229  * Synchronous write.
230  * Release buffer on completion.
231  */
232 bwrite(bp)
233 	register struct buf *bp;
234 {
235 	struct proc *p = curproc;		/* XXX */
236 	register int flag;
237 	int s, error = 0;
238 
239 	if ((bp->b_flags & B_ASYNC) == 0 &&
240 	    bp->b_vp && bp->b_vp->v_mount &&
241 	    (bp->b_vp->v_mount->mnt_flag & MNT_ASYNC)) {
242 		bdwrite(bp);
243 		return (0);
244 	}
245 	flag = bp->b_flags;
246 	bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
247 	if (flag & B_ASYNC) {
248 		if ((flag & B_DELWRI) == 0)
249 			p->p_stats->p_ru.ru_oublock++;	/* no one paid yet */
250 		else
251 			reassignbuf(bp, bp->b_vp);
252 	}
253 	trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno);
254 	if (bp->b_bcount > bp->b_bufsize)
255 		panic("bwrite");
256 	s = splbio();
257 	bp->b_vp->v_numoutput++;
258 	bp->b_flags |= B_WRITEINPROG;
259 	splx(s);
260 	VOP_STRATEGY(bp);
261 
262 	/*
263 	 * If the write was synchronous, then await I/O completion.
264 	 * If the write was "delayed", then we put the buffer on
265 	 * the queue of blocks awaiting I/O completion status.
266 	 */
267 	if ((flag & B_ASYNC) == 0) {
268 		error = biowait(bp);
269 		if ((flag&B_DELWRI) == 0)
270 			p->p_stats->p_ru.ru_oublock++;	/* no one paid yet */
271 		else
272 			reassignbuf(bp, bp->b_vp);
273 		if (bp->b_flags & B_EINTR) {
274 			bp->b_flags &= ~B_EINTR;
275 			error = EINTR;
276 		}
277 		brelse(bp);
278 	} else if (flag & B_DELWRI) {
279 		s = splbio();
280 		bp->b_flags |= B_AGE;
281 		splx(s);
282 	}
283 	return (error);
284 }
285 
286 int
287 vn_bwrite(ap)
288 	struct vop_bwrite_args *ap;
289 {
290 
291 	return (bwrite(ap->a_bp));
292 }
293 
294 
295 /*
296  * Delayed write.
297  *
298  * The buffer is marked dirty, but is not queued for I/O.
299  * This routine should be used when the buffer is expected
300  * to be modified again soon, typically a small write that
301  * partially fills a buffer.
302  *
303  * NB: magnetic tapes cannot be delayed; they must be
304  * written in the order that the writes are requested.
305  */
306 void
307 bdwrite(bp)
308 	register struct buf *bp;
309 {
310 	struct proc *p = curproc;		/* XXX */
311 
312 	if ((bp->b_flags & B_DELWRI) == 0) {
313 		bp->b_flags |= B_DELWRI;
314 		reassignbuf(bp, bp->b_vp);
315 		p->p_stats->p_ru.ru_oublock++;		/* no one paid yet */
316 	}
317 	/*
318 	 * If this is a tape drive, the write must be initiated.
319 	 */
320 	if (VOP_IOCTL(bp->b_vp, 0, (caddr_t)B_TAPE, 0, NOCRED, p) == 0) {
321 		bawrite(bp);
322 	} else {
323 		bp->b_flags |= (B_DONE | B_DELWRI);
324 		brelse(bp);
325 	}
326 }
327 
328 /*
329  * Asynchronous write.
330  * Start I/O on a buffer, but do not wait for it to complete.
331  * The buffer is released when the I/O completes.
332  */
333 void
334 bawrite(bp)
335 	register struct buf *bp;
336 {
337 
338 	/*
339 	 * Setting the ASYNC flag causes bwrite to return
340 	 * after starting the I/O.
341 	 */
342 	bp->b_flags |= B_ASYNC;
343 	(void) VOP_BWRITE(bp);
344 }
345 
346 /*
347  * Release a buffer.
348  * Even if the buffer is dirty, no I/O is started.
349  */
350 void
351 brelse(bp)
352 	register struct buf *bp;
353 {
354 	register struct bqueues *flist;
355 	int s;
356 
357 	trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
358 	/*
359 	 * If a process is waiting for the buffer, or
360 	 * is waiting for a free buffer, awaken it.
361 	 */
362 	if (bp->b_flags & B_WANTED)
363 		wakeup((caddr_t)bp);
364 	if (needbuffer) {
365 		needbuffer = 0;
366 		wakeup((caddr_t)&needbuffer);
367 	}
368 	/*
369 	 * Retry I/O for locked buffers rather than invalidating them.
370 	 */
371 	s = splbio();
372 	if ((bp->b_flags & B_ERROR) && (bp->b_flags & B_LOCKED))
373 		bp->b_flags &= ~B_ERROR;
374 	/*
375 	 * Disassociate buffers that are no longer valid.
376 	 */
377 	if (bp->b_flags & (B_NOCACHE | B_ERROR))
378 		bp->b_flags |= B_INVAL;
379 	if ((bp->b_bufsize <= 0) || (bp->b_flags & (B_ERROR | B_INVAL))) {
380 		if (bp->b_vp)
381 			brelvp(bp);
382 		bp->b_flags &= ~B_DELWRI;
383 	}
384 	/*
385 	 * Stick the buffer back on a free list.
386 	 */
387 	if (bp->b_bufsize <= 0) {
388 		/* block has no buffer ... put at front of unused buffer list */
389 		flist = &bufqueues[BQ_EMPTY];
390 		binsheadfree(bp, flist);
391 	} else if (bp->b_flags & (B_ERROR | B_INVAL)) {
392 		/* block has no info ... put at front of most free list */
393 		flist = &bufqueues[BQ_AGE];
394 		binsheadfree(bp, flist);
395 	} else {
396 		if (bp->b_flags & B_LOCKED)
397 			flist = &bufqueues[BQ_LOCKED];
398 		else if (bp->b_flags & B_AGE)
399 			flist = &bufqueues[BQ_AGE];
400 		else
401 			flist = &bufqueues[BQ_LRU];
402 		binstailfree(bp, flist);
403 	}
404 	bp->b_flags &= ~(B_WANTED | B_BUSY | B_ASYNC | B_AGE | B_NOCACHE);
405 	splx(s);
406 }
407 
408 /*
409  * Check to see if a block is currently memory resident.
410  */
411 struct buf *
412 incore(vp, blkno)
413 	struct vnode *vp;
414 	daddr_t blkno;
415 {
416 	register struct buf *bp;
417 
418 	for (bp = BUFHASH(vp, blkno)->lh_first; bp; bp = bp->b_hash.le_next)
419 		if (bp->b_lblkno == blkno && bp->b_vp == vp &&
420 		    (bp->b_flags & B_INVAL) == 0)
421 			return (bp);
422 	return (NULL);
423 }
424 
425 /*
426  * Check to see if a block is currently memory resident.
427  * If it is resident, return it. If it is not resident,
428  * allocate a new buffer and assign it to the block.
429  */
430 struct buf *
431 getblk(vp, blkno, size, slpflag, slptimeo)
432 	register struct vnode *vp;
433 	daddr_t blkno;
434 	int size, slpflag, slptimeo;
435 {
436 	register struct buf *bp;
437 	struct bufhashhdr *dp;
438 	int s, error;
439 
440 	if (size > MAXBSIZE)
441 		panic("getblk: size too big");
442 	/*
443 	 * Search the cache for the block. If the buffer is found,
444 	 * but it is currently locked, the we must wait for it to
445 	 * become available.
446 	 */
447 	dp = BUFHASH(vp, blkno);
448 loop:
449 	for (bp = dp->lh_first; bp; bp = bp->b_hash.le_next) {
450 		if (bp->b_lblkno != blkno || bp->b_vp != vp)
451 			continue;
452 		s = splbio();
453 		if (bp->b_flags & B_BUSY) {
454 			bp->b_flags |= B_WANTED;
455 			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
456 				"getblk", slptimeo);
457 			splx(s);
458 			if (error)
459 				return (NULL);
460 			goto loop;
461 		}
462 		/*
463 		 * The test for B_INVAL is moved down here, since there
464 		 * are cases where B_INVAL is set before VOP_BWRITE() is
465 		 * called and for NFS, the process cannot be allowed to
466 		 * allocate a new buffer for the same block until the write
467 		 * back to the server has been completed. (ie. B_BUSY clears)
468 		 */
469 		if (bp->b_flags & B_INVAL) {
470 			splx(s);
471 			continue;
472 		}
473 		bremfree(bp);
474 		bp->b_flags |= B_BUSY;
475 		splx(s);
476 		if (bp->b_bcount != size) {
477 			printf("getblk: stray size\n");
478 			bp->b_flags |= B_INVAL;
479 			VOP_BWRITE(bp);
480 			goto loop;
481 		}
482 		bp->b_flags |= B_CACHE;
483 		return (bp);
484 	}
485 	/*
486 	 * The loop back to the top when getnewbuf() fails is because
487 	 * stateless filesystems like NFS have no node locks. Thus,
488 	 * there is a slight chance that more than one process will
489 	 * try and getnewbuf() for the same block concurrently when
490 	 * the first sleeps in getnewbuf(). So after a sleep, go back
491 	 * up to the top to check the hash lists again.
492 	 */
493 	if ((bp = getnewbuf(slpflag, slptimeo)) == 0)
494 		goto loop;
495 	bremhash(bp);
496 	bgetvp(vp, bp);
497 	bp->b_bcount = 0;
498 	bp->b_lblkno = blkno;
499 	bp->b_blkno = blkno;
500 	bp->b_error = 0;
501 	bp->b_resid = 0;
502 	binshash(bp, dp);
503 	allocbuf(bp, size);
504 	return (bp);
505 }
506 
507 /*
508  * Allocate a buffer.
509  * The caller will assign it to a block.
510  */
511 struct buf *
512 geteblk(size)
513 	int size;
514 {
515 	register struct buf *bp;
516 
517 	if (size > MAXBSIZE)
518 		panic("geteblk: size too big");
519 	while ((bp = getnewbuf(0, 0)) == NULL)
520 		/* void */;
521 	bp->b_flags |= B_INVAL;
522 	bremhash(bp);
523 	binshash(bp, &invalhash);
524 	bp->b_bcount = 0;
525 	bp->b_error = 0;
526 	bp->b_resid = 0;
527 	allocbuf(bp, size);
528 	return (bp);
529 }
530 
531 /*
532  * Expand or contract the actual memory allocated to a buffer.
533  * If no memory is available, release buffer and take error exit.
534  */
535 allocbuf(tp, size)
536 	register struct buf *tp;
537 	int size;
538 {
539 	register struct buf *bp, *ep;
540 	int sizealloc, take, s;
541 
542 	sizealloc = roundup(size, CLBYTES);
543 	/*
544 	 * Buffer size does not change
545 	 */
546 	if (sizealloc == tp->b_bufsize)
547 		goto out;
548 	/*
549 	 * Buffer size is shrinking.
550 	 * Place excess space in a buffer header taken from the
551 	 * BQ_EMPTY buffer list and placed on the "most free" list.
552 	 * If no extra buffer headers are available, leave the
553 	 * extra space in the present buffer.
554 	 */
555 	if (sizealloc < tp->b_bufsize) {
556 		if ((ep = bufqueues[BQ_EMPTY].tqh_first) == NULL)
557 			goto out;
558 		s = splbio();
559 		bremfree(ep);
560 		ep->b_flags |= B_BUSY;
561 		splx(s);
562 		pagemove((char *)tp->b_data + sizealloc, ep->b_data,
563 		    (int)tp->b_bufsize - sizealloc);
564 		ep->b_bufsize = tp->b_bufsize - sizealloc;
565 		tp->b_bufsize = sizealloc;
566 		ep->b_flags |= B_INVAL;
567 		ep->b_bcount = 0;
568 		brelse(ep);
569 		goto out;
570 	}
571 	/*
572 	 * More buffer space is needed. Get it out of buffers on
573 	 * the "most free" list, placing the empty headers on the
574 	 * BQ_EMPTY buffer header list.
575 	 */
576 	while (tp->b_bufsize < sizealloc) {
577 		take = sizealloc - tp->b_bufsize;
578 		while ((bp = getnewbuf(0, 0)) == NULL)
579 			/* void */;
580 		if (take >= bp->b_bufsize)
581 			take = bp->b_bufsize;
582 		pagemove(&((char *)bp->b_data)[bp->b_bufsize - take],
583 		    &((char *)tp->b_data)[tp->b_bufsize], take);
584 		tp->b_bufsize += take;
585 		bp->b_bufsize = bp->b_bufsize - take;
586 		if (bp->b_bcount > bp->b_bufsize)
587 			bp->b_bcount = bp->b_bufsize;
588 		if (bp->b_bufsize <= 0) {
589 			bremhash(bp);
590 			binshash(bp, &invalhash);
591 			bp->b_dev = NODEV;
592 			bp->b_error = 0;
593 			bp->b_flags |= B_INVAL;
594 		}
595 		brelse(bp);
596 	}
597 out:
598 	tp->b_bcount = size;
599 	return (1);
600 }
601 
602 /*
603  * Find a buffer which is available for use.
604  * Select something from a free list.
605  * Preference is to AGE list, then LRU list.
606  */
607 struct buf *
608 getnewbuf(slpflag, slptimeo)
609 	int slpflag, slptimeo;
610 {
611 	register struct buf *bp;
612 	register struct bqueues *dp;
613 	register struct ucred *cred;
614 	int s;
615 
616 loop:
617 	s = splbio();
618 	for (dp = &bufqueues[BQ_AGE]; dp > bufqueues; dp--)
619 		if (dp->tqh_first)
620 			break;
621 	if (dp == bufqueues) {		/* no free blocks */
622 		needbuffer = 1;
623 		(void) tsleep((caddr_t)&needbuffer, slpflag | (PRIBIO + 1),
624 			"getnewbuf", slptimeo);
625 		splx(s);
626 		return (NULL);
627 	}
628 	bp = dp->tqh_first;
629 	bremfree(bp);
630 	bp->b_flags |= B_BUSY;
631 	splx(s);
632 	if (bp->b_flags & B_DELWRI) {
633 		(void) bawrite(bp);
634 		goto loop;
635 	}
636 	trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
637 	if (bp->b_vp)
638 		brelvp(bp);
639 	if (bp->b_rcred != NOCRED) {
640 		cred = bp->b_rcred;
641 		bp->b_rcred = NOCRED;
642 		crfree(cred);
643 	}
644 	if (bp->b_wcred != NOCRED) {
645 		cred = bp->b_wcred;
646 		bp->b_wcred = NOCRED;
647 		crfree(cred);
648 	}
649 	bp->b_flags = B_BUSY;
650 	bp->b_dirtyoff = bp->b_dirtyend = 0;
651 	bp->b_validoff = bp->b_validend = 0;
652 	return (bp);
653 }
654 
655 /*
656  * Wait for I/O to complete.
657  *
658  * Extract and return any errors associated with the I/O.
659  * If the error flag is set, but no specific error is
660  * given, return EIO.
661  */
662 biowait(bp)
663 	register struct buf *bp;
664 {
665 	int s;
666 
667 	s = splbio();
668 	while ((bp->b_flags & B_DONE) == 0)
669 		sleep((caddr_t)bp, PRIBIO);
670 	splx(s);
671 	if ((bp->b_flags & B_ERROR) == 0)
672 		return (0);
673 	if (bp->b_error)
674 		return (bp->b_error);
675 	return (EIO);
676 }
677 
678 /*
679  * Mark I/O complete on a buffer.
680  *
681  * If a callback has been requested, e.g. the pageout
682  * daemon, do so. Otherwise, awaken waiting processes.
683  */
684 void
685 biodone(bp)
686 	register struct buf *bp;
687 {
688 
689 	if (bp->b_flags & B_DONE)
690 		panic("dup biodone");
691 	bp->b_flags |= B_DONE;
692 	if ((bp->b_flags & B_READ) == 0)
693 		vwakeup(bp);
694 	if (bp->b_flags & B_CALL) {
695 		bp->b_flags &= ~B_CALL;
696 		(*bp->b_iodone)(bp);
697 		return;
698 	}
699 	if (bp->b_flags & B_ASYNC)
700 		brelse(bp);
701 	else {
702 		bp->b_flags &= ~B_WANTED;
703 		wakeup((caddr_t)bp);
704 	}
705 }
706 
707 int
708 count_lock_queue()
709 {
710 	register struct buf *bp;
711 	register int ret;
712 
713 	for (ret = 0, bp = (struct buf *)bufqueues[BQ_LOCKED].tqh_first;
714 	    bp; bp = (struct buf *)bp->b_freelist.tqe_next)
715 		++ret;
716 	return(ret);
717 }
718 
719 #ifdef DIAGNOSTIC
720 /*
721  * Print out statistics on the current allocation of the buffer pool.
722  * Can be enabled to print out on every ``sync'' by setting "syncprt"
723  * in vfs_syscalls.c using sysctl.
724  */
725 void
726 vfs_bufstats()
727 {
728 	int s, i, j, count;
729 	register struct buf *bp;
730 	register struct bqueues *dp;
731 	int counts[MAXBSIZE/CLBYTES+1];
732 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
733 
734 	for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) {
735 		count = 0;
736 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
737 			counts[j] = 0;
738 		s = splbio();
739 		for (bp = dp->tqh_first; bp; bp = bp->b_freelist.tqe_next) {
740 			counts[bp->b_bufsize/CLBYTES]++;
741 			count++;
742 		}
743 		splx(s);
744 		printf("%s: total-%d", bname[i], count);
745 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
746 			if (counts[j] != 0)
747 				printf(", %d-%d", j * CLBYTES, counts[j]);
748 		printf("\n");
749 	}
750 }
751 #endif /* DIAGNOSTIC */
752