1*9857Ssam /* vfs_cluster.c 4.41 82/12/19 */ 28Sbill 39763Ssam #include "../machine/pte.h" 49763Ssam 58Sbill #include "../h/param.h" 68Sbill #include "../h/systm.h" 78Sbill #include "../h/dir.h" 88Sbill #include "../h/user.h" 98Sbill #include "../h/buf.h" 108Sbill #include "../h/conf.h" 118Sbill #include "../h/proc.h" 128Sbill #include "../h/seg.h" 138Sbill #include "../h/vm.h" 142045Swnj #include "../h/trace.h" 158Sbill 1691Sbill /* 178Sbill * Read in (if necessary) the block and return a buffer pointer. 188Sbill */ 198Sbill struct buf * 206563Smckusic bread(dev, blkno, size) 216563Smckusic dev_t dev; 226563Smckusic daddr_t blkno; 236563Smckusic int size; 248Sbill { 258Sbill register struct buf *bp; 268Sbill 278670S if (size == 0) 288670S panic("bread: size 0"); 296563Smckusic bp = getblk(dev, blkno, size); 308Sbill if (bp->b_flags&B_DONE) { 313199Swnj trace(TR_BREADHIT, dev, blkno); 328Sbill return(bp); 338Sbill } 348Sbill bp->b_flags |= B_READ; 358670S if (bp->b_bcount > bp->b_bufsize) 368670S panic("bread"); 378Sbill (*bdevsw[major(dev)].d_strategy)(bp); 383199Swnj trace(TR_BREADMISS, dev, blkno); 398039Sroot u.u_ru.ru_inblock++; /* pay for read */ 407015Smckusick biowait(bp); 418Sbill return(bp); 428Sbill } 438Sbill 448Sbill /* 458Sbill * Read in the block, like bread, but also start I/O on the 468Sbill * read-ahead block (which is not allocated to the caller) 478Sbill */ 488Sbill struct buf * 498592Sroot breada(dev, blkno, size, rablkno, rabsize) 506563Smckusic dev_t dev; 517114Smckusick daddr_t blkno; int size; 528592Sroot daddr_t rablkno; int rabsize; 538Sbill { 548Sbill register struct buf *bp, *rabp; 558Sbill 568Sbill bp = NULL; 577015Smckusick /* 587015Smckusick * If the block isn't in core, then allocate 597015Smckusick * a buffer and initiate i/o (getblk checks 607015Smckusick * for a cache hit). 617015Smckusick */ 628Sbill if (!incore(dev, blkno)) { 636563Smckusic bp = getblk(dev, blkno, size); 648Sbill if ((bp->b_flags&B_DONE) == 0) { 658Sbill bp->b_flags |= B_READ; 668670S if (bp->b_bcount > bp->b_bufsize) 678670S panic("breada"); 688Sbill (*bdevsw[major(dev)].d_strategy)(bp); 693199Swnj trace(TR_BREADMISS, dev, blkno); 708039Sroot u.u_ru.ru_inblock++; /* pay for read */ 717015Smckusick } else 723199Swnj trace(TR_BREADHIT, dev, blkno); 738Sbill } 747015Smckusick 757015Smckusick /* 767015Smckusick * If there's a read-ahead block, start i/o 777015Smckusick * on it also (as above). 787015Smckusick */ 798Sbill if (rablkno && !incore(dev, rablkno)) { 808592Sroot rabp = getblk(dev, rablkno, rabsize); 812045Swnj if (rabp->b_flags & B_DONE) { 828Sbill brelse(rabp); 833199Swnj trace(TR_BREADHITRA, dev, blkno); 842045Swnj } else { 858Sbill rabp->b_flags |= B_READ|B_ASYNC; 868670S if (rabp->b_bcount > rabp->b_bufsize) 878670S panic("breadrabp"); 888Sbill (*bdevsw[major(dev)].d_strategy)(rabp); 893199Swnj trace(TR_BREADMISSRA, dev, rablock); 908039Sroot u.u_ru.ru_inblock++; /* pay in advance */ 918Sbill } 928Sbill } 937015Smckusick 947015Smckusick /* 957114Smckusick * If block was in core, let bread get it. 967114Smckusick * If block wasn't in core, then the read was started 977114Smckusick * above, and just wait for it. 987015Smckusick */ 997114Smckusick if (bp == NULL) 1007114Smckusick return (bread(dev, blkno, size)); 1017015Smckusick biowait(bp); 1027114Smckusick return (bp); 1038Sbill } 1048Sbill 1058Sbill /* 1068Sbill * Write the buffer, waiting for completion. 1078Sbill * Then release the buffer. 1088Sbill */ 1098Sbill bwrite(bp) 1107015Smckusick register struct buf *bp; 1118Sbill { 1128Sbill register flag; 1138Sbill 1148Sbill flag = bp->b_flags; 115*9857Ssam bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); 1168Sbill if ((flag&B_DELWRI) == 0) 1178039Sroot u.u_ru.ru_oublock++; /* noone paid yet */ 1184033Swnj trace(TR_BWRITE, bp->b_dev, bp->b_blkno); 1198670S if (bp->b_bcount > bp->b_bufsize) 1208670S panic("bwrite"); 1218Sbill (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 1227015Smckusick 1237015Smckusick /* 1247015Smckusick * If the write was synchronous, then await i/o completion. 1257015Smckusick * If the write was "delayed", then we put the buffer on 1267015Smckusick * the q of blocks awaiting i/o completion status. 1277015Smckusick */ 1288Sbill if ((flag&B_ASYNC) == 0) { 1297015Smckusick biowait(bp); 1308Sbill brelse(bp); 1318Sbill } else if (flag & B_DELWRI) 1328Sbill bp->b_flags |= B_AGE; 1338Sbill } 1348Sbill 1358Sbill /* 1368Sbill * Release the buffer, marking it so that if it is grabbed 1378Sbill * for another purpose it will be written out before being 1388Sbill * given up (e.g. when writing a partial block where it is 1398Sbill * assumed that another write for the same block will soon follow). 1408Sbill * This can't be done for magtape, since writes must be done 1418Sbill * in the same order as requested. 1428Sbill */ 1438Sbill bdwrite(bp) 1447015Smckusick register struct buf *bp; 1458Sbill { 1462403Skre register int flags; 1478Sbill 1488Sbill if ((bp->b_flags&B_DELWRI) == 0) 1498039Sroot u.u_ru.ru_oublock++; /* noone paid yet */ 1502403Skre flags = bdevsw[major(bp->b_dev)].d_flags; 1512403Skre if(flags & B_TAPE) 1528Sbill bawrite(bp); 1538Sbill else { 1548Sbill bp->b_flags |= B_DELWRI | B_DONE; 1558Sbill brelse(bp); 1568Sbill } 1578Sbill } 1588Sbill 1598Sbill /* 1608Sbill * Release the buffer, start I/O on it, but don't wait for completion. 1618Sbill */ 1628Sbill bawrite(bp) 1637015Smckusick register struct buf *bp; 1648Sbill { 1658Sbill 1668Sbill bp->b_flags |= B_ASYNC; 1678Sbill bwrite(bp); 1688Sbill } 1698Sbill 1708Sbill /* 1717015Smckusick * Release the buffer, with no I/O implied. 1728Sbill */ 1738Sbill brelse(bp) 1747015Smckusick register struct buf *bp; 1758Sbill { 1762325Swnj register struct buf *flist; 1778Sbill register s; 1788Sbill 1797015Smckusick /* 1807015Smckusick * If someone's waiting for the buffer, or 1817015Smckusick * is waiting for a buffer wake 'em up. 1827015Smckusick */ 1838Sbill if (bp->b_flags&B_WANTED) 1848Sbill wakeup((caddr_t)bp); 1852325Swnj if (bfreelist[0].b_flags&B_WANTED) { 1862325Swnj bfreelist[0].b_flags &= ~B_WANTED; 1872325Swnj wakeup((caddr_t)bfreelist); 1888Sbill } 1892683Swnj if (bp->b_flags&B_ERROR) 1902683Swnj if (bp->b_flags & B_LOCKED) 1912683Swnj bp->b_flags &= ~B_ERROR; /* try again later */ 1922683Swnj else 1932683Swnj bp->b_dev = NODEV; /* no assoc */ 1947015Smckusick 1957015Smckusick /* 1967015Smckusick * Stick the buffer back on a free list. 1977015Smckusick */ 1988Sbill s = spl6(); 1998670S if (bp->b_bufsize <= 0) { 2008670S /* block has no buffer ... put at front of unused buffer list */ 2018670S flist = &bfreelist[BQ_EMPTY]; 2028670S binsheadfree(bp, flist); 2038670S } else if (bp->b_flags & (B_ERROR|B_INVAL)) { 2042325Swnj /* block has no info ... put at front of most free list */ 2058670S flist = &bfreelist[BQ_AGE]; 2067015Smckusick binsheadfree(bp, flist); 2078Sbill } else { 2082325Swnj if (bp->b_flags & B_LOCKED) 2092325Swnj flist = &bfreelist[BQ_LOCKED]; 2102325Swnj else if (bp->b_flags & B_AGE) 2112325Swnj flist = &bfreelist[BQ_AGE]; 2122325Swnj else 2132325Swnj flist = &bfreelist[BQ_LRU]; 2147015Smckusick binstailfree(bp, flist); 2158Sbill } 2168Sbill bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); 2178Sbill splx(s); 2188Sbill } 2198Sbill 2208Sbill /* 2218Sbill * See if the block is associated with some buffer 2228Sbill * (mainly to avoid getting hung up on a wait in breada) 2238Sbill */ 2248Sbill incore(dev, blkno) 2257015Smckusick dev_t dev; 2267015Smckusick daddr_t blkno; 2278Sbill { 2288Sbill register struct buf *bp; 2292325Swnj register struct buf *dp; 2308Sbill 2316563Smckusic dp = BUFHASH(dev, blkno); 2322325Swnj for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) 2336563Smckusic if (bp->b_blkno == blkno && bp->b_dev == dev && 2347015Smckusick (bp->b_flags & B_INVAL) == 0) 23591Sbill return (1); 23691Sbill return (0); 2378Sbill } 2388Sbill 2398Sbill struct buf * 2406563Smckusic baddr(dev, blkno, size) 2416563Smckusic dev_t dev; 2426563Smckusic daddr_t blkno; 2436563Smckusic int size; 2448Sbill { 2458Sbill 2468Sbill if (incore(dev, blkno)) 2476563Smckusic return (bread(dev, blkno, size)); 2488Sbill return (0); 2498Sbill } 2508Sbill 2518Sbill /* 2528Sbill * Assign a buffer for the given block. If the appropriate 2538Sbill * block is already associated, return it; otherwise search 2548Sbill * for the oldest non-busy buffer and reassign it. 2555424Swnj * 2565424Swnj * We use splx here because this routine may be called 2575424Swnj * on the interrupt stack during a dump, and we don't 2585424Swnj * want to lower the ipl back to 0. 2598Sbill */ 2608Sbill struct buf * 2616563Smckusic getblk(dev, blkno, size) 2626563Smckusic dev_t dev; 2636563Smckusic daddr_t blkno; 2646563Smckusic int size; 2658Sbill { 2668670S register struct buf *bp, *dp; 2675424Swnj int s; 2688Sbill 2699763Ssam if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT)) /* XXX */ 2701831Sbill blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1); 2717015Smckusick /* 2727015Smckusick * Search the cache for the block. If we hit, but 2737015Smckusick * the buffer is in use for i/o, then we wait until 2747015Smckusick * the i/o has completed. 2757015Smckusick */ 2766563Smckusic dp = BUFHASH(dev, blkno); 2777015Smckusick loop: 2782325Swnj for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { 2796563Smckusic if (bp->b_blkno != blkno || bp->b_dev != dev || 2802325Swnj bp->b_flags&B_INVAL) 2818Sbill continue; 2825424Swnj s = spl6(); 2838Sbill if (bp->b_flags&B_BUSY) { 2848Sbill bp->b_flags |= B_WANTED; 2858Sbill sleep((caddr_t)bp, PRIBIO+1); 2865424Swnj splx(s); 2878Sbill goto loop; 2888Sbill } 2895424Swnj splx(s); 2908Sbill notavail(bp); 2917188Sroot if (brealloc(bp, size) == 0) 2927188Sroot goto loop; 2938Sbill bp->b_flags |= B_CACHE; 2948Sbill return(bp); 2958Sbill } 29691Sbill if (major(dev) >= nblkdev) 29791Sbill panic("blkdev"); 2988670S bp = getnewbuf(); 2996563Smckusic bfree(bp); 3007015Smckusick bremhash(bp); 3017015Smckusick binshash(bp, dp); 3028Sbill bp->b_dev = dev; 3036563Smckusic bp->b_blkno = blkno; 3048670S bp->b_error = 0; 3057188Sroot if (brealloc(bp, size) == 0) 3067188Sroot goto loop; 3078Sbill return(bp); 3088Sbill } 3098Sbill 3108Sbill /* 3118Sbill * get an empty block, 3128Sbill * not assigned to any particular device 3138Sbill */ 3148Sbill struct buf * 3156563Smckusic geteblk(size) 3166563Smckusic int size; 3178Sbill { 3188670S register struct buf *bp, *flist; 3198Sbill 3208Sbill loop: 3218670S bp = getnewbuf(); 3228670S bp->b_flags |= B_INVAL; 3237015Smckusick bfree(bp); 3247015Smckusick bremhash(bp); 3258670S flist = &bfreelist[BQ_AGE]; 3268670S binshash(bp, flist); 3278Sbill bp->b_dev = (dev_t)NODEV; 3288670S bp->b_error = 0; 3297188Sroot if (brealloc(bp, size) == 0) 3307188Sroot goto loop; 3318Sbill return(bp); 3328Sbill } 3338Sbill 3348Sbill /* 3356563Smckusic * Allocate space associated with a buffer. 3369763Ssam * If can't get space, buffer is released 3376563Smckusic */ 3386563Smckusic brealloc(bp, size) 3396563Smckusic register struct buf *bp; 3406563Smckusic int size; 3416563Smckusic { 3426563Smckusic daddr_t start, last; 3436563Smckusic register struct buf *ep; 3446563Smckusic struct buf *dp; 3456563Smckusic int s; 3466563Smckusic 3476563Smckusic /* 3486563Smckusic * First need to make sure that all overlaping previous I/O 3496563Smckusic * is dispatched with. 3506563Smckusic */ 3516563Smckusic if (size == bp->b_bcount) 3527188Sroot return (1); 3537188Sroot if (size < bp->b_bcount) { 3547188Sroot if (bp->b_flags & B_DELWRI) { 3557188Sroot bwrite(bp); 3567188Sroot return (0); 3577188Sroot } 3587188Sroot if (bp->b_flags & B_LOCKED) 3597188Sroot panic("brealloc"); 3609763Ssam return (allocbuf(bp, size)); 3617188Sroot } 3627188Sroot bp->b_flags &= ~B_DONE; 3639763Ssam if (bp->b_dev == NODEV) 3649763Ssam return (allocbuf(bp, size)); 3657016Smckusick 3667188Sroot /* 3677188Sroot * Search cache for any buffers that overlap the one that we 3687188Sroot * are trying to allocate. Overlapping buffers must be marked 3697188Sroot * invalid, after being written out if they are dirty. (indicated 3707188Sroot * by B_DELWRI) A disk block must be mapped by at most one buffer 3717188Sroot * at any point in time. Care must be taken to avoid deadlocking 3727188Sroot * when two buffer are trying to get the same set of disk blocks. 3737188Sroot */ 3747188Sroot start = bp->b_blkno; 3757188Sroot last = start + (size / DEV_BSIZE) - 1; 3766563Smckusic dp = BUFHASH(bp->b_dev, bp->b_blkno); 3776563Smckusic loop: 3786563Smckusic for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { 3797188Sroot if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL)) 3806563Smckusic continue; 3817188Sroot /* look for overlap */ 3827188Sroot if (ep->b_bcount == 0 || ep->b_blkno > last || 3837188Sroot ep->b_blkno + (ep->b_bcount / DEV_BSIZE) <= start) 3847188Sroot continue; 3856563Smckusic s = spl6(); 3866563Smckusic if (ep->b_flags&B_BUSY) { 3876563Smckusic ep->b_flags |= B_WANTED; 3886563Smckusic sleep((caddr_t)ep, PRIBIO+1); 3898670S splx(s); 3906563Smckusic goto loop; 3916563Smckusic } 3928670S splx(s); 3937188Sroot notavail(ep); 3946563Smckusic if (ep->b_flags & B_DELWRI) { 3956563Smckusic bwrite(ep); 3966563Smckusic goto loop; 3976563Smckusic } 3987188Sroot ep->b_flags |= B_INVAL; 3997188Sroot brelse(ep); 4006563Smckusic } 4019763Ssam return (allocbuf(bp, size)); 4028670S } 4038670S 4048670S /* 4058670S * Expand or contract the actual memory allocated to a buffer. 4069763Ssam * If no memory is available, release buffer and take error exit 4078670S */ 4088670S allocbuf(tp, size) 4098670S register struct buf *tp; 4108670S int size; 4118670S { 4128670S register struct buf *bp, *ep; 4138670S int sizealloc, take; 4149763Ssam #ifdef sun 4159763Ssam register char *a; 4169763Ssam int osize; 4179763Ssam #endif 4188670S 4199763Ssam #ifndef sun 4208670S sizealloc = roundup(size, CLBYTES); 4219763Ssam #else 4229763Ssam sizealloc = roundup(size, BUFALLOCSIZE); 4239763Ssam #endif 4246563Smckusic /* 4258670S * Buffer size does not change 4266563Smckusic */ 4278670S if (sizealloc == tp->b_bufsize) 4288670S goto out; 4299763Ssam #ifndef sun 4308670S /* 4318670S * Buffer size is shrinking. 4328670S * Place excess space in a buffer header taken from the 4338670S * BQ_EMPTY buffer list and placed on the "most free" list. 4348670S * If no extra buffer headers are available, leave the 4358670S * extra space in the present buffer. 4368670S */ 4378670S if (sizealloc < tp->b_bufsize) { 4388670S ep = bfreelist[BQ_EMPTY].av_forw; 4398670S if (ep == &bfreelist[BQ_EMPTY]) 4408670S goto out; 4418670S notavail(ep); 4428670S pagemove(tp->b_un.b_addr + sizealloc, ep->b_un.b_addr, 4438670S (int)tp->b_bufsize - sizealloc); 4448670S ep->b_bufsize = tp->b_bufsize - sizealloc; 4458670S tp->b_bufsize = sizealloc; 4468670S ep->b_flags |= B_INVAL; 4478670S ep->b_bcount = 0; 4488670S brelse(ep); 4498670S goto out; 4508670S } 4518670S /* 4528670S * More buffer space is needed. Get it out of buffers on 4538670S * the "most free" list, placing the empty headers on the 4548670S * BQ_EMPTY buffer header list. 4558670S */ 4568670S while (tp->b_bufsize < sizealloc) { 4578670S take = sizealloc - tp->b_bufsize; 4588670S bp = getnewbuf(); 4598670S if (take >= bp->b_bufsize) 4608670S take = bp->b_bufsize; 4618670S pagemove(&bp->b_un.b_addr[bp->b_bufsize - take], 4628670S &tp->b_un.b_addr[tp->b_bufsize], take); 4638670S tp->b_bufsize += take; 4648670S bp->b_bufsize = bp->b_bufsize - take; 4658670S if (bp->b_bcount > bp->b_bufsize) 4668670S bp->b_bcount = bp->b_bufsize; 4678670S if (bp->b_bufsize <= 0) { 4688670S bremhash(bp); 4698670S binshash(bp, &bfreelist[BQ_EMPTY]); 4708670S bp->b_dev = (dev_t)NODEV; 4718670S bp->b_error = 0; 4728670S bp->b_flags |= B_INVAL; 4738670S } 4748670S brelse(bp); 4758670S } 4769763Ssam #else 4779763Ssam /* 4789763Ssam * Buffer size is shrinking 4799763Ssam * Just put the tail end back in the map 4809763Ssam */ 4819763Ssam if (sizealloc < tp->b_bufsize) { 4829763Ssam rmfree(buffermap, (long)(tp->b_bufsize - sizealloc), 4839763Ssam (long)(tp->b_un.b_addr + sizealloc)); 4849763Ssam tp->b_bufsize = sizealloc; 4859763Ssam goto out; 4869763Ssam } 4879763Ssam /* 4889763Ssam * Buffer is being expanded or created 4899763Ssam * If being expanded, attempt to get contiguous 4909763Ssam * section, otherwise get a new chunk and copy. 4919763Ssam * If no space, free up a buffer on the AGE list 4929763Ssam * and try again. 4939763Ssam */ 4949763Ssam do { 4959763Ssam if ((osize = tp->b_bufsize)) { 4969763Ssam a = (char *)rmget(buffermap, (long)(sizealloc-osize), 4979763Ssam (long)(tp->b_un.b_addr + osize)); 4989763Ssam if (a == 0) { 4999763Ssam a = (char *)rmalloc(buffermap, (long)sizealloc); 5009763Ssam if (a != 0) { 5019763Ssam bcopy(tp->b_un.b_addr, a, osize); 5029763Ssam rmfree(buffermap, (long)osize, 5039763Ssam (long)tp->b_un.b_addr); 5049763Ssam tp->b_un.b_addr = a; 5059763Ssam } 5069763Ssam } 5079763Ssam } else { 5089763Ssam a = (char *)rmalloc(buffermap, (long)sizealloc); 5099763Ssam if (a != 0) 5109763Ssam tp->b_un.b_addr = a; 5119763Ssam } 5129763Ssam } while (a == 0 && bfreemem()); 5139763Ssam if (a == 0) { 5149763Ssam brelse(tp); 5159763Ssam return (0); 5169763Ssam } 5179763Ssam tp->b_bufsize = sizealloc; 5189763Ssam #endif 5198670S out: 5208670S tp->b_bcount = size; 5219763Ssam return (1); 5226563Smckusic } 5236563Smckusic 5246563Smckusic /* 5256563Smckusic * Release space associated with a buffer. 5266563Smckusic */ 5276563Smckusic bfree(bp) 5286563Smckusic struct buf *bp; 5296563Smckusic { 5309763Ssam #ifdef sun 5319763Ssam if (bp->b_bufsize) { 5329763Ssam rmfree(buffermap, (long)bp->b_bufsize, (long)bp->b_un.b_addr); 5339763Ssam bp->b_bufsize = 0; 5349763Ssam } 5359763Ssam #endif 5366563Smckusic bp->b_bcount = 0; 5376563Smckusic } 5386563Smckusic 5399763Ssam #ifdef sun 5406563Smckusic /* 5419763Ssam * Attempt to free up buffer space by flushing 5429763Ssam * something in the free list. 5439763Ssam * Don't wait for something, that could cause deadlocks 5449763Ssam * We start with BQ_AGE because we know BQ_EMPTY take no memory. 5459763Ssam */ 5469763Ssam bfreemem() 5479763Ssam { 5489763Ssam register struct buf *bp, *dp; 5499763Ssam int s; 5509763Ssam 5519763Ssam loop: 5529763Ssam s = spl6(); 5539763Ssam for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) 5549763Ssam if (dp->av_forw != dp) 5559763Ssam break; 5569763Ssam splx(s); 5579763Ssam if (dp == bfreelist) { /* no free blocks */ 5589763Ssam return (0); 5599763Ssam } 5609763Ssam bp = dp->av_forw; 5619763Ssam notavail(bp); 5629763Ssam if (bp->b_flags & B_DELWRI) { 5639763Ssam bp->b_flags |= B_ASYNC; 5649763Ssam bwrite(bp); 5659763Ssam goto loop; 5669763Ssam } 5679763Ssam trace(TR_BRELSE, bp->b_dev, bp->b_blkno); 5689763Ssam bp->b_flags = B_BUSY | B_INVAL; 5699763Ssam bfree(bp); 5709763Ssam bremhash(bp); 5719763Ssam binshash(bp, &bfreelist[BQ_EMPTY]); 5729763Ssam bp->b_dev = (dev_t)NODEV; 5739763Ssam bp->b_error = 0; 5749763Ssam brelse(bp); 5759763Ssam return (1); 5769763Ssam } 5779763Ssam #endif 5789763Ssam 5799763Ssam /* 5808670S * Find a buffer which is available for use. 5818670S * Select something from a free list. 5828670S * Preference is to AGE list, then LRU list. 5838670S */ 5848670S struct buf * 5858670S getnewbuf() 5868670S { 5878670S register struct buf *bp, *dp; 5888670S int s; 5898670S 5908670S loop: 5918670S s = spl6(); 5929763Ssam #ifndef sun 5938670S for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--) 5949763Ssam #else 5959763Ssam for (dp = &bfreelist[BQ_EMPTY]; dp > bfreelist; dp--) 5969763Ssam #endif 5978670S if (dp->av_forw != dp) 5988670S break; 5998670S if (dp == bfreelist) { /* no free blocks */ 6008670S dp->b_flags |= B_WANTED; 6018670S sleep((caddr_t)dp, PRIBIO+1); 6028670S goto loop; 6038670S } 6048670S splx(s); 6058670S bp = dp->av_forw; 6068670S notavail(bp); 6078670S if (bp->b_flags & B_DELWRI) { 6088670S bp->b_flags |= B_ASYNC; 6098670S bwrite(bp); 6108670S goto loop; 6118670S } 6128670S trace(TR_BRELSE, bp->b_dev, bp->b_blkno); 6138670S bp->b_flags = B_BUSY; 6148670S return (bp); 6158670S } 6168670S 6178670S /* 6188Sbill * Wait for I/O completion on the buffer; return errors 6198Sbill * to the user. 6208Sbill */ 6217015Smckusick biowait(bp) 6226563Smckusic register struct buf *bp; 6238Sbill { 6245431Sroot int s; 6258Sbill 6265431Sroot s = spl6(); 6278Sbill while ((bp->b_flags&B_DONE)==0) 6288Sbill sleep((caddr_t)bp, PRIBIO); 6295431Sroot splx(s); 6307723Swnj u.u_error = geterror(bp); 6318Sbill } 6328Sbill 6338Sbill /* 6348Sbill * Mark I/O complete on a buffer. If the header 6358Sbill * indicates a dirty page push completion, the 6368Sbill * header is inserted into the ``cleaned'' list 6378Sbill * to be processed by the pageout daemon. Otherwise 6388Sbill * release it if I/O is asynchronous, and wake 6398Sbill * up anyone waiting for it. 6408Sbill */ 6417015Smckusick biodone(bp) 6427015Smckusick register struct buf *bp; 6438Sbill { 6448Sbill register int s; 6458Sbill 646420Sbill if (bp->b_flags & B_DONE) 6477015Smckusick panic("dup biodone"); 6488Sbill bp->b_flags |= B_DONE; 6498Sbill if (bp->b_flags & B_DIRTY) { 6508Sbill if (bp->b_flags & B_ERROR) 6518Sbill panic("IO err in push"); 6528Sbill s = spl6(); 6538Sbill bp->av_forw = bclnlist; 6548Sbill bp->b_bcount = swsize[bp - swbuf]; 6558Sbill bp->b_pfcent = swpf[bp - swbuf]; 6563601Swnj cnt.v_pgout++; 6573601Swnj cnt.v_pgpgout += bp->b_bcount / NBPG; 6588Sbill bclnlist = bp; 6598Sbill if (bswlist.b_flags & B_WANTED) 6608Sbill wakeup((caddr_t)&proc[2]); 6618Sbill splx(s); 662383Sbill return; 6638Sbill } 6649763Ssam if (bp->b_flags & B_CALL) { 6659763Ssam bp->b_flags &= ~B_CALL; 6669763Ssam (*bp->b_iodone)(bp); 6679763Ssam return; 6689763Ssam } 6698Sbill if (bp->b_flags&B_ASYNC) 6708Sbill brelse(bp); 6718Sbill else { 6728Sbill bp->b_flags &= ~B_WANTED; 6738Sbill wakeup((caddr_t)bp); 6748Sbill } 6758Sbill } 6768Sbill 6778Sbill /* 6788670S * Insure that no part of a specified block is in an incore buffer. 6798670S */ 6808670S blkflush(dev, blkno, size) 6818670S dev_t dev; 6828670S daddr_t blkno; 6838670S long size; 6848670S { 6858670S register struct buf *ep; 6868670S struct buf *dp; 6878670S daddr_t start, last; 6888670S int s; 6898670S 6908670S start = blkno; 6918670S last = start + (size / DEV_BSIZE) - 1; 6928670S dp = BUFHASH(dev, blkno); 6938670S loop: 6948670S for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { 6958670S if (ep->b_dev != dev || (ep->b_flags&B_INVAL)) 6968670S continue; 6978670S /* look for overlap */ 6988670S if (ep->b_bcount == 0 || ep->b_blkno > last || 6998670S ep->b_blkno + (ep->b_bcount / DEV_BSIZE) <= start) 7008670S continue; 7018670S s = spl6(); 7028670S if (ep->b_flags&B_BUSY) { 7038670S ep->b_flags |= B_WANTED; 7048670S sleep((caddr_t)ep, PRIBIO+1); 7058670S splx(s); 7068670S goto loop; 7078670S } 7088670S if (ep->b_flags & B_DELWRI) { 7098670S splx(s); 7108670S notavail(ep); 7118670S bwrite(ep); 7128670S goto loop; 7138670S } 7148670S splx(s); 7158670S } 7168670S } 7178670S 7188670S /* 7198Sbill * make sure all write-behind blocks 7208Sbill * on dev (or NODEV for all) 7218Sbill * are flushed out. 7228Sbill * (from umount and update) 7236563Smckusic * (and temporarily pagein) 7248Sbill */ 7258Sbill bflush(dev) 7267015Smckusick dev_t dev; 7278Sbill { 7288Sbill register struct buf *bp; 7292325Swnj register struct buf *flist; 7305431Sroot int s; 7318Sbill 7328Sbill loop: 7335431Sroot s = spl6(); 7348670S for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) 7352325Swnj for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { 7367015Smckusick if ((bp->b_flags & B_DELWRI) == 0) 7377015Smckusick continue; 7387015Smckusick if (dev == NODEV || dev == bp->b_dev) { 7398Sbill bp->b_flags |= B_ASYNC; 7408Sbill notavail(bp); 7418Sbill bwrite(bp); 7428Sbill goto loop; 7438Sbill } 7448Sbill } 7455431Sroot splx(s); 7468Sbill } 7478Sbill 7488Sbill /* 7498Sbill * Pick up the device's error number and pass it to the user; 7508Sbill * if there is an error but the number is 0 set a generalized 7518Sbill * code. Actually the latter is always true because devices 7528Sbill * don't yet return specific errors. 7538Sbill */ 7548Sbill geterror(bp) 7557015Smckusick register struct buf *bp; 7568Sbill { 7577723Swnj int error = 0; 7588Sbill 7598Sbill if (bp->b_flags&B_ERROR) 7607723Swnj if ((error = bp->b_error)==0) 7617723Swnj return (EIO); 7627723Swnj return (error); 7638Sbill } 7642299Skre 7652299Skre /* 7662299Skre * Invalidate in core blocks belonging to closed or umounted filesystem 7672299Skre * 7682299Skre * This is not nicely done at all - the buffer ought to be removed from the 7692299Skre * hash chains & have its dev/blkno fields clobbered, but unfortunately we 7702299Skre * can't do that here, as it is quite possible that the block is still 7712299Skre * being used for i/o. Eventually, all disc drivers should be forced to 7722299Skre * have a close routine, which ought ensure that the queue is empty, then 7732299Skre * properly flush the queues. Until that happy day, this suffices for 7742299Skre * correctness. ... kre 7752299Skre */ 7762299Skre binval(dev) 7777015Smckusick dev_t dev; 7782299Skre { 7792361Skre register struct buf *bp; 7802361Skre register struct bufhd *hp; 7812361Skre #define dp ((struct buf *)hp) 7822299Skre 7832361Skre for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++) 7842361Skre for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) 7852361Skre if (bp->b_dev == dev) 7862361Skre bp->b_flags |= B_INVAL; 7872299Skre } 788