1*383Sbill /* vfs_cluster.c 3.9 07/19/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 } 3428Sbill 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) */ 35391Sbill i = BUFHASH(dbtofsb(bp->b_blkno)); 35491Sbill x = bp - buf; 35591Sbill if (bufhash[i] == x) { 35691Sbill bufhash[i] = bp->b_hlink; 35791Sbill } else { 35891Sbill for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 35991Sbill ep = &buf[ep->b_hlink]) 36091Sbill if (ep->b_hlink == x) { 36191Sbill ep->b_hlink = bp->b_hlink; 36291Sbill goto done; 36391Sbill } 36491Sbill panic("getblk"); 36591Sbill } 36691Sbill done: 36791Sbill /* END INLINE EXPANSION */ 3688Sbill bp->b_flags = B_BUSY; 3698Sbill bp->b_back->b_forw = bp->b_forw; 3708Sbill bp->b_forw->b_back = bp->b_back; 3718Sbill bp->b_forw = dp->b_forw; 3728Sbill bp->b_back = dp; 3738Sbill dp->b_forw->b_back = bp; 3748Sbill dp->b_forw = bp; 3758Sbill bp->b_dev = dev; 3768Sbill bp->b_blkno = dblkno; 37791Sbill i = BUFHASH(blkno); 37891Sbill bp->b_hlink = bufhash[i]; 37991Sbill bufhash[i] = bp - buf; 3808Sbill return(bp); 3818Sbill } 3828Sbill 3838Sbill /* 3848Sbill * get an empty block, 3858Sbill * not assigned to any particular device 3868Sbill */ 3878Sbill struct buf * 3888Sbill geteblk() 3898Sbill { 390182Sbill register struct buf *bp, *dp; 3918Sbill 3928Sbill loop: 393124Sbill (void) spl6(); 3948Sbill while (bfreelist.av_forw == &bfreelist) { 3958Sbill bfreelist.b_flags |= B_WANTED; 3968Sbill sleep((caddr_t)&bfreelist, PRIBIO+1); 3978Sbill } 398124Sbill (void) spl0(); 3998Sbill dp = &bfreelist; 4008Sbill bp = bfreelist.av_forw; 4018Sbill notavail(bp); 4028Sbill if (bp->b_flags & B_DELWRI) { 4038Sbill bp->b_flags |= B_ASYNC; 4048Sbill bwrite(bp); 4058Sbill goto loop; 4068Sbill } 40791Sbill if (bp->b_dev != NODEV) 40891Sbill bunhash(bp); 4098Sbill bp->b_flags = B_BUSY; 4108Sbill bp->b_back->b_forw = bp->b_forw; 4118Sbill bp->b_forw->b_back = bp->b_back; 4128Sbill bp->b_forw = dp->b_forw; 4138Sbill bp->b_back = dp; 4148Sbill dp->b_forw->b_back = bp; 4158Sbill dp->b_forw = bp; 4168Sbill bp->b_dev = (dev_t)NODEV; 41791Sbill bp->b_hlink = -1; 4188Sbill return(bp); 4198Sbill } 4208Sbill 42191Sbill bunhash(bp) 42291Sbill register struct buf *bp; 42391Sbill { 42491Sbill register struct buf *ep; 42591Sbill register int i, x; 42691Sbill 42791Sbill if (bp->b_dev == NODEV) 42891Sbill return; 42991Sbill i = BUFHASH(dbtofsb(bp->b_blkno)); 43091Sbill x = bp - buf; 43191Sbill if (bufhash[i] == x) { 43291Sbill bufhash[i] = bp->b_hlink; 43391Sbill return; 43491Sbill } 43591Sbill for (ep = &buf[bufhash[i]]; ep != &buf[-1]; 43691Sbill ep = &buf[ep->b_hlink]) 43791Sbill if (ep->b_hlink == x) { 43891Sbill ep->b_hlink = bp->b_hlink; 43991Sbill return; 44091Sbill } 44191Sbill panic("bunhash"); 44291Sbill } 44391Sbill 4448Sbill /* 4458Sbill * Wait for I/O completion on the buffer; return errors 4468Sbill * to the user. 4478Sbill */ 4488Sbill iowait(bp) 4498Sbill register struct buf *bp; 4508Sbill { 4518Sbill 452124Sbill (void) spl6(); 4538Sbill while ((bp->b_flags&B_DONE)==0) 4548Sbill sleep((caddr_t)bp, PRIBIO); 455124Sbill (void) spl0(); 4568Sbill geterror(bp); 4578Sbill } 4588Sbill 4598Sbill #ifndef FASTVAX 4608Sbill /* 4618Sbill * Unlink a buffer from the available list and mark it busy. 4628Sbill * (internal interface) 4638Sbill */ 4648Sbill notavail(bp) 4658Sbill register struct buf *bp; 4668Sbill { 4678Sbill register s; 4688Sbill 4698Sbill s = spl6(); 4708Sbill bp->av_back->av_forw = bp->av_forw; 4718Sbill bp->av_forw->av_back = bp->av_back; 4728Sbill bp->b_flags |= B_BUSY; 4738Sbill splx(s); 4748Sbill } 4758Sbill #endif 4768Sbill 4778Sbill /* 4788Sbill * Mark I/O complete on a buffer. If the header 4798Sbill * indicates a dirty page push completion, the 4808Sbill * header is inserted into the ``cleaned'' list 4818Sbill * to be processed by the pageout daemon. Otherwise 4828Sbill * release it if I/O is asynchronous, and wake 4838Sbill * up anyone waiting for it. 4848Sbill */ 4858Sbill iodone(bp) 4868Sbill register struct buf *bp; 4878Sbill { 4888Sbill register int s; 4898Sbill 4908Sbill bp->b_flags |= B_DONE; 4918Sbill if (bp->b_flags & B_DIRTY) { 4928Sbill if (bp->b_flags & B_ERROR) 4938Sbill panic("IO err in push"); 4948Sbill s = spl6(); 4958Sbill cnt.v_pgout++; 4968Sbill bp->av_forw = bclnlist; 4978Sbill bp->b_bcount = swsize[bp - swbuf]; 4988Sbill bp->b_pfcent = swpf[bp - swbuf]; 4998Sbill bclnlist = bp; 5008Sbill if (bswlist.b_flags & B_WANTED) 5018Sbill wakeup((caddr_t)&proc[2]); 5028Sbill splx(s); 503*383Sbill return; 5048Sbill } 5058Sbill if (bp->b_flags&B_ASYNC) 5068Sbill brelse(bp); 5078Sbill else { 5088Sbill bp->b_flags &= ~B_WANTED; 5098Sbill wakeup((caddr_t)bp); 5108Sbill } 5118Sbill } 5128Sbill 5138Sbill /* 5148Sbill * Zero the core associated with a buffer. 5158Sbill */ 5168Sbill clrbuf(bp) 5178Sbill struct buf *bp; 5188Sbill { 5198Sbill register *p; 5208Sbill register c; 5218Sbill 5228Sbill p = bp->b_un.b_words; 5238Sbill c = BSIZE/sizeof(int); 5248Sbill do 5258Sbill *p++ = 0; 5268Sbill while (--c); 5278Sbill bp->b_resid = 0; 5288Sbill } 5298Sbill 5308Sbill /* 5318Sbill * swap I/O - 5328Sbill * 5338Sbill * If the flag indicates a dirty page push initiated 5348Sbill * by the pageout daemon, we map the page into the i th 5358Sbill * virtual page of process 2 (the daemon itself) where i is 5368Sbill * the index of the swap header that has been allocated. 5378Sbill * We simply initialize the header and queue the I/O but 5388Sbill * do not wait for completion. When the I/O completes, 5398Sbill * iodone() will link the header to a list of cleaned 5408Sbill * pages to be processed by the pageout daemon. 5418Sbill */ 5428Sbill swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent) 5438Sbill struct proc *p; 5448Sbill swblk_t dblkno; 5458Sbill caddr_t addr; 5468Sbill int flag, nbytes; 5478Sbill dev_t dev; 5488Sbill unsigned pfcent; 5498Sbill { 5508Sbill register struct buf *bp; 5518Sbill register int c; 5528Sbill int p2dp; 5538Sbill register struct pte *dpte, *vpte; 5548Sbill 555124Sbill (void) spl6(); 5568Sbill while (bswlist.av_forw == NULL) { 5578Sbill bswlist.b_flags |= B_WANTED; 5588Sbill sleep((caddr_t)&bswlist, PSWP+1); 5598Sbill } 5608Sbill bp = bswlist.av_forw; 5618Sbill bswlist.av_forw = bp->av_forw; 562124Sbill (void) spl0(); 5638Sbill 5648Sbill bp->b_flags = B_BUSY | B_PHYS | rdflg | flag; 5658Sbill if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0) 5668Sbill if (rdflg == B_READ) 5678Sbill sum.v_pswpin += btoc(nbytes); 5688Sbill else 5698Sbill sum.v_pswpout += btoc(nbytes); 5708Sbill bp->b_proc = p; 5718Sbill if (flag & B_DIRTY) { 5728Sbill p2dp = ((bp - swbuf) * CLSIZE) * KLMAX; 5738Sbill dpte = dptopte(&proc[2], p2dp); 5748Sbill vpte = vtopte(p, btop(addr)); 5758Sbill for (c = 0; c < nbytes; c += NBPG) { 5768Sbill if (vpte->pg_pfnum == 0 || vpte->pg_fod) 5778Sbill panic("swap bad pte"); 5788Sbill *dpte++ = *vpte++; 5798Sbill } 5808Sbill bp->b_un.b_addr = (caddr_t)ctob(p2dp); 5818Sbill } else 5828Sbill bp->b_un.b_addr = addr; 5838Sbill while (nbytes > 0) { 5848Sbill c = imin(ctob(120), nbytes); 5858Sbill bp->b_bcount = c; 5868Sbill bp->b_blkno = dblkno; 5878Sbill bp->b_dev = dev; 5888Sbill (*bdevsw[major(dev)].d_strategy)(bp); 5898Sbill if (flag & B_DIRTY) { 5908Sbill if (c < nbytes) 5918Sbill panic("big push"); 5928Sbill swsize[bp - swbuf] = nbytes; 5938Sbill swpf[bp - swbuf] = pfcent; 5948Sbill return; 5958Sbill } 596124Sbill (void) spl6(); 5978Sbill while((bp->b_flags&B_DONE)==0) 5988Sbill sleep((caddr_t)bp, PSWP); 599124Sbill (void) spl0(); 6008Sbill bp->b_un.b_addr += c; 6018Sbill bp->b_flags &= ~B_DONE; 6028Sbill if (bp->b_flags & B_ERROR) { 6038Sbill if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE) 6048Sbill panic("hard IO err in swap"); 6058Sbill swkill(p, (char *)0); 6068Sbill } 6078Sbill nbytes -= c; 6088Sbill dblkno += btoc(c); 6098Sbill } 610124Sbill (void) spl6(); 6118Sbill bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); 6128Sbill bp->av_forw = bswlist.av_forw; 6138Sbill bswlist.av_forw = bp; 6148Sbill if (bswlist.b_flags & B_WANTED) { 6158Sbill bswlist.b_flags &= ~B_WANTED; 6168Sbill wakeup((caddr_t)&bswlist); 6178Sbill wakeup((caddr_t)&proc[2]); 6188Sbill } 619124Sbill (void) spl0(); 6208Sbill } 6218Sbill 6228Sbill /* 6238Sbill * If rout == 0 then killed on swap error, else 6248Sbill * rout is the name of the routine where we ran out of 6258Sbill * swap space. 6268Sbill */ 6278Sbill swkill(p, rout) 6288Sbill struct proc *p; 6298Sbill char *rout; 6308Sbill { 6318Sbill 6328Sbill printf("%d: ", p->p_pid); 6338Sbill if (rout) 6348Sbill printf("out of swap space in %s\n", rout); 6358Sbill else 6368Sbill printf("killed on swap error\n"); 6378Sbill /* 6388Sbill * To be sure no looping (e.g. in vmsched trying to 6398Sbill * swap out) mark process locked in core (as though 6408Sbill * done by user) after killing it so noone will try 6418Sbill * to swap it out. 6428Sbill */ 643165Sbill psignal(p, SIGKILL); 6448Sbill p->p_flag |= SULOCK; 6458Sbill } 6468Sbill 6478Sbill /* 6488Sbill * make sure all write-behind blocks 6498Sbill * on dev (or NODEV for all) 6508Sbill * are flushed out. 6518Sbill * (from umount and update) 6528Sbill */ 6538Sbill bflush(dev) 6548Sbill dev_t dev; 6558Sbill { 6568Sbill register struct buf *bp; 6578Sbill 6588Sbill loop: 659124Sbill (void) spl6(); 6608Sbill for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) { 6618Sbill if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) { 6628Sbill bp->b_flags |= B_ASYNC; 6638Sbill notavail(bp); 6648Sbill bwrite(bp); 6658Sbill goto loop; 6668Sbill } 6678Sbill } 668124Sbill (void) spl0(); 6698Sbill } 6708Sbill 6718Sbill /* 6728Sbill * Raw I/O. The arguments are 6738Sbill * The strategy routine for the device 6748Sbill * A buffer, which will always be a special buffer 6758Sbill * header owned exclusively by the device for this purpose 6768Sbill * The device number 6778Sbill * Read/write flag 6788Sbill * Essentially all the work is computing physical addresses and 6798Sbill * validating them. 6808Sbill * If the user has the proper access privilidges, the process is 6818Sbill * marked 'delayed unlock' and the pages involved in the I/O are 6828Sbill * faulted and locked. After the completion of the I/O, the above pages 6838Sbill * are unlocked. 6848Sbill */ 6858Sbill physio(strat, bp, dev, rw, mincnt) 6868Sbill int (*strat)(); 6878Sbill register struct buf *bp; 6888Sbill unsigned (*mincnt)(); 6898Sbill { 6908Sbill register int c; 6918Sbill char *a; 6928Sbill 6938Sbill if (useracc(u.u_base,u.u_count,rw==B_READ?B_WRITE:B_READ) == NULL) { 6948Sbill u.u_error = EFAULT; 6958Sbill return; 6968Sbill } 697124Sbill (void) spl6(); 6988Sbill while (bp->b_flags&B_BUSY) { 6998Sbill bp->b_flags |= B_WANTED; 7008Sbill sleep((caddr_t)bp, PRIBIO+1); 7018Sbill } 7028Sbill bp->b_error = 0; 7038Sbill bp->b_proc = u.u_procp; 7048Sbill bp->b_un.b_addr = u.u_base; 7058Sbill while (u.u_count != 0 && bp->b_error==0) { 7068Sbill bp->b_flags = B_BUSY | B_PHYS | rw; 7078Sbill bp->b_dev = dev; 7088Sbill bp->b_blkno = u.u_offset >> PGSHIFT; 7098Sbill bp->b_bcount = u.u_count; 7108Sbill (*mincnt)(bp); 7118Sbill c = bp->b_bcount; 7128Sbill u.u_procp->p_flag |= SPHYSIO; 7138Sbill vslock(a = bp->b_un.b_addr, c); 7148Sbill (*strat)(bp); 715124Sbill (void) spl6(); 7168Sbill while ((bp->b_flags&B_DONE) == 0) 7178Sbill sleep((caddr_t)bp, PRIBIO); 7188Sbill vsunlock(a, c, rw); 7198Sbill u.u_procp->p_flag &= ~SPHYSIO; 7208Sbill if (bp->b_flags&B_WANTED) 7218Sbill wakeup((caddr_t)bp); 722124Sbill (void) spl0(); 7238Sbill bp->b_un.b_addr += c; 7248Sbill u.u_count -= c; 7258Sbill u.u_offset += c; 7268Sbill } 7278Sbill bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); 7288Sbill u.u_count = bp->b_resid; 7298Sbill geterror(bp); 7308Sbill } 7318Sbill 7328Sbill /*ARGSUSED*/ 7338Sbill unsigned 7348Sbill minphys(bp) 7358Sbill struct buf *bp; 7368Sbill { 7378Sbill 7388Sbill if (bp->b_bcount > 60 * 1024) 7398Sbill bp->b_bcount = 60 * 1024; 7408Sbill } 7418Sbill 7428Sbill /* 7438Sbill * Pick up the device's error number and pass it to the user; 7448Sbill * if there is an error but the number is 0 set a generalized 7458Sbill * code. Actually the latter is always true because devices 7468Sbill * don't yet return specific errors. 7478Sbill */ 7488Sbill geterror(bp) 7498Sbill register struct buf *bp; 7508Sbill { 7518Sbill 7528Sbill if (bp->b_flags&B_ERROR) 7538Sbill if ((u.u_error = bp->b_error)==0) 7548Sbill u.u_error = EIO; 7558Sbill } 756