1*12173Ssam /* vfs_cluster.c 4.44 83/05/02 */ 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; 1159857Ssam 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); 60212170Ssam splx(s); 6038670S goto loop; 6048670S } 6058670S splx(s); 6068670S bp = dp->av_forw; 6078670S notavail(bp); 6088670S if (bp->b_flags & B_DELWRI) { 6098670S bp->b_flags |= B_ASYNC; 6108670S bwrite(bp); 6118670S goto loop; 6128670S } 6138670S trace(TR_BRELSE, bp->b_dev, bp->b_blkno); 6148670S bp->b_flags = B_BUSY; 6158670S return (bp); 6168670S } 6178670S 6188670S /* 6198Sbill * Wait for I/O completion on the buffer; return errors 6208Sbill * to the user. 6218Sbill */ 6227015Smckusick biowait(bp) 6236563Smckusic register struct buf *bp; 6248Sbill { 6255431Sroot int s; 6268Sbill 6275431Sroot s = spl6(); 6288Sbill while ((bp->b_flags&B_DONE)==0) 6298Sbill sleep((caddr_t)bp, PRIBIO); 6305431Sroot splx(s); 63111841Ssam if (u.u_error == 0) /* XXX */ 63211841Ssam u.u_error = geterror(bp); 6338Sbill } 6348Sbill 6358Sbill /* 6368Sbill * Mark I/O complete on a buffer. If the header 6378Sbill * indicates a dirty page push completion, the 6388Sbill * header is inserted into the ``cleaned'' list 6398Sbill * to be processed by the pageout daemon. Otherwise 6408Sbill * release it if I/O is asynchronous, and wake 6418Sbill * up anyone waiting for it. 6428Sbill */ 6437015Smckusick biodone(bp) 6447015Smckusick register struct buf *bp; 6458Sbill { 6468Sbill register int s; 6478Sbill 648420Sbill if (bp->b_flags & B_DONE) 6497015Smckusick panic("dup biodone"); 6508Sbill bp->b_flags |= B_DONE; 6518Sbill if (bp->b_flags & B_DIRTY) { 6528Sbill if (bp->b_flags & B_ERROR) 6538Sbill panic("IO err in push"); 6548Sbill s = spl6(); 6558Sbill bp->av_forw = bclnlist; 6568Sbill bp->b_bcount = swsize[bp - swbuf]; 6578Sbill bp->b_pfcent = swpf[bp - swbuf]; 6583601Swnj cnt.v_pgout++; 6593601Swnj cnt.v_pgpgout += bp->b_bcount / NBPG; 6608Sbill bclnlist = bp; 6618Sbill if (bswlist.b_flags & B_WANTED) 6628Sbill wakeup((caddr_t)&proc[2]); 6638Sbill splx(s); 664383Sbill return; 6658Sbill } 6669763Ssam if (bp->b_flags & B_CALL) { 6679763Ssam bp->b_flags &= ~B_CALL; 6689763Ssam (*bp->b_iodone)(bp); 6699763Ssam return; 6709763Ssam } 6718Sbill if (bp->b_flags&B_ASYNC) 6728Sbill brelse(bp); 6738Sbill else { 6748Sbill bp->b_flags &= ~B_WANTED; 6758Sbill wakeup((caddr_t)bp); 6768Sbill } 6778Sbill } 6788Sbill 6798Sbill /* 6808670S * Insure that no part of a specified block is in an incore buffer. 6818670S */ 6828670S blkflush(dev, blkno, size) 6838670S dev_t dev; 6848670S daddr_t blkno; 6858670S long size; 6868670S { 6878670S register struct buf *ep; 6888670S struct buf *dp; 6898670S daddr_t start, last; 6908670S int s; 6918670S 6928670S start = blkno; 6938670S last = start + (size / DEV_BSIZE) - 1; 6948670S dp = BUFHASH(dev, blkno); 6958670S loop: 6968670S for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) { 6978670S if (ep->b_dev != dev || (ep->b_flags&B_INVAL)) 6988670S continue; 6998670S /* look for overlap */ 7008670S if (ep->b_bcount == 0 || ep->b_blkno > last || 7018670S ep->b_blkno + (ep->b_bcount / DEV_BSIZE) <= start) 7028670S continue; 7038670S s = spl6(); 7048670S if (ep->b_flags&B_BUSY) { 7058670S ep->b_flags |= B_WANTED; 7068670S sleep((caddr_t)ep, PRIBIO+1); 7078670S splx(s); 7088670S goto loop; 7098670S } 7108670S if (ep->b_flags & B_DELWRI) { 7118670S splx(s); 7128670S notavail(ep); 7138670S bwrite(ep); 7148670S goto loop; 7158670S } 7168670S splx(s); 7178670S } 7188670S } 7198670S 7208670S /* 7218Sbill * make sure all write-behind blocks 7228Sbill * on dev (or NODEV for all) 7238Sbill * are flushed out. 7248Sbill * (from umount and update) 7256563Smckusic * (and temporarily pagein) 7268Sbill */ 7278Sbill bflush(dev) 7287015Smckusick dev_t dev; 7298Sbill { 7308Sbill register struct buf *bp; 7312325Swnj register struct buf *flist; 7325431Sroot int s; 7338Sbill 7348Sbill loop: 7355431Sroot s = spl6(); 7368670S for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) 7372325Swnj for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { 7387015Smckusick if ((bp->b_flags & B_DELWRI) == 0) 7397015Smckusick continue; 7407015Smckusick if (dev == NODEV || dev == bp->b_dev) { 7418Sbill bp->b_flags |= B_ASYNC; 7428Sbill notavail(bp); 7438Sbill bwrite(bp); 744*12173Ssam splx(s); 7458Sbill goto loop; 7468Sbill } 7478Sbill } 7485431Sroot splx(s); 7498Sbill } 7508Sbill 7518Sbill /* 7528Sbill * Pick up the device's error number and pass it to the user; 7538Sbill * if there is an error but the number is 0 set a generalized 7548Sbill * code. Actually the latter is always true because devices 7558Sbill * don't yet return specific errors. 7568Sbill */ 7578Sbill geterror(bp) 7587015Smckusick register struct buf *bp; 7598Sbill { 7607723Swnj int error = 0; 7618Sbill 7628Sbill if (bp->b_flags&B_ERROR) 7637723Swnj if ((error = bp->b_error)==0) 7647723Swnj return (EIO); 7657723Swnj return (error); 7668Sbill } 7672299Skre 7682299Skre /* 7692299Skre * Invalidate in core blocks belonging to closed or umounted filesystem 7702299Skre * 7712299Skre * This is not nicely done at all - the buffer ought to be removed from the 7722299Skre * hash chains & have its dev/blkno fields clobbered, but unfortunately we 7732299Skre * can't do that here, as it is quite possible that the block is still 7742299Skre * being used for i/o. Eventually, all disc drivers should be forced to 7752299Skre * have a close routine, which ought ensure that the queue is empty, then 7762299Skre * properly flush the queues. Until that happy day, this suffices for 7772299Skre * correctness. ... kre 7782299Skre */ 7792299Skre binval(dev) 7807015Smckusick dev_t dev; 7812299Skre { 7822361Skre register struct buf *bp; 7832361Skre register struct bufhd *hp; 7842361Skre #define dp ((struct buf *)hp) 7852299Skre 7862361Skre for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++) 7872361Skre for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) 7882361Skre if (bp->b_dev == dev) 7892361Skre bp->b_flags |= B_INVAL; 7902299Skre } 791