1*1792Sbill /* vfs_cluster.c 4.2 11/10/80 */ 28Sbill 38Sbill #include "../h/param.h" 48Sbill #include "../h/systm.h" 58Sbill #include "../h/dir.h" 68Sbill #include "../h/user.h" 78Sbill #include "../h/buf.h" 88Sbill #include "../h/conf.h" 98Sbill #include "../h/proc.h" 108Sbill #include "../h/seg.h" 118Sbill #include "../h/pte.h" 128Sbill #include "../h/vm.h" 138Sbill 1491Sbill /* 1591Sbill * The following several routines allocate and free 1691Sbill * buffers with various side effects. In general the 1791Sbill * arguments to an allocate routine are a device and 1891Sbill * a block number, and the value is a pointer to 1991Sbill * to the buffer header; the buffer is marked "busy" 2091Sbill * so that no one else can touch it. If the block was 2191Sbill * already in core, no I/O need be done; if it is 2291Sbill * already busy, the process waits until it becomes free. 2391Sbill * The following routines allocate a buffer: 2491Sbill * getblk 2591Sbill * bread 2691Sbill * breada 2791Sbill * baddr (if it is incore) 2891Sbill * Eventually the buffer must be released, possibly with the 2991Sbill * side effect of writing it out, by using one of 3091Sbill * bwrite 3191Sbill * bdwrite 3291Sbill * bawrite 3391Sbill * brelse 3491Sbill */ 3591Sbill 3691Sbill #define BUFHSZ 63 3791Sbill #define BUFHASH(blkno) (blkno % BUFHSZ) 3891Sbill short bufhash[BUFHSZ]; 3991Sbill 4091Sbill /* 4191Sbill * Initialize hash links for buffers. 4291Sbill */ 4391Sbill bhinit() 4491Sbill { 4591Sbill register int i; 4691Sbill 4791Sbill for (i = 0; i < BUFHSZ; i++) 4891Sbill bufhash[i] = -1; 4991Sbill } 5091Sbill 518Sbill /* #define DISKMON 1 */ 528Sbill 538Sbill #ifdef DISKMON 548Sbill struct { 558Sbill int nbuf; 568Sbill long nread; 578Sbill long nreada; 588Sbill long ncache; 598Sbill long nwrite; 608Sbill long bufcount[NBUF]; 618Sbill } io_info; 628Sbill #endif 638Sbill 648Sbill /* 658Sbill * Swap IO headers - 668Sbill * They contain the necessary information for the swap I/O. 678Sbill * At any given time, a swap header can be in three 688Sbill * different lists. When free it is in the free list, 698Sbill * when allocated and the I/O queued, it is on the swap 708Sbill * device list, and finally, if the operation was a dirty 718Sbill * page push, when the I/O completes, it is inserted 728Sbill * in a list of cleaned pages to be processed by the pageout daemon. 738Sbill */ 748Sbill struct buf swbuf[NSWBUF]; 758Sbill short swsize[NSWBUF]; /* CAN WE JUST USE B_BCOUNT? */ 768Sbill int swpf[NSWBUF]; 778Sbill 788Sbill 798Sbill #ifdef FASTVAX 808Sbill #define notavail(bp) \ 818Sbill { \ 828Sbill int s = spl6(); \ 838Sbill (bp)->av_back->av_forw = (bp)->av_forw; \ 848Sbill (bp)->av_forw->av_back = (bp)->av_back; \ 858Sbill (bp)->b_flags |= B_BUSY; \ 868Sbill splx(s); \ 878Sbill } 888Sbill #endif 898Sbill 908Sbill /* 918Sbill * Read in (if necessary) the block and return a buffer pointer. 928Sbill */ 938Sbill struct buf * 948Sbill bread(dev, blkno) 958Sbill dev_t dev; 968Sbill daddr_t blkno; 978Sbill { 988Sbill register struct buf *bp; 998Sbill 1008Sbill bp = getblk(dev, blkno); 1018Sbill if (bp->b_flags&B_DONE) { 1028Sbill #ifdef DISKMON 1038Sbill io_info.ncache++; 1048Sbill #endif 1058Sbill return(bp); 1068Sbill } 1078Sbill bp->b_flags |= B_READ; 1088Sbill bp->b_bcount = BSIZE; 1098Sbill (*bdevsw[major(dev)].d_strategy)(bp); 1108Sbill #ifdef DISKMON 1118Sbill io_info.nread++; 1128Sbill #endif 1138Sbill u.u_vm.vm_inblk++; /* pay for read */ 1148Sbill iowait(bp); 1158Sbill return(bp); 1168Sbill } 1178Sbill 1188Sbill /* 1198Sbill * Read in the block, like bread, but also start I/O on the 1208Sbill * read-ahead block (which is not allocated to the caller) 1218Sbill */ 1228Sbill struct buf * 1238Sbill breada(dev, blkno, rablkno) 1248Sbill dev_t dev; 1258Sbill daddr_t blkno, rablkno; 1268Sbill { 1278Sbill register struct buf *bp, *rabp; 1288Sbill 1298Sbill bp = NULL; 1308Sbill if (!incore(dev, blkno)) { 1318Sbill bp = getblk(dev, blkno); 1328Sbill if ((bp->b_flags&B_DONE) == 0) { 1338Sbill bp->b_flags |= B_READ; 1348Sbill bp->b_bcount = BSIZE; 1358Sbill (*bdevsw[major(dev)].d_strategy)(bp); 1368Sbill #ifdef DISKMON 1378Sbill io_info.nread++; 1388Sbill #endif 1398Sbill u.u_vm.vm_inblk++; /* pay for read */ 1408Sbill } 1418Sbill } 1428Sbill if (rablkno && !incore(dev, rablkno)) { 1438Sbill rabp = getblk(dev, rablkno); 1448Sbill if (rabp->b_flags & B_DONE) 1458Sbill brelse(rabp); 1468Sbill else { 1478Sbill rabp->b_flags |= B_READ|B_ASYNC; 1488Sbill rabp->b_bcount = BSIZE; 1498Sbill (*bdevsw[major(dev)].d_strategy)(rabp); 1508Sbill #ifdef DISKMON 1518Sbill io_info.nreada++; 1528Sbill #endif 1538Sbill u.u_vm.vm_inblk++; /* pay in advance */ 1548Sbill } 1558Sbill } 1568Sbill if(bp == NULL) 1578Sbill return(bread(dev, blkno)); 1588Sbill iowait(bp); 1598Sbill return(bp); 1608Sbill } 1618Sbill 1628Sbill /* 1638Sbill * Write the buffer, waiting for completion. 1648Sbill * Then release the buffer. 1658Sbill */ 1668Sbill bwrite(bp) 1678Sbill register struct buf *bp; 1688Sbill { 1698Sbill register flag; 1708Sbill 1718Sbill flag = bp->b_flags; 1728Sbill bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE); 1738Sbill bp->b_bcount = BSIZE; 1748Sbill #ifdef DISKMON 1758Sbill io_info.nwrite++; 1768Sbill #endif 1778Sbill if ((flag&B_DELWRI) == 0) 1788Sbill u.u_vm.vm_oublk++; /* noone paid yet */ 1798Sbill (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 1808Sbill if ((flag&B_ASYNC) == 0) { 1818Sbill iowait(bp); 1828Sbill brelse(bp); 1838Sbill } else if (flag & B_DELWRI) 1848Sbill bp->b_flags |= B_AGE; 1858Sbill else 1868Sbill geterror(bp); 1878Sbill } 1888Sbill 1898Sbill /* 1908Sbill * Release the buffer, marking it so that if it is grabbed 1918Sbill * for another purpose it will be written out before being 1928Sbill * given up (e.g. when writing a partial block where it is 1938Sbill * assumed that another write for the same block will soon follow). 1948Sbill * This can't be done for magtape, since writes must be done 1958Sbill * in the same order as requested. 1968Sbill */ 1978Sbill bdwrite(bp) 1988Sbill register struct buf *bp; 1998Sbill { 2008Sbill register struct buf *dp; 2018Sbill 2028Sbill if ((bp->b_flags&B_DELWRI) == 0) 2038Sbill u.u_vm.vm_oublk++; /* noone paid yet */ 2048Sbill dp = bdevsw[major(bp->b_dev)].d_tab; 2058Sbill if(dp->b_flags & B_TAPE) 2068Sbill bawrite(bp); 2078Sbill else { 2088Sbill bp->b_flags |= B_DELWRI | B_DONE; 2098Sbill brelse(bp); 2108Sbill } 2118Sbill } 2128Sbill 2138Sbill /* 2148Sbill * Release the buffer, start I/O on it, but don't wait for completion. 2158Sbill */ 2168Sbill bawrite(bp) 2178Sbill register struct buf *bp; 2188Sbill { 2198Sbill 2208Sbill bp->b_flags |= B_ASYNC; 2218Sbill bwrite(bp); 2228Sbill } 2238Sbill 2248Sbill /* 2258Sbill * release the buffer, with no I/O implied. 2268Sbill */ 2278Sbill brelse(bp) 2288Sbill register struct buf *bp; 2298Sbill { 2308Sbill register struct buf **backp; 2318Sbill register s; 2328Sbill 2338Sbill if (bp->b_flags&B_WANTED) 2348Sbill wakeup((caddr_t)bp); 2358Sbill if (bfreelist.b_flags&B_WANTED) { 2368Sbill bfreelist.b_flags &= ~B_WANTED; 2378Sbill wakeup((caddr_t)&bfreelist); 2388Sbill } 23991Sbill if ((bp->b_flags&B_ERROR) && bp->b_dev != NODEV) { 24091Sbill bunhash(bp); 2418Sbill bp->b_dev = NODEV; /* no assoc. on error */ 24291Sbill } 2438Sbill s = spl6(); 2448Sbill if(bp->b_flags & (B_AGE|B_ERROR)) { 2458Sbill backp = &bfreelist.av_forw; 2468Sbill (*backp)->av_back = bp; 2478Sbill bp->av_forw = *backp; 2488Sbill *backp = bp; 2498Sbill bp->av_back = &bfreelist; 2508Sbill } else { 2518Sbill backp = &bfreelist.av_back; 2528Sbill (*backp)->av_forw = bp; 2538Sbill bp->av_back = *backp; 2548Sbill *backp = bp; 2558Sbill bp->av_forw = &bfreelist; 2568Sbill } 2578Sbill bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); 2588Sbill splx(s); 2598Sbill } 2608Sbill 2618Sbill /* 2628Sbill * See if the block is associated with some buffer 2638Sbill * (mainly to avoid getting hung up on a wait in breada) 2648Sbill */ 2658Sbill incore(dev, blkno) 2668Sbill dev_t dev; 2678Sbill daddr_t blkno; 2688Sbill { 2698Sbill register struct buf *bp; 2708Sbill register int dblkno = fsbtodb(blkno); 2718Sbill 27291Sbill for (bp = &buf[bufhash[BUFHASH(blkno)]]; bp != &buf[-1]; 27391Sbill bp = &buf[bp->b_hlink]) 27495Sbill if (bp->b_blkno == dblkno && bp->b_dev == dev) 27591Sbill return (1); 27691Sbill return (0); 2778Sbill } 2788Sbill 2798Sbill struct buf * 2808Sbill baddr(dev, blkno) 2818Sbill dev_t dev; 2828Sbill daddr_t blkno; 2838Sbill { 2848Sbill 2858Sbill if (incore(dev, blkno)) 2868Sbill return (bread(dev, blkno)); 2878Sbill return (0); 2888Sbill } 2898Sbill 2908Sbill /* 2918Sbill * Assign a buffer for the given block. If the appropriate 2928Sbill * block is already associated, return it; otherwise search 2938Sbill * for the oldest non-busy buffer and reassign it. 2948Sbill */ 2958Sbill struct buf * 2968Sbill getblk(dev, blkno) 2978Sbill dev_t dev; 2988Sbill daddr_t blkno; 2998Sbill { 30091Sbill register struct buf *bp, *dp, *ep; 30191Sbill register int i, x; 3028Sbill register int dblkno = fsbtodb(blkno); 3038Sbill 3048Sbill loop: 305124Sbill (void) spl0(); 30691Sbill for (bp = &buf[bufhash[BUFHASH(blkno)]]; bp != &buf[-1]; 30791Sbill bp = &buf[bp->b_hlink]) { 30891Sbill if (bp->b_blkno != dblkno || bp->b_dev != dev) 3098Sbill continue; 310124Sbill (void) spl6(); 3118Sbill if (bp->b_flags&B_BUSY) { 3128Sbill bp->b_flags |= B_WANTED; 3138Sbill sleep((caddr_t)bp, PRIBIO+1); 3148Sbill goto loop; 3158Sbill } 316124Sbill (void) spl0(); 3178Sbill #ifdef DISKMON 3188Sbill i = 0; 3198Sbill dp = bp->av_forw; 3208Sbill while (dp != &bfreelist) { 3218Sbill i++; 3228Sbill dp = dp->av_forw; 3238Sbill } 3248Sbill if (i<NBUF) 3258Sbill io_info.bufcount[i]++; 3268Sbill #endif 3278Sbill notavail(bp); 3288Sbill bp->b_flags |= B_CACHE; 3298Sbill return(bp); 3308Sbill } 33191Sbill if (major(dev) >= nblkdev) 33291Sbill panic("blkdev"); 33391Sbill dp = bdevsw[major(dev)].d_tab; 33491Sbill if (dp == NULL) 33591Sbill panic("devtab"); 336124Sbill (void) spl6(); 3378Sbill if (bfreelist.av_forw == &bfreelist) { 3388Sbill bfreelist.b_flags |= B_WANTED; 3398Sbill sleep((caddr_t)&bfreelist, PRIBIO+1); 3408Sbill goto loop; 3418Sbill } 342*1792Sbill (void) spl0(); 3438Sbill bp = bfreelist.av_forw; 3448Sbill notavail(bp); 3458Sbill if (bp->b_flags & B_DELWRI) { 3468Sbill bp->b_flags |= B_ASYNC; 3478Sbill bwrite(bp); 3488Sbill goto loop; 3498Sbill } 35091Sbill if (bp->b_dev == NODEV) 35191Sbill goto done; 35291Sbill /* INLINE EXPANSION OF bunhash(bp) */ 353884Sbill (void) spl6(); 35491Sbill i = BUFHASH(dbtofsb(bp->b_blkno)); 35591Sbill x = bp - buf; 35691Sbill if (bufhash[i] == x) { 35791Sbill bufhash[i] = bp->b_hlink; 35891Sbill } else { 35991Sbill for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 36091Sbill ep = &buf[ep->b_hlink]) 36191Sbill if (ep->b_hlink == x) { 36291Sbill ep->b_hlink = bp->b_hlink; 36391Sbill goto done; 36491Sbill } 36591Sbill panic("getblk"); 36691Sbill } 36791Sbill done: 368884Sbill (void) spl0(); 36991Sbill /* END INLINE EXPANSION */ 3708Sbill bp->b_flags = B_BUSY; 3718Sbill bp->b_back->b_forw = bp->b_forw; 3728Sbill bp->b_forw->b_back = bp->b_back; 3738Sbill bp->b_forw = dp->b_forw; 3748Sbill bp->b_back = dp; 3758Sbill dp->b_forw->b_back = bp; 3768Sbill dp->b_forw = bp; 3778Sbill bp->b_dev = dev; 3788Sbill bp->b_blkno = dblkno; 37991Sbill i = BUFHASH(blkno); 38091Sbill bp->b_hlink = bufhash[i]; 38191Sbill bufhash[i] = bp - buf; 3828Sbill return(bp); 3838Sbill } 3848Sbill 3858Sbill /* 3868Sbill * get an empty block, 3878Sbill * not assigned to any particular device 3888Sbill */ 3898Sbill struct buf * 3908Sbill geteblk() 3918Sbill { 392182Sbill register struct buf *bp, *dp; 3938Sbill 3948Sbill loop: 395124Sbill (void) spl6(); 3968Sbill while (bfreelist.av_forw == &bfreelist) { 3978Sbill bfreelist.b_flags |= B_WANTED; 3988Sbill sleep((caddr_t)&bfreelist, PRIBIO+1); 3998Sbill } 400124Sbill (void) spl0(); 4018Sbill dp = &bfreelist; 4028Sbill bp = bfreelist.av_forw; 4038Sbill notavail(bp); 4048Sbill if (bp->b_flags & B_DELWRI) { 4058Sbill bp->b_flags |= B_ASYNC; 4068Sbill bwrite(bp); 4078Sbill goto loop; 4088Sbill } 40991Sbill if (bp->b_dev != NODEV) 41091Sbill bunhash(bp); 4118Sbill bp->b_flags = B_BUSY; 4128Sbill bp->b_back->b_forw = bp->b_forw; 4138Sbill bp->b_forw->b_back = bp->b_back; 4148Sbill bp->b_forw = dp->b_forw; 4158Sbill bp->b_back = dp; 4168Sbill dp->b_forw->b_back = bp; 4178Sbill dp->b_forw = bp; 4188Sbill bp->b_dev = (dev_t)NODEV; 41991Sbill bp->b_hlink = -1; 4208Sbill return(bp); 4218Sbill } 4228Sbill 42391Sbill bunhash(bp) 42491Sbill register struct buf *bp; 42591Sbill { 42691Sbill register struct buf *ep; 427884Sbill register int i, x, s; 42891Sbill 42991Sbill if (bp->b_dev == NODEV) 43091Sbill return; 431884Sbill s = spl6(); 43291Sbill i = BUFHASH(dbtofsb(bp->b_blkno)); 43391Sbill x = bp - buf; 43491Sbill if (bufhash[i] == x) { 43591Sbill bufhash[i] = bp->b_hlink; 436884Sbill goto ret; 43791Sbill } 43891Sbill for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 43991Sbill ep = &buf[ep->b_hlink]) 44091Sbill if (ep->b_hlink == x) { 44191Sbill ep->b_hlink = bp->b_hlink; 442884Sbill goto ret; 44391Sbill } 44491Sbill panic("bunhash"); 445884Sbill ret: 446884Sbill splx(s); 44791Sbill } 44891Sbill 4498Sbill /* 4508Sbill * Wait for I/O completion on the buffer; return errors 4518Sbill * to the user. 4528Sbill */ 4538Sbill iowait(bp) 4548Sbill register struct buf *bp; 4558Sbill { 4568Sbill 457124Sbill (void) spl6(); 4588Sbill while ((bp->b_flags&B_DONE)==0) 4598Sbill sleep((caddr_t)bp, PRIBIO); 460124Sbill (void) spl0(); 4618Sbill geterror(bp); 4628Sbill } 4638Sbill 4648Sbill #ifndef FASTVAX 4658Sbill /* 4668Sbill * Unlink a buffer from the available list and mark it busy. 4678Sbill * (internal interface) 4688Sbill */ 4698Sbill notavail(bp) 4708Sbill register struct buf *bp; 4718Sbill { 4728Sbill register s; 4738Sbill 4748Sbill s = spl6(); 4758Sbill bp->av_back->av_forw = bp->av_forw; 4768Sbill bp->av_forw->av_back = bp->av_back; 4778Sbill bp->b_flags |= B_BUSY; 4788Sbill splx(s); 4798Sbill } 4808Sbill #endif 4818Sbill 4828Sbill /* 4838Sbill * Mark I/O complete on a buffer. If the header 4848Sbill * indicates a dirty page push completion, the 4858Sbill * header is inserted into the ``cleaned'' list 4868Sbill * to be processed by the pageout daemon. Otherwise 4878Sbill * release it if I/O is asynchronous, and wake 4888Sbill * up anyone waiting for it. 4898Sbill */ 4908Sbill iodone(bp) 4918Sbill register struct buf *bp; 4928Sbill { 4938Sbill register int s; 4948Sbill 495420Sbill if (bp->b_flags & B_DONE) 496420Sbill panic("dup iodone"); 4978Sbill bp->b_flags |= B_DONE; 4988Sbill if (bp->b_flags & B_DIRTY) { 4998Sbill if (bp->b_flags & B_ERROR) 5008Sbill panic("IO err in push"); 5018Sbill s = spl6(); 5028Sbill cnt.v_pgout++; 5038Sbill bp->av_forw = bclnlist; 5048Sbill bp->b_bcount = swsize[bp - swbuf]; 5058Sbill bp->b_pfcent = swpf[bp - swbuf]; 5068Sbill bclnlist = bp; 5078Sbill if (bswlist.b_flags & B_WANTED) 5088Sbill wakeup((caddr_t)&proc[2]); 5098Sbill splx(s); 510383Sbill return; 5118Sbill } 5128Sbill if (bp->b_flags&B_ASYNC) 5138Sbill brelse(bp); 5148Sbill else { 5158Sbill bp->b_flags &= ~B_WANTED; 5168Sbill wakeup((caddr_t)bp); 5178Sbill } 5188Sbill } 5198Sbill 5208Sbill /* 5218Sbill * Zero the core associated with a buffer. 5228Sbill */ 5238Sbill clrbuf(bp) 5248Sbill struct buf *bp; 5258Sbill { 5268Sbill register *p; 5278Sbill register c; 5288Sbill 5298Sbill p = bp->b_un.b_words; 5308Sbill c = BSIZE/sizeof(int); 5318Sbill do 5328Sbill *p++ = 0; 5338Sbill while (--c); 5348Sbill bp->b_resid = 0; 5358Sbill } 5368Sbill 5378Sbill /* 5388Sbill * swap I/O - 5398Sbill * 5408Sbill * If the flag indicates a dirty page push initiated 5418Sbill * by the pageout daemon, we map the page into the i th 5428Sbill * virtual page of process 2 (the daemon itself) where i is 5438Sbill * the index of the swap header that has been allocated. 5448Sbill * We simply initialize the header and queue the I/O but 5458Sbill * do not wait for completion. When the I/O completes, 5468Sbill * iodone() will link the header to a list of cleaned 5478Sbill * pages to be processed by the pageout daemon. 5488Sbill */ 5498Sbill swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent) 5508Sbill struct proc *p; 5518Sbill swblk_t dblkno; 5528Sbill caddr_t addr; 5538Sbill int flag, nbytes; 5548Sbill dev_t dev; 5558Sbill unsigned pfcent; 5568Sbill { 5578Sbill register struct buf *bp; 5588Sbill register int c; 5598Sbill int p2dp; 5608Sbill register struct pte *dpte, *vpte; 5618Sbill 562124Sbill (void) spl6(); 5638Sbill while (bswlist.av_forw == NULL) { 5648Sbill bswlist.b_flags |= B_WANTED; 5658Sbill sleep((caddr_t)&bswlist, PSWP+1); 5668Sbill } 5678Sbill bp = bswlist.av_forw; 5688Sbill bswlist.av_forw = bp->av_forw; 569124Sbill (void) spl0(); 5708Sbill 5718Sbill bp->b_flags = B_BUSY | B_PHYS | rdflg | flag; 5728Sbill if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0) 5738Sbill if (rdflg == B_READ) 5748Sbill sum.v_pswpin += btoc(nbytes); 5758Sbill else 5768Sbill sum.v_pswpout += btoc(nbytes); 5778Sbill bp->b_proc = p; 5788Sbill if (flag & B_DIRTY) { 5798Sbill p2dp = ((bp - swbuf) * CLSIZE) * KLMAX; 5808Sbill dpte = dptopte(&proc[2], p2dp); 5818Sbill vpte = vtopte(p, btop(addr)); 5828Sbill for (c = 0; c < nbytes; c += NBPG) { 5838Sbill if (vpte->pg_pfnum == 0 || vpte->pg_fod) 5848Sbill panic("swap bad pte"); 5858Sbill *dpte++ = *vpte++; 5868Sbill } 5878Sbill bp->b_un.b_addr = (caddr_t)ctob(p2dp); 5888Sbill } else 5898Sbill bp->b_un.b_addr = addr; 5908Sbill while (nbytes > 0) { 5918Sbill c = imin(ctob(120), nbytes); 5928Sbill bp->b_bcount = c; 5938Sbill bp->b_blkno = dblkno; 5948Sbill bp->b_dev = dev; 595718Sbill if (flag & B_DIRTY) { 596718Sbill swpf[bp - swbuf] = pfcent; 597718Sbill swsize[bp - swbuf] = nbytes; 598718Sbill } 5998Sbill (*bdevsw[major(dev)].d_strategy)(bp); 6008Sbill if (flag & B_DIRTY) { 6018Sbill if (c < nbytes) 6028Sbill panic("big push"); 6038Sbill return; 6048Sbill } 605124Sbill (void) spl6(); 6068Sbill while((bp->b_flags&B_DONE)==0) 6078Sbill sleep((caddr_t)bp, PSWP); 608124Sbill (void) spl0(); 6098Sbill bp->b_un.b_addr += c; 6108Sbill bp->b_flags &= ~B_DONE; 6118Sbill if (bp->b_flags & B_ERROR) { 6128Sbill if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE) 6138Sbill panic("hard IO err in swap"); 6148Sbill swkill(p, (char *)0); 6158Sbill } 6168Sbill nbytes -= c; 6178Sbill dblkno += btoc(c); 6188Sbill } 619124Sbill (void) spl6(); 6208Sbill bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); 6218Sbill bp->av_forw = bswlist.av_forw; 6228Sbill bswlist.av_forw = bp; 6238Sbill if (bswlist.b_flags & B_WANTED) { 6248Sbill bswlist.b_flags &= ~B_WANTED; 6258Sbill wakeup((caddr_t)&bswlist); 6268Sbill wakeup((caddr_t)&proc[2]); 6278Sbill } 628124Sbill (void) spl0(); 6298Sbill } 6308Sbill 6318Sbill /* 6328Sbill * If rout == 0 then killed on swap error, else 6338Sbill * rout is the name of the routine where we ran out of 6348Sbill * swap space. 6358Sbill */ 6368Sbill swkill(p, rout) 6378Sbill struct proc *p; 6388Sbill char *rout; 6398Sbill { 6408Sbill 6418Sbill printf("%d: ", p->p_pid); 6428Sbill if (rout) 6438Sbill printf("out of swap space in %s\n", rout); 6448Sbill else 6458Sbill printf("killed on swap error\n"); 6468Sbill /* 6478Sbill * To be sure no looping (e.g. in vmsched trying to 6488Sbill * swap out) mark process locked in core (as though 6498Sbill * done by user) after killing it so noone will try 6508Sbill * to swap it out. 6518Sbill */ 652165Sbill psignal(p, SIGKILL); 6538Sbill p->p_flag |= SULOCK; 6548Sbill } 6558Sbill 6568Sbill /* 6578Sbill * make sure all write-behind blocks 6588Sbill * on dev (or NODEV for all) 6598Sbill * are flushed out. 6608Sbill * (from umount and update) 6618Sbill */ 6628Sbill bflush(dev) 6638Sbill dev_t dev; 6648Sbill { 6658Sbill register struct buf *bp; 6668Sbill 6678Sbill loop: 668124Sbill (void) spl6(); 6698Sbill for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) { 6708Sbill if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) { 6718Sbill bp->b_flags |= B_ASYNC; 6728Sbill notavail(bp); 6738Sbill bwrite(bp); 6748Sbill goto loop; 6758Sbill } 6768Sbill } 677124Sbill (void) spl0(); 6788Sbill } 6798Sbill 6808Sbill /* 6818Sbill * Raw I/O. The arguments are 6828Sbill * The strategy routine for the device 6838Sbill * A buffer, which will always be a special buffer 6848Sbill * header owned exclusively by the device for this purpose 6858Sbill * The device number 6868Sbill * Read/write flag 6878Sbill * Essentially all the work is computing physical addresses and 6888Sbill * validating them. 6898Sbill * If the user has the proper access privilidges, the process is 6908Sbill * marked 'delayed unlock' and the pages involved in the I/O are 6918Sbill * faulted and locked. After the completion of the I/O, the above pages 6928Sbill * are unlocked. 6938Sbill */ 6948Sbill physio(strat, bp, dev, rw, mincnt) 6958Sbill int (*strat)(); 6968Sbill register struct buf *bp; 6978Sbill unsigned (*mincnt)(); 6988Sbill { 6998Sbill register int c; 7008Sbill char *a; 7018Sbill 7028Sbill if (useracc(u.u_base,u.u_count,rw==B_READ?B_WRITE:B_READ) == NULL) { 7038Sbill u.u_error = EFAULT; 7048Sbill return; 7058Sbill } 706124Sbill (void) spl6(); 7078Sbill while (bp->b_flags&B_BUSY) { 7088Sbill bp->b_flags |= B_WANTED; 7098Sbill sleep((caddr_t)bp, PRIBIO+1); 7108Sbill } 7118Sbill bp->b_error = 0; 7128Sbill bp->b_proc = u.u_procp; 7138Sbill bp->b_un.b_addr = u.u_base; 7148Sbill while (u.u_count != 0 && bp->b_error==0) { 7158Sbill bp->b_flags = B_BUSY | B_PHYS | rw; 7168Sbill bp->b_dev = dev; 7178Sbill bp->b_blkno = u.u_offset >> PGSHIFT; 7188Sbill bp->b_bcount = u.u_count; 7198Sbill (*mincnt)(bp); 7208Sbill c = bp->b_bcount; 7218Sbill u.u_procp->p_flag |= SPHYSIO; 7228Sbill vslock(a = bp->b_un.b_addr, c); 7238Sbill (*strat)(bp); 724124Sbill (void) spl6(); 7258Sbill while ((bp->b_flags&B_DONE) == 0) 7268Sbill sleep((caddr_t)bp, PRIBIO); 7278Sbill vsunlock(a, c, rw); 7288Sbill u.u_procp->p_flag &= ~SPHYSIO; 7298Sbill if (bp->b_flags&B_WANTED) 7308Sbill wakeup((caddr_t)bp); 731124Sbill (void) spl0(); 7328Sbill bp->b_un.b_addr += c; 7338Sbill u.u_count -= c; 7348Sbill u.u_offset += c; 7358Sbill } 7368Sbill bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); 7378Sbill u.u_count = bp->b_resid; 7388Sbill geterror(bp); 7398Sbill } 7408Sbill 7418Sbill /*ARGSUSED*/ 7428Sbill unsigned 7438Sbill minphys(bp) 7448Sbill struct buf *bp; 7458Sbill { 7468Sbill 7478Sbill if (bp->b_bcount > 60 * 1024) 7488Sbill bp->b_bcount = 60 * 1024; 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) 7588Sbill register struct buf *bp; 7598Sbill { 7608Sbill 7618Sbill if (bp->b_flags&B_ERROR) 7628Sbill if ((u.u_error = bp->b_error)==0) 7638Sbill u.u_error = EIO; 7648Sbill } 765