- register int c;
- int p2dp;
- register struct pte *dpte, *vpte;
-
- (void) spl6();
- while (bswlist.av_forw == NULL) {
- bswlist.b_flags |= B_WANTED;
- sleep((caddr_t)&bswlist, PSWP+1);
- }
- bp = bswlist.av_forw;
- bswlist.av_forw = bp->av_forw;
- (void) spl0();
-
- bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
- if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
- if (rdflg == B_READ)
- sum.v_pswpin += btoc(nbytes);
- else
- sum.v_pswpout += btoc(nbytes);
- bp->b_proc = p;
- if (flag & B_DIRTY) {
- p2dp = ((bp - swbuf) * CLSIZE) * KLMAX;
- dpte = dptopte(&proc[2], p2dp);
- vpte = vtopte(p, btop(addr));
- for (c = 0; c < nbytes; c += NBPG) {
- if (vpte->pg_pfnum == 0 || vpte->pg_fod)
- panic("swap bad pte");
- *dpte++ = *vpte++;
- }
- bp->b_un.b_addr = (caddr_t)ctob(p2dp);
- } else
- bp->b_un.b_addr = addr;
- while (nbytes > 0) {
- c = imin(ctob(120), nbytes);
- bp->b_bcount = c;
- bp->b_blkno = dblkno;
- bp->b_dev = dev;
- if (flag & B_DIRTY) {
- swpf[bp - swbuf] = pfcent;
- swsize[bp - swbuf] = nbytes;
- }
- (*bdevsw[major(dev)].d_strategy)(bp);
- if (flag & B_DIRTY) {
- if (c < nbytes)
- panic("big push");
- return;
- }
- (void) spl6();
- while((bp->b_flags&B_DONE)==0)
- sleep((caddr_t)bp, PSWP);
- (void) spl0();
- bp->b_un.b_addr += c;
- bp->b_flags &= ~B_DONE;
- if (bp->b_flags & B_ERROR) {
- if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE)
- panic("hard IO err in swap");
- swkill(p, (char *)0);
+ struct buf *nbp;
+ int s;
+
+loop:
+ s = splbio();
+ for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
+ nbp = bp->b_blockf;
+ if ((bp->b_flags & B_BUSY))
+ continue;
+ if ((bp->b_flags & B_DELWRI) == 0)
+ panic("vflushbuf: not dirty");
+ bremfree(bp);
+ bp->b_flags |= B_BUSY;
+ splx(s);
+ /*
+ * Wait for I/O associated with indirect blocks to complete,
+ * since there is no way to quickly wait for them below.
+ * NB: This is really specific to ufs, but is done here
+ * as it is easier and quicker.
+ */
+ if (bp->b_vp == vp || (flags & B_SYNC) == 0) {
+ (void) bawrite(bp);
+ s = splbio();
+ } else {
+ (void) bwrite(bp);
+ goto loop;