xref: /csrg-svn/sys/kern/vfs_cluster.c (revision 32608)
123395Smckusick /*
229114Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323395Smckusick  * All rights reserved.  The Berkeley software License Agreement
423395Smckusick  * specifies the terms and conditions for redistribution.
523395Smckusick  *
6*32608Smckusick  *	@(#)vfs_cluster.c	7.3 (Berkeley) 11/12/87
723395Smckusick  */
88Sbill 
99763Ssam #include "../machine/pte.h"
109763Ssam 
1117098Sbloom #include "param.h"
1217098Sbloom #include "systm.h"
1317098Sbloom #include "dir.h"
1417098Sbloom #include "user.h"
1517098Sbloom #include "buf.h"
1617098Sbloom #include "conf.h"
1717098Sbloom #include "proc.h"
1817098Sbloom #include "seg.h"
1917098Sbloom #include "vm.h"
2017098Sbloom #include "trace.h"
218Sbill 
2291Sbill /*
238Sbill  * Read in (if necessary) the block and return a buffer pointer.
248Sbill  */
258Sbill struct buf *
266563Smckusic bread(dev, blkno, size)
276563Smckusic 	dev_t dev;
286563Smckusic 	daddr_t blkno;
296563Smckusic 	int size;
308Sbill {
318Sbill 	register struct buf *bp;
328Sbill 
338670S 	if (size == 0)
348670S 		panic("bread: size 0");
356563Smckusic 	bp = getblk(dev, blkno, size);
36*32608Smckusick 	if (bp->b_flags&(B_DONE|B_DELWRI)) {
3715795Ssam 		trace(TR_BREADHIT, pack(dev, size), blkno);
3826271Skarels 		return (bp);
398Sbill 	}
408Sbill 	bp->b_flags |= B_READ;
418670S 	if (bp->b_bcount > bp->b_bufsize)
428670S 		panic("bread");
438Sbill 	(*bdevsw[major(dev)].d_strategy)(bp);
4415795Ssam 	trace(TR_BREADMISS, pack(dev, size), blkno);
458039Sroot 	u.u_ru.ru_inblock++;		/* pay for read */
467015Smckusick 	biowait(bp);
4726271Skarels 	return (bp);
488Sbill }
498Sbill 
508Sbill /*
518Sbill  * Read in the block, like bread, but also start I/O on the
528Sbill  * read-ahead block (which is not allocated to the caller)
538Sbill  */
548Sbill struct buf *
558592Sroot breada(dev, blkno, size, rablkno, rabsize)
566563Smckusic 	dev_t dev;
577114Smckusick 	daddr_t blkno; int size;
588592Sroot 	daddr_t rablkno; int rabsize;
598Sbill {
608Sbill 	register struct buf *bp, *rabp;
618Sbill 
628Sbill 	bp = NULL;
637015Smckusick 	/*
647015Smckusick 	 * If the block isn't in core, then allocate
657015Smckusick 	 * a buffer and initiate i/o (getblk checks
667015Smckusick 	 * for a cache hit).
677015Smckusick 	 */
688Sbill 	if (!incore(dev, blkno)) {
696563Smckusic 		bp = getblk(dev, blkno, size);
70*32608Smckusick 		if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
718Sbill 			bp->b_flags |= B_READ;
728670S 			if (bp->b_bcount > bp->b_bufsize)
738670S 				panic("breada");
748Sbill 			(*bdevsw[major(dev)].d_strategy)(bp);
7515795Ssam 			trace(TR_BREADMISS, pack(dev, size), blkno);
768039Sroot 			u.u_ru.ru_inblock++;		/* pay for read */
777015Smckusick 		} else
7815795Ssam 			trace(TR_BREADHIT, pack(dev, size), blkno);
798Sbill 	}
807015Smckusick 
817015Smckusick 	/*
827015Smckusick 	 * If there's a read-ahead block, start i/o
837015Smckusick 	 * on it also (as above).
847015Smckusick 	 */
858Sbill 	if (rablkno && !incore(dev, rablkno)) {
868592Sroot 		rabp = getblk(dev, rablkno, rabsize);
87*32608Smckusick 		if (rabp->b_flags & (B_DONE|B_DELWRI)) {
888Sbill 			brelse(rabp);
8915795Ssam 			trace(TR_BREADHITRA, pack(dev, rabsize), blkno);
902045Swnj 		} else {
918Sbill 			rabp->b_flags |= B_READ|B_ASYNC;
928670S 			if (rabp->b_bcount > rabp->b_bufsize)
938670S 				panic("breadrabp");
948Sbill 			(*bdevsw[major(dev)].d_strategy)(rabp);
9515795Ssam 			trace(TR_BREADMISSRA, pack(dev, rabsize), rablock);
968039Sroot 			u.u_ru.ru_inblock++;		/* pay in advance */
978Sbill 		}
988Sbill 	}
997015Smckusick 
1007015Smckusick 	/*
1017114Smckusick 	 * If block was in core, let bread get it.
1027114Smckusick 	 * If block wasn't in core, then the read was started
1037114Smckusick 	 * above, and just wait for it.
1047015Smckusick 	 */
1057114Smckusick 	if (bp == NULL)
1067114Smckusick 		return (bread(dev, blkno, size));
1077015Smckusick 	biowait(bp);
1087114Smckusick 	return (bp);
1098Sbill }
1108Sbill 
1118Sbill /*
1128Sbill  * Write the buffer, waiting for completion.
1138Sbill  * Then release the buffer.
1148Sbill  */
1158Sbill bwrite(bp)
1167015Smckusick 	register struct buf *bp;
1178Sbill {
1188Sbill 	register flag;
1198Sbill 
1208Sbill 	flag = bp->b_flags;
1219857Ssam 	bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
1228Sbill 	if ((flag&B_DELWRI) == 0)
1238039Sroot 		u.u_ru.ru_oublock++;		/* noone paid yet */
12415795Ssam 	trace(TR_BWRITE, pack(bp->b_dev, bp->b_bcount), bp->b_blkno);
1258670S 	if (bp->b_bcount > bp->b_bufsize)
1268670S 		panic("bwrite");
1278Sbill 	(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
1287015Smckusick 
1297015Smckusick 	/*
1307015Smckusick 	 * If the write was synchronous, then await i/o completion.
1317015Smckusick 	 * If the write was "delayed", then we put the buffer on
1327015Smckusick 	 * the q of blocks awaiting i/o completion status.
1337015Smckusick 	 */
1348Sbill 	if ((flag&B_ASYNC) == 0) {
1357015Smckusick 		biowait(bp);
1368Sbill 		brelse(bp);
1378Sbill 	} else if (flag & B_DELWRI)
1388Sbill 		bp->b_flags |= B_AGE;
1398Sbill }
1408Sbill 
1418Sbill /*
1428Sbill  * Release the buffer, marking it so that if it is grabbed
1438Sbill  * for another purpose it will be written out before being
1448Sbill  * given up (e.g. when writing a partial block where it is
1458Sbill  * assumed that another write for the same block will soon follow).
1468Sbill  * This can't be done for magtape, since writes must be done
1478Sbill  * in the same order as requested.
1488Sbill  */
1498Sbill bdwrite(bp)
1507015Smckusick 	register struct buf *bp;
1518Sbill {
1528Sbill 
1538Sbill 	if ((bp->b_flags&B_DELWRI) == 0)
1548039Sroot 		u.u_ru.ru_oublock++;		/* noone paid yet */
15530749Skarels 	if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
1568Sbill 		bawrite(bp);
1578Sbill 	else {
1588Sbill 		bp->b_flags |= B_DELWRI | B_DONE;
1598Sbill 		brelse(bp);
1608Sbill 	}
1618Sbill }
1628Sbill 
1638Sbill /*
1648Sbill  * Release the buffer, start I/O on it, but don't wait for completion.
1658Sbill  */
1668Sbill bawrite(bp)
1677015Smckusick 	register struct buf *bp;
1688Sbill {
1698Sbill 
1708Sbill 	bp->b_flags |= B_ASYNC;
1718Sbill 	bwrite(bp);
1728Sbill }
1738Sbill 
1748Sbill /*
1757015Smckusick  * Release the buffer, with no I/O implied.
1768Sbill  */
1778Sbill brelse(bp)
1787015Smckusick 	register struct buf *bp;
1798Sbill {
1802325Swnj 	register struct buf *flist;
1818Sbill 	register s;
1828Sbill 
18315795Ssam 	trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
1847015Smckusick 	/*
1857015Smckusick 	 * If someone's waiting for the buffer, or
1867015Smckusick 	 * is waiting for a buffer wake 'em up.
1877015Smckusick 	 */
1888Sbill 	if (bp->b_flags&B_WANTED)
1898Sbill 		wakeup((caddr_t)bp);
1902325Swnj 	if (bfreelist[0].b_flags&B_WANTED) {
1912325Swnj 		bfreelist[0].b_flags &= ~B_WANTED;
1922325Swnj 		wakeup((caddr_t)bfreelist);
1938Sbill 	}
1942683Swnj 	if (bp->b_flags&B_ERROR)
1952683Swnj 		if (bp->b_flags & B_LOCKED)
1962683Swnj 			bp->b_flags &= ~B_ERROR;	/* try again later */
1972683Swnj 		else
1982683Swnj 			bp->b_dev = NODEV;  		/* no assoc */
1997015Smckusick 
2007015Smckusick 	/*
2017015Smckusick 	 * Stick the buffer back on a free list.
2027015Smckusick 	 */
20326271Skarels 	s = splbio();
2048670S 	if (bp->b_bufsize <= 0) {
2058670S 		/* block has no buffer ... put at front of unused buffer list */
2068670S 		flist = &bfreelist[BQ_EMPTY];
2078670S 		binsheadfree(bp, flist);
2088670S 	} else if (bp->b_flags & (B_ERROR|B_INVAL)) {
2092325Swnj 		/* block has no info ... put at front of most free list */
2108670S 		flist = &bfreelist[BQ_AGE];
2117015Smckusick 		binsheadfree(bp, flist);
2128Sbill 	} else {
2132325Swnj 		if (bp->b_flags & B_LOCKED)
2142325Swnj 			flist = &bfreelist[BQ_LOCKED];
2152325Swnj 		else if (bp->b_flags & B_AGE)
2162325Swnj 			flist = &bfreelist[BQ_AGE];
2172325Swnj 		else
2182325Swnj 			flist = &bfreelist[BQ_LRU];
2197015Smckusick 		binstailfree(bp, flist);
2208Sbill 	}
2218Sbill 	bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
2228Sbill 	splx(s);
2238Sbill }
2248Sbill 
2258Sbill /*
2268Sbill  * See if the block is associated with some buffer
2278Sbill  * (mainly to avoid getting hung up on a wait in breada)
2288Sbill  */
2298Sbill incore(dev, blkno)
2307015Smckusick 	dev_t dev;
2317015Smckusick 	daddr_t blkno;
2328Sbill {
2338Sbill 	register struct buf *bp;
2342325Swnj 	register struct buf *dp;
2358Sbill 
2366563Smckusic 	dp = BUFHASH(dev, blkno);
2372325Swnj 	for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
2386563Smckusic 		if (bp->b_blkno == blkno && bp->b_dev == dev &&
2397015Smckusick 		    (bp->b_flags & B_INVAL) == 0)
24091Sbill 			return (1);
24191Sbill 	return (0);
2428Sbill }
2438Sbill 
2448Sbill struct buf *
2456563Smckusic baddr(dev, blkno, size)
2466563Smckusic 	dev_t dev;
2476563Smckusic 	daddr_t blkno;
2486563Smckusic 	int size;
2498Sbill {
2508Sbill 
2518Sbill 	if (incore(dev, blkno))
2526563Smckusic 		return (bread(dev, blkno, size));
2538Sbill 	return (0);
2548Sbill }
2558Sbill 
2568Sbill /*
2578Sbill  * Assign a buffer for the given block.  If the appropriate
2588Sbill  * block is already associated, return it; otherwise search
2598Sbill  * for the oldest non-busy buffer and reassign it.
2605424Swnj  *
261*32608Smckusick  * If we find the buffer, but it is dirty (marked DELWRI) and
262*32608Smckusick  * its size is changing, we must write it out first. When the
263*32608Smckusick  * buffer is shrinking, the write is done by brealloc to avoid
264*32608Smckusick  * losing the unwritten data. When the buffer is growing, the
265*32608Smckusick  * write is done by getblk, so that bread will not read stale
266*32608Smckusick  * disk data over the modified data in the buffer.
267*32608Smckusick  *
2685424Swnj  * We use splx here because this routine may be called
2695424Swnj  * on the interrupt stack during a dump, and we don't
2705424Swnj  * want to lower the ipl back to 0.
2718Sbill  */
2728Sbill struct buf *
2736563Smckusic getblk(dev, blkno, size)
2746563Smckusic 	dev_t dev;
2756563Smckusic 	daddr_t blkno;
2766563Smckusic 	int size;
2778Sbill {
2788670S 	register struct buf *bp, *dp;
2795424Swnj 	int s;
2808Sbill 
28125255Smckusick 	if (size > MAXBSIZE)
28225255Smckusick 		panic("getblk: size too big");
2837015Smckusick 	/*
28424730Smckusick 	 * To prevent overflow of 32-bit ints when converting block
28524730Smckusick 	 * numbers to byte offsets, blknos > 2^32 / DEV_BSIZE are set
28624730Smckusick 	 * to the maximum number that can be converted to a byte offset
28724730Smckusick 	 * without overflow. This is historic code; what bug it fixed,
28824730Smckusick 	 * or whether it is still a reasonable thing to do is open to
28924730Smckusick 	 * dispute. mkm 9/85
29024730Smckusick 	 */
29124730Smckusick 	if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-DEV_BSHIFT))
29224730Smckusick 		blkno = 1 << ((sizeof(int)*NBBY-DEV_BSHIFT) + 1);
29324730Smckusick 	/*
2947015Smckusick 	 * Search the cache for the block.  If we hit, but
2957015Smckusick 	 * the buffer is in use for i/o, then we wait until
2967015Smckusick 	 * the i/o has completed.
2977015Smckusick 	 */
2986563Smckusic 	dp = BUFHASH(dev, blkno);
2997015Smckusick loop:
3002325Swnj 	for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
3016563Smckusic 		if (bp->b_blkno != blkno || bp->b_dev != dev ||
3022325Swnj 		    bp->b_flags&B_INVAL)
3038Sbill 			continue;
30426271Skarels 		s = splbio();
3058Sbill 		if (bp->b_flags&B_BUSY) {
3068Sbill 			bp->b_flags |= B_WANTED;
3078Sbill 			sleep((caddr_t)bp, PRIBIO+1);
3085424Swnj 			splx(s);
3098Sbill 			goto loop;
3108Sbill 		}
3115424Swnj 		splx(s);
3128Sbill 		notavail(bp);
313*32608Smckusick 		if (bp->b_bcount != size) {
314*32608Smckusick 			if (bp->b_bcount < size && (bp->b_flags&B_DELWRI)) {
315*32608Smckusick 				bp->b_flags &= ~B_ASYNC;
316*32608Smckusick 				bwrite(bp);
317*32608Smckusick 				goto loop;
318*32608Smckusick 			}
319*32608Smckusick 			if (brealloc(bp, size) == 0)
320*32608Smckusick 				goto loop;
321*32608Smckusick 		}
32216855Smckusick 		if (bp->b_bcount != size && brealloc(bp, size) == 0)
3237188Sroot 			goto loop;
3248Sbill 		bp->b_flags |= B_CACHE;
32526271Skarels 		return (bp);
3268Sbill 	}
32791Sbill 	if (major(dev) >= nblkdev)
32891Sbill 		panic("blkdev");
3298670S 	bp = getnewbuf();
3306563Smckusic 	bfree(bp);
3317015Smckusick 	bremhash(bp);
3327015Smckusick 	binshash(bp, dp);
3338Sbill 	bp->b_dev = dev;
3346563Smckusic 	bp->b_blkno = blkno;
3358670S 	bp->b_error = 0;
3367188Sroot 	if (brealloc(bp, size) == 0)
3377188Sroot 		goto loop;
33826271Skarels 	return (bp);
3398Sbill }
3408Sbill 
3418Sbill /*
3428Sbill  * get an empty block,
3438Sbill  * not assigned to any particular device
3448Sbill  */
3458Sbill struct buf *
3466563Smckusic geteblk(size)
3476563Smckusic 	int size;
3488Sbill {
3498670S 	register struct buf *bp, *flist;
3508Sbill 
35125255Smckusick 	if (size > MAXBSIZE)
35225255Smckusick 		panic("geteblk: size too big");
3538Sbill loop:
3548670S 	bp = getnewbuf();
3558670S 	bp->b_flags |= B_INVAL;
3567015Smckusick 	bfree(bp);
3577015Smckusick 	bremhash(bp);
3588670S 	flist = &bfreelist[BQ_AGE];
3598670S 	binshash(bp, flist);
3608Sbill 	bp->b_dev = (dev_t)NODEV;
3618670S 	bp->b_error = 0;
3627188Sroot 	if (brealloc(bp, size) == 0)
3637188Sroot 		goto loop;
36426271Skarels 	return (bp);
3658Sbill }
3668Sbill 
3678Sbill /*
3686563Smckusic  * Allocate space associated with a buffer.
3699763Ssam  * If can't get space, buffer is released
3706563Smckusic  */
3716563Smckusic brealloc(bp, size)
3726563Smckusic 	register struct buf *bp;
3736563Smckusic 	int size;
3746563Smckusic {
3756563Smckusic 	daddr_t start, last;
3766563Smckusic 	register struct buf *ep;
3776563Smckusic 	struct buf *dp;
3786563Smckusic 	int s;
3796563Smckusic 
3806563Smckusic 	/*
38130749Skarels 	 * First need to make sure that all overlapping previous I/O
3826563Smckusic 	 * is dispatched with.
3836563Smckusic 	 */
3846563Smckusic 	if (size == bp->b_bcount)
3857188Sroot 		return (1);
3867188Sroot 	if (size < bp->b_bcount) {
3877188Sroot 		if (bp->b_flags & B_DELWRI) {
3887188Sroot 			bwrite(bp);
3897188Sroot 			return (0);
3907188Sroot 		}
3917188Sroot 		if (bp->b_flags & B_LOCKED)
3927188Sroot 			panic("brealloc");
3939763Ssam 		return (allocbuf(bp, size));
3947188Sroot 	}
3957188Sroot 	bp->b_flags &= ~B_DONE;
3969763Ssam 	if (bp->b_dev == NODEV)
3979763Ssam 		return (allocbuf(bp, size));
3987016Smckusick 
39915795Ssam 	trace(TR_BREALLOC, pack(bp->b_dev, size), bp->b_blkno);
4007188Sroot 	/*
4017188Sroot 	 * Search cache for any buffers that overlap the one that we
4027188Sroot 	 * are trying to allocate. Overlapping buffers must be marked
4037188Sroot 	 * invalid, after being written out if they are dirty. (indicated
4047188Sroot 	 * by B_DELWRI) A disk block must be mapped by at most one buffer
4057188Sroot 	 * at any point in time. Care must be taken to avoid deadlocking
4067188Sroot 	 * when two buffer are trying to get the same set of disk blocks.
4077188Sroot 	 */
4087188Sroot 	start = bp->b_blkno;
40912644Ssam 	last = start + btodb(size) - 1;
4106563Smckusic 	dp = BUFHASH(bp->b_dev, bp->b_blkno);
4116563Smckusic loop:
4126563Smckusic 	for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
4137188Sroot 		if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL))
4146563Smckusic 			continue;
4157188Sroot 		/* look for overlap */
4167188Sroot 		if (ep->b_bcount == 0 || ep->b_blkno > last ||
41712644Ssam 		    ep->b_blkno + btodb(ep->b_bcount) <= start)
4187188Sroot 			continue;
41926271Skarels 		s = splbio();
4206563Smckusic 		if (ep->b_flags&B_BUSY) {
4216563Smckusic 			ep->b_flags |= B_WANTED;
4226563Smckusic 			sleep((caddr_t)ep, PRIBIO+1);
4238670S 			splx(s);
4246563Smckusic 			goto loop;
4256563Smckusic 		}
4268670S 		splx(s);
4277188Sroot 		notavail(ep);
4286563Smckusic 		if (ep->b_flags & B_DELWRI) {
4296563Smckusic 			bwrite(ep);
4306563Smckusic 			goto loop;
4316563Smckusic 		}
4327188Sroot 		ep->b_flags |= B_INVAL;
4337188Sroot 		brelse(ep);
4346563Smckusic 	}
4359763Ssam 	return (allocbuf(bp, size));
4368670S }
4378670S 
4388670S /*
4398670S  * Find a buffer which is available for use.
4408670S  * Select something from a free list.
4418670S  * Preference is to AGE list, then LRU list.
4428670S  */
4438670S struct buf *
4448670S getnewbuf()
4458670S {
4468670S 	register struct buf *bp, *dp;
4478670S 	int s;
4488670S 
4498670S loop:
45026271Skarels 	s = splbio();
4518670S 	for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--)
4528670S 		if (dp->av_forw != dp)
4538670S 			break;
4548670S 	if (dp == bfreelist) {		/* no free blocks */
4558670S 		dp->b_flags |= B_WANTED;
4568670S 		sleep((caddr_t)dp, PRIBIO+1);
45712170Ssam 		splx(s);
4588670S 		goto loop;
4598670S 	}
4608670S 	splx(s);
4618670S 	bp = dp->av_forw;
4628670S 	notavail(bp);
4638670S 	if (bp->b_flags & B_DELWRI) {
4648670S 		bp->b_flags |= B_ASYNC;
4658670S 		bwrite(bp);
4668670S 		goto loop;
4678670S 	}
46815795Ssam 	trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
4698670S 	bp->b_flags = B_BUSY;
4708670S 	return (bp);
4718670S }
4728670S 
4738670S /*
4748Sbill  * Wait for I/O completion on the buffer; return errors
4758Sbill  * to the user.
4768Sbill  */
4777015Smckusick biowait(bp)
4786563Smckusic 	register struct buf *bp;
4798Sbill {
4805431Sroot 	int s;
4818Sbill 
48226271Skarels 	s = splbio();
4838Sbill 	while ((bp->b_flags&B_DONE)==0)
4848Sbill 		sleep((caddr_t)bp, PRIBIO);
4855431Sroot 	splx(s);
48611841Ssam 	if (u.u_error == 0)			/* XXX */
48711841Ssam 		u.u_error = geterror(bp);
4888Sbill }
4898Sbill 
4908Sbill /*
49113128Ssam  * Mark I/O complete on a buffer.
49213128Ssam  * If someone should be called, e.g. the pageout
49313128Ssam  * daemon, do so.  Otherwise, wake up anyone
49413128Ssam  * waiting for it.
4958Sbill  */
4967015Smckusick biodone(bp)
4977015Smckusick 	register struct buf *bp;
4988Sbill {
4998Sbill 
500420Sbill 	if (bp->b_flags & B_DONE)
5017015Smckusick 		panic("dup biodone");
5028Sbill 	bp->b_flags |= B_DONE;
5039763Ssam 	if (bp->b_flags & B_CALL) {
5049763Ssam 		bp->b_flags &= ~B_CALL;
5059763Ssam 		(*bp->b_iodone)(bp);
5069763Ssam 		return;
5079763Ssam 	}
5088Sbill 	if (bp->b_flags&B_ASYNC)
5098Sbill 		brelse(bp);
5108Sbill 	else {
5118Sbill 		bp->b_flags &= ~B_WANTED;
5128Sbill 		wakeup((caddr_t)bp);
5138Sbill 	}
5148Sbill }
5158Sbill 
5168Sbill /*
5178670S  * Insure that no part of a specified block is in an incore buffer.
51830749Skarels #ifdef SECSIZE
51930749Skarels  * "size" is given in device blocks (the units of b_blkno).
52030749Skarels #endif SECSIZE
5218670S  */
5228670S blkflush(dev, blkno, size)
5238670S 	dev_t dev;
5248670S 	daddr_t blkno;
5258670S 	long size;
5268670S {
5278670S 	register struct buf *ep;
5288670S 	struct buf *dp;
5298670S 	daddr_t start, last;
5308670S 	int s;
5318670S 
5328670S 	start = blkno;
53312644Ssam 	last = start + btodb(size) - 1;
5348670S 	dp = BUFHASH(dev, blkno);
5358670S loop:
5368670S 	for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
5378670S 		if (ep->b_dev != dev || (ep->b_flags&B_INVAL))
5388670S 			continue;
5398670S 		/* look for overlap */
5408670S 		if (ep->b_bcount == 0 || ep->b_blkno > last ||
54112644Ssam 		    ep->b_blkno + btodb(ep->b_bcount) <= start)
5428670S 			continue;
54326271Skarels 		s = splbio();
5448670S 		if (ep->b_flags&B_BUSY) {
5458670S 			ep->b_flags |= B_WANTED;
5468670S 			sleep((caddr_t)ep, PRIBIO+1);
5478670S 			splx(s);
5488670S 			goto loop;
5498670S 		}
5508670S 		if (ep->b_flags & B_DELWRI) {
5518670S 			splx(s);
5528670S 			notavail(ep);
5538670S 			bwrite(ep);
5548670S 			goto loop;
5558670S 		}
5568670S 		splx(s);
5578670S 	}
5588670S }
5598670S 
5608670S /*
56113128Ssam  * Make sure all write-behind blocks
5628Sbill  * on dev (or NODEV for all)
5638Sbill  * are flushed out.
5648Sbill  * (from umount and update)
5658Sbill  */
5668Sbill bflush(dev)
5677015Smckusick 	dev_t dev;
5688Sbill {
5698Sbill 	register struct buf *bp;
5702325Swnj 	register struct buf *flist;
5715431Sroot 	int s;
5728Sbill 
5738Sbill loop:
57426271Skarels 	s = splbio();
5758670S 	for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++)
5762325Swnj 	for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
5777015Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
5787015Smckusick 			continue;
5797015Smckusick 		if (dev == NODEV || dev == bp->b_dev) {
5808Sbill 			bp->b_flags |= B_ASYNC;
5818Sbill 			notavail(bp);
5828Sbill 			bwrite(bp);
58312173Ssam 			splx(s);
5848Sbill 			goto loop;
5858Sbill 		}
5868Sbill 	}
5875431Sroot 	splx(s);
5888Sbill }
5898Sbill 
5908Sbill /*
5918Sbill  * Pick up the device's error number and pass it to the user;
59224829Skarels  * if there is an error but the number is 0 set a generalized code.
5938Sbill  */
5948Sbill geterror(bp)
5957015Smckusick 	register struct buf *bp;
5968Sbill {
5977723Swnj 	int error = 0;
5988Sbill 
5998Sbill 	if (bp->b_flags&B_ERROR)
6007723Swnj 		if ((error = bp->b_error)==0)
6017723Swnj 			return (EIO);
6027723Swnj 	return (error);
6038Sbill }
6042299Skre 
6052299Skre /*
6062299Skre  * Invalidate in core blocks belonging to closed or umounted filesystem
6072299Skre  *
6082299Skre  * This is not nicely done at all - the buffer ought to be removed from the
6092299Skre  * hash chains & have its dev/blkno fields clobbered, but unfortunately we
6102299Skre  * can't do that here, as it is quite possible that the block is still
6112299Skre  * being used for i/o. Eventually, all disc drivers should be forced to
6122299Skre  * have a close routine, which ought ensure that the queue is empty, then
6132299Skre  * properly flush the queues. Until that happy day, this suffices for
6142299Skre  * correctness.						... kre
6152299Skre  */
6162299Skre binval(dev)
6177015Smckusick 	dev_t dev;
6182299Skre {
6192361Skre 	register struct buf *bp;
6202361Skre 	register struct bufhd *hp;
6212361Skre #define dp ((struct buf *)hp)
6222299Skre 
6232361Skre 	for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
6242361Skre 		for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
6252361Skre 			if (bp->b_dev == dev)
6262361Skre 				bp->b_flags |= B_INVAL;
6272299Skre }
628