early non-blocking stuff
[unix-history] / usr / src / sys / kern / vfs_cluster.c
index 1951dc3..a1a6ddf 100644 (file)
@@ -1,4 +1,4 @@
-/*     vfs_cluster.c   3.1     %H%     */
+/*     vfs_cluster.c   4.23    81/07/25        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/seg.h"
 #include "../h/pte.h"
 #include "../h/vm.h"
 #include "../h/seg.h"
 #include "../h/pte.h"
 #include "../h/vm.h"
+#include "../h/trace.h"
+
+/*
+ * The following several routines allocate and free
+ * buffers with various side effects.  In general the
+ * arguments to an allocate routine are a device and
+ * a block number, and the value is a pointer to
+ * to the buffer header; the buffer is marked "busy"
+ * so that no one else can touch it.  If the block was
+ * already in core, no I/O need be done; if it is
+ * already busy, the process waits until it becomes free.
+ * The following routines allocate a buffer:
+ *     getblk
+ *     bread
+ *     breada
+ *     baddr   (if it is incore)
+ * Eventually the buffer must be released, possibly with the
+ * side effect of writing it out, by using one of
+ *     bwrite
+ *     bdwrite
+ *     bawrite
+ *     brelse
+ */
+
+struct buf bfreelist[BQUEUES];
+struct buf bswlist, *bclnlist;
+
+#define        BUFHSZ  63
+struct bufhd bufhash[BUFHSZ];
+#define        BUFHASH(dev, dblkno)    \
+               ((struct buf *)&bufhash[((int)(dev)+(int)(dblkno)) % BUFHSZ])
+
+/*
+ * Initialize hash links for buffers.
+ */
+bhinit()
+{
+       register int i;
+       register struct bufhd *bp;
+
+       for (bp = bufhash, i = 0; i < BUFHSZ; i++, bp++)
+               bp->b_forw = bp->b_back = (struct buf *)bp;
+}
 
 /* #define     DISKMON 1 */
 
 
 /* #define     DISKMON 1 */
 
@@ -20,7 +63,7 @@ struct {
        long    nreada;
        long    ncache;
        long    nwrite;
        long    nreada;
        long    ncache;
        long    nwrite;
-       long    bufcount[NBUF];
+       long    bufcount[64];
 } io_info;
 #endif
 
 } io_info;
 #endif
 
@@ -34,33 +77,12 @@ struct {
  * page push, when the I/O completes, it is inserted 
  * in a list of cleaned pages to be processed by the pageout daemon.
  */
  * page push, when the I/O completes, it is inserted 
  * in a list of cleaned pages to be processed by the pageout daemon.
  */
-struct buf swbuf[NSWBUF];
-short  swsize[NSWBUF];         /* CAN WE JUST USE B_BCOUNT? */
-int    swpf[NSWBUF];
+struct buf *swbuf;
+short  *swsize;                /* CAN WE JUST USE B_BCOUNT? */
+int    *swpf;
 
 
-/*
- * The following several routines allocate and free
- * buffers with various side effects.  In general the
- * arguments to an allocate routine are a device and
- * a block number, and the value is a pointer to
- * to the buffer header; the buffer is marked "busy"
- * so that no one else can touch it.  If the block was
- * already in core, no I/O need be done; if it is
- * already busy, the process waits until it becomes free.
- * The following routines allocate a buffer:
- *     getblk
- *     bread
- *     breada
- *     baddr   (if it is incore)
- * Eventually the buffer must be released, possibly with the
- * side effect of writing it out, by using one of
- *     bwrite
- *     bdwrite
- *     bawrite
- *     brelse
- */
 
 
-#ifdef FASTVAX
+#ifndef        UNFAST
 #define        notavail(bp) \
 { \
        int s = spl6(); \
 #define        notavail(bp) \
 { \
        int s = spl6(); \
@@ -83,6 +105,9 @@ daddr_t blkno;
 
        bp = getblk(dev, blkno);
        if (bp->b_flags&B_DONE) {
 
        bp = getblk(dev, blkno);
        if (bp->b_flags&B_DONE) {
+#ifdef TRACE
+               trace(TR_BREADHIT, dev, blkno);
+#endif
 #ifdef DISKMON
                io_info.ncache++;
 #endif
 #ifdef DISKMON
                io_info.ncache++;
 #endif
@@ -91,6 +116,9 @@ daddr_t blkno;
        bp->b_flags |= B_READ;
        bp->b_bcount = BSIZE;
        (*bdevsw[major(dev)].d_strategy)(bp);
        bp->b_flags |= B_READ;
        bp->b_bcount = BSIZE;
        (*bdevsw[major(dev)].d_strategy)(bp);
+#ifdef TRACE
+       trace(TR_BREADMISS, dev, blkno);
+#endif
 #ifdef DISKMON
        io_info.nread++;
 #endif
 #ifdef DISKMON
        io_info.nread++;
 #endif
@@ -117,20 +145,33 @@ daddr_t blkno, rablkno;
                        bp->b_flags |= B_READ;
                        bp->b_bcount = BSIZE;
                        (*bdevsw[major(dev)].d_strategy)(bp);
                        bp->b_flags |= B_READ;
                        bp->b_bcount = BSIZE;
                        (*bdevsw[major(dev)].d_strategy)(bp);
+#ifdef TRACE
+                       trace(TR_BREADMISS, dev, blkno);
+#endif
 #ifdef DISKMON
                        io_info.nread++;
 #endif
                        u.u_vm.vm_inblk++;              /* pay for read */
                }
 #ifdef DISKMON
                        io_info.nread++;
 #endif
                        u.u_vm.vm_inblk++;              /* pay for read */
                }
+#ifdef TRACE
+               else
+                       trace(TR_BREADHIT, dev, blkno);
+#endif
        }
        if (rablkno && !incore(dev, rablkno)) {
                rabp = getblk(dev, rablkno);
        }
        if (rablkno && !incore(dev, rablkno)) {
                rabp = getblk(dev, rablkno);
-               if (rabp->b_flags & B_DONE)
+               if (rabp->b_flags & B_DONE) {
                        brelse(rabp);
                        brelse(rabp);
-               else {
+#ifdef TRACE
+                       trace(TR_BREADHITRA, dev, blkno);
+#endif
+               } else {
                        rabp->b_flags |= B_READ|B_ASYNC;
                        rabp->b_bcount = BSIZE;
                        (*bdevsw[major(dev)].d_strategy)(rabp);
                        rabp->b_flags |= B_READ|B_ASYNC;
                        rabp->b_bcount = BSIZE;
                        (*bdevsw[major(dev)].d_strategy)(rabp);
+#ifdef TRACE
+                       trace(TR_BREADMISSRA, dev, rablock);
+#endif
 #ifdef DISKMON
                        io_info.nreada++;
 #endif
 #ifdef DISKMON
                        io_info.nreada++;
 #endif
@@ -160,6 +201,9 @@ register struct buf *bp;
 #endif
        if ((flag&B_DELWRI) == 0)
                u.u_vm.vm_oublk++;              /* noone paid yet */
 #endif
        if ((flag&B_DELWRI) == 0)
                u.u_vm.vm_oublk++;              /* noone paid yet */
+#ifdef TRACE
+       trace(TR_BWRITE, bp->b_dev, bp->b_blkno);
+#endif
        (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
        if ((flag&B_ASYNC) == 0) {
                iowait(bp);
        (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
        if ((flag&B_ASYNC) == 0) {
                iowait(bp);
@@ -181,12 +225,12 @@ register struct buf *bp;
 bdwrite(bp)
 register struct buf *bp;
 {
 bdwrite(bp)
 register struct buf *bp;
 {
-       register struct buf *dp;
+       register int flags;
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_vm.vm_oublk++;              /* noone paid yet */
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_vm.vm_oublk++;              /* noone paid yet */
-       dp = bdevsw[major(bp->b_dev)].d_tab;
-       if(dp->b_flags & B_TAPE)
+       flags = bdevsw[major(bp->b_dev)].d_flags;
+       if(flags & B_TAPE)
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
@@ -211,30 +255,39 @@ register struct buf *bp;
 brelse(bp)
 register struct buf *bp;
 {
 brelse(bp)
 register struct buf *bp;
 {
-       register struct buf **backp;
+       register struct buf *flist;
        register s;
 
        if (bp->b_flags&B_WANTED)
                wakeup((caddr_t)bp);
        register s;
 
        if (bp->b_flags&B_WANTED)
                wakeup((caddr_t)bp);
-       if (bfreelist.b_flags&B_WANTED) {
-               bfreelist.b_flags &= ~B_WANTED;
-               wakeup((caddr_t)&bfreelist);
+       if (bfreelist[0].b_flags&B_WANTED) {
+               bfreelist[0].b_flags &= ~B_WANTED;
+               wakeup((caddr_t)bfreelist);
        }
        if (bp->b_flags&B_ERROR)
        }
        if (bp->b_flags&B_ERROR)
-               bp->b_dev = NODEV;  /* no assoc. on error */
+               if (bp->b_flags & B_LOCKED)
+                       bp->b_flags &= ~B_ERROR;        /* try again later */
+               else
+                       bp->b_dev = NODEV;              /* no assoc */
        s = spl6();
        s = spl6();
-       if(bp->b_flags & (B_AGE|B_ERROR)) {
-               backp = &bfreelist.av_forw;
-               (*backp)->av_back = bp;
-               bp->av_forw = *backp;
-               *backp = bp;
-               bp->av_back = &bfreelist;
+       if (bp->b_flags & (B_ERROR|B_INVAL)) {
+               /* block has no info ... put at front of most free list */
+               flist = &bfreelist[BQUEUES-1];
+               flist->av_forw->av_back = bp;
+               bp->av_forw = flist->av_forw;
+               flist->av_forw = bp;
+               bp->av_back = flist;
        } else {
        } else {
-               backp = &bfreelist.av_back;
-               (*backp)->av_forw = bp;
-               bp->av_back = *backp;
-               *backp = bp;
-               bp->av_forw = &bfreelist;
+               if (bp->b_flags & B_LOCKED)
+                       flist = &bfreelist[BQ_LOCKED];
+               else if (bp->b_flags & B_AGE)
+                       flist = &bfreelist[BQ_AGE];
+               else
+                       flist = &bfreelist[BQ_LRU];
+               flist->av_back->av_forw = bp;
+               bp->av_back = flist->av_back;
+               flist->av_back = bp;
+               bp->av_forw = flist;
        }
        bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
        splx(s);
        }
        bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
        splx(s);
@@ -252,11 +305,12 @@ daddr_t blkno;
        register struct buf *dp;
        register int dblkno = fsbtodb(blkno);
 
        register struct buf *dp;
        register int dblkno = fsbtodb(blkno);
 
-       dp = bdevsw[major(dev)].d_tab;
-       for (bp=dp->b_forw; bp != dp; bp = bp->b_forw)
-               if (bp->b_blkno==dblkno && bp->b_dev==dev)
-                       return(1);
-       return(0);
+       dp = BUFHASH(dev, dblkno);
+       for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
+               if (bp->b_blkno == dblkno && bp->b_dev == dev &&
+                   !(bp->b_flags & B_INVAL))
+                       return (1);
+       return (0);
 }
 
 struct buf *
 }
 
 struct buf *
@@ -280,59 +334,65 @@ getblk(dev, blkno)
 dev_t dev;
 daddr_t blkno;
 {
 dev_t dev;
 daddr_t blkno;
 {
-       register struct buf *bp;
-       register struct buf *dp;
+       register struct buf *bp, *dp, *ep;
+       register int dblkno = fsbtodb(blkno);
 #ifdef DISKMON
 #ifdef DISKMON
-       register i;
+       register int i;
 #endif
 #endif
-       register int dblkno = fsbtodb(blkno);
-
-       if(major(dev) >= nblkdev)
-               panic("blkdev");
 
 
+       if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT))
+               blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1);
+       dblkno = fsbtodb(blkno);
+       dp = BUFHASH(dev, dblkno);
     loop:
     loop:
-       VOID spl0();
-       dp = bdevsw[major(dev)].d_tab;
-       if(dp == NULL)
-               panic("devtab");
-       for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) {
-               if (bp->b_blkno!=dblkno || bp->b_dev!=dev)
+       (void) spl0();
+       for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
+               if (bp->b_blkno != dblkno || bp->b_dev != dev ||
+                   bp->b_flags&B_INVAL)
                        continue;
                        continue;
-               VOID spl6();
+               (void) spl6();
                if (bp->b_flags&B_BUSY) {
                        bp->b_flags |= B_WANTED;
                        sleep((caddr_t)bp, PRIBIO+1);
                        goto loop;
                }
                if (bp->b_flags&B_BUSY) {
                        bp->b_flags |= B_WANTED;
                        sleep((caddr_t)bp, PRIBIO+1);
                        goto loop;
                }
-               VOID spl0();
+               (void) spl0();
 #ifdef DISKMON
                i = 0;
                dp = bp->av_forw;
 #ifdef DISKMON
                i = 0;
                dp = bp->av_forw;
-               while (dp != &bfreelist) {
+               while ((dp->b_flags & B_HEAD) == 0) {
                        i++;
                        dp = dp->av_forw;
                }
                        i++;
                        dp = dp->av_forw;
                }
-               if (i<NBUF)
+               if (i<64)
                        io_info.bufcount[i]++;
 #endif
                notavail(bp);
                bp->b_flags |= B_CACHE;
                return(bp);
        }
                        io_info.bufcount[i]++;
 #endif
                notavail(bp);
                bp->b_flags |= B_CACHE;
                return(bp);
        }
-       VOID spl6();
-       if (bfreelist.av_forw == &bfreelist) {
-               bfreelist.b_flags |= B_WANTED;
-               sleep((caddr_t)&bfreelist, PRIBIO+1);
+       if (major(dev) >= nblkdev)
+               panic("blkdev");
+       (void) spl6();
+       for (ep = &bfreelist[BQUEUES-1]; ep > bfreelist; ep--)
+               if (ep->av_forw != ep)
+                       break;
+       if (ep == bfreelist) {          /* no free blocks at all */
+               ep->b_flags |= B_WANTED;
+               sleep((caddr_t)ep, PRIBIO+1);
                goto loop;
        }
                goto loop;
        }
-       spl0();
-       bp = bfreelist.av_forw;
+       (void) spl0();
+       bp = ep->av_forw;
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
                bwrite(bp);
                goto loop;
        }
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
                bwrite(bp);
                goto loop;
        }
+#ifdef TRACE
+       trace(TR_BRELSE, bp->b_dev, bp->b_blkno);
+#endif
        bp->b_flags = B_BUSY;
        bp->b_back->b_forw = bp->b_forw;
        bp->b_forw->b_back = bp->b_back;
        bp->b_flags = B_BUSY;
        bp->b_back->b_forw = bp->b_forw;
        bp->b_forw->b_back = bp->b_back;
@@ -352,25 +412,30 @@ daddr_t blkno;
 struct buf *
 geteblk()
 {
 struct buf *
 geteblk()
 {
-       register struct buf *bp;
-       register struct buf *dp;
+       register struct buf *bp, *dp;
 
 loop:
 
 loop:
-       VOID spl6();
-       while (bfreelist.av_forw == &bfreelist) {
-               bfreelist.b_flags |= B_WANTED;
-               sleep((caddr_t)&bfreelist, PRIBIO+1);
+       (void) spl6();
+       for (dp = &bfreelist[BQUEUES-1]; dp > bfreelist; dp--)
+               if (dp->av_forw != dp)
+                       break;
+       if (dp == bfreelist) {          /* no free blocks */
+               dp->b_flags |= B_WANTED;
+               sleep((caddr_t)dp, PRIBIO+1);
+               goto loop;
        }
        }
-       VOID spl0();
-       dp = &bfreelist;
-       bp = bfreelist.av_forw;
+       (void) spl0();
+       bp = dp->av_forw;
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
                bwrite(bp);
                goto loop;
        }
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
                bwrite(bp);
                goto loop;
        }
-       bp->b_flags = B_BUSY;
+#ifdef TRACE
+       trace(TR_BRELSE, bp->b_dev, bp->b_blkno);
+#endif
+       bp->b_flags = B_BUSY|B_INVAL;
        bp->b_back->b_forw = bp->b_forw;
        bp->b_forw->b_back = bp->b_back;
        bp->b_forw = dp->b_forw;
        bp->b_back->b_forw = bp->b_forw;
        bp->b_forw->b_back = bp->b_back;
        bp->b_forw = dp->b_forw;
@@ -389,14 +454,14 @@ iowait(bp)
 register struct buf *bp;
 {
 
 register struct buf *bp;
 {
 
-       VOID spl6();
+       (void) spl6();
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
-       VOID spl0();
+       (void) spl0();
        geterror(bp);
 }
 
        geterror(bp);
 }
 
-#ifndef FASTVAX
+#ifdef UNFAST
 /*
  * Unlink a buffer from the available list and mark it busy.
  * (internal interface)
 /*
  * Unlink a buffer from the available list and mark it busy.
  * (internal interface)
@@ -427,19 +492,23 @@ register struct buf *bp;
 {
        register int s;
 
 {
        register int s;
 
+       if (bp->b_flags & B_DONE)
+               panic("dup iodone");
        bp->b_flags |= B_DONE;
        if (bp->b_flags & B_DIRTY) {
                if (bp->b_flags & B_ERROR)
                        panic("IO err in push");
                s = spl6();
        bp->b_flags |= B_DONE;
        if (bp->b_flags & B_DIRTY) {
                if (bp->b_flags & B_ERROR)
                        panic("IO err in push");
                s = spl6();
-               cnt.v_pgout++;
                bp->av_forw = bclnlist;
                bp->b_bcount = swsize[bp - swbuf];
                bp->b_pfcent = swpf[bp - swbuf];
                bp->av_forw = bclnlist;
                bp->b_bcount = swsize[bp - swbuf];
                bp->b_pfcent = swpf[bp - swbuf];
+               cnt.v_pgout++;
+               cnt.v_pgpgout += bp->b_bcount / NBPG;
                bclnlist = bp;
                if (bswlist.b_flags & B_WANTED)
                        wakeup((caddr_t)&proc[2]);
                splx(s);
                bclnlist = bp;
                if (bswlist.b_flags & B_WANTED)
                        wakeup((caddr_t)&proc[2]);
                splx(s);
+               return;
        }
        if (bp->b_flags&B_ASYNC)
                brelse(bp);
        }
        if (bp->b_flags&B_ASYNC)
                brelse(bp);
@@ -491,14 +560,14 @@ swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
        int p2dp;
        register struct pte *dpte, *vpte;
 
        int p2dp;
        register struct pte *dpte, *vpte;
 
-       VOID spl6();
+       (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;
        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();
+       (void) spl0();
 
        bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
        if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
 
        bp->b_flags = B_BUSY | B_PHYS | rdflg | flag;
        if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0)
@@ -524,20 +593,23 @@ swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
                bp->b_bcount = c;
                bp->b_blkno = dblkno;
                bp->b_dev = dev;
                bp->b_bcount = c;
                bp->b_blkno = dblkno;
                bp->b_dev = dev;
-               if (dev == swapdev)
-                       bp->b_blkno += swplo;
+               if (flag & B_DIRTY) {
+                       swpf[bp - swbuf] = pfcent;
+                       swsize[bp - swbuf] = nbytes;
+               }
+#ifdef TRACE
+               trace(TR_SWAPIO, dev, bp->b_blkno);
+#endif
                (*bdevsw[major(dev)].d_strategy)(bp);
                if (flag & B_DIRTY) {
                        if (c < nbytes)
                                panic("big push");
                (*bdevsw[major(dev)].d_strategy)(bp);
                if (flag & B_DIRTY) {
                        if (c < nbytes)
                                panic("big push");
-                       swsize[bp - swbuf] = nbytes;
-                       swpf[bp - swbuf] = pfcent;
                        return;
                }
                        return;
                }
-               VOID spl6();
+               (void) spl6();
                while((bp->b_flags&B_DONE)==0)
                        sleep((caddr_t)bp, PSWP);
                while((bp->b_flags&B_DONE)==0)
                        sleep((caddr_t)bp, PSWP);
-               VOID spl0();
+               (void) spl0();
                bp->b_un.b_addr += c;
                bp->b_flags &= ~B_DONE;
                if (bp->b_flags & B_ERROR) {
                bp->b_un.b_addr += c;
                bp->b_flags &= ~B_DONE;
                if (bp->b_flags & B_ERROR) {
@@ -548,7 +620,7 @@ swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
                nbytes -= c;
                dblkno += btoc(c);
        }
                nbytes -= c;
                dblkno += btoc(c);
        }
-       VOID spl6();
+       (void) spl6();
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
        bp->av_forw = bswlist.av_forw;
        bswlist.av_forw = bp;
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
        bp->av_forw = bswlist.av_forw;
        bswlist.av_forw = bp;
@@ -557,7 +629,7 @@ swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent)
                wakeup((caddr_t)&bswlist);
                wakeup((caddr_t)&proc[2]);
        }
                wakeup((caddr_t)&bswlist);
                wakeup((caddr_t)&proc[2]);
        }
-       VOID spl0();
+       (void) spl0();
 }
 
 /*
 }
 
 /*
@@ -569,19 +641,21 @@ swkill(p, rout)
        struct proc *p;
        char *rout;
 {
        struct proc *p;
        char *rout;
 {
+       char *mesg;
 
 
-       printf("%d: ", p->p_pid);
+       printf("pid %d: ", p->p_pid);
        if (rout)
        if (rout)
-               printf("out of swap space in %s\n", rout);
+               printf(mesg = "killed due to no swap space\n");
        else
        else
-               printf("killed on swap error\n");
+               printf(mesg = "killed on swap error\n");
+       uprintf("sorry, pid %d was %s", p->p_pid, mesg);
        /*
         * To be sure no looping (e.g. in vmsched trying to
         * swap out) mark process locked in core (as though
         * done by user) after killing it so noone will try
         * to swap it out.
         */
        /*
         * To be sure no looping (e.g. in vmsched trying to
         * swap out) mark process locked in core (as though
         * done by user) after killing it so noone will try
         * to swap it out.
         */
-       psignal(p, SIGKIL);
+       psignal(p, SIGKILL);
        p->p_flag |= SULOCK;
 }
 
        p->p_flag |= SULOCK;
 }
 
@@ -595,10 +669,12 @@ bflush(dev)
 dev_t dev;
 {
        register struct buf *bp;
 dev_t dev;
 {
        register struct buf *bp;
+       register struct buf *flist;
 
 loop:
 
 loop:
-       VOID spl6();
-       for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) {
+       (void) spl6();
+       for (flist = bfreelist; flist < &bfreelist[BQUEUES]; flist++)
+       for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
                if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
                if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
@@ -606,7 +682,7 @@ loop:
                        goto loop;
                }
        }
                        goto loop;
                }
        }
-       VOID spl0();
+       (void) spl0();
 }
 
 /*
 }
 
 /*
@@ -635,7 +711,7 @@ unsigned (*mincnt)();
                u.u_error = EFAULT;
                return;
        }
                u.u_error = EFAULT;
                return;
        }
-       VOID spl6();
+       (void) spl6();
        while (bp->b_flags&B_BUSY) {
                bp->b_flags |= B_WANTED;
                sleep((caddr_t)bp, PRIBIO+1);
        while (bp->b_flags&B_BUSY) {
                bp->b_flags |= B_WANTED;
                sleep((caddr_t)bp, PRIBIO+1);
@@ -643,7 +719,7 @@ unsigned (*mincnt)();
        bp->b_error = 0;
        bp->b_proc = u.u_procp;
        bp->b_un.b_addr = u.u_base;
        bp->b_error = 0;
        bp->b_proc = u.u_procp;
        bp->b_un.b_addr = u.u_base;
-       while (u.u_count != 0 && bp->b_error==0) {
+       while (u.u_count != 0) {
                bp->b_flags = B_BUSY | B_PHYS | rw;
                bp->b_dev = dev;
                bp->b_blkno = u.u_offset >> PGSHIFT;
                bp->b_flags = B_BUSY | B_PHYS | rw;
                bp->b_dev = dev;
                bp->b_blkno = u.u_offset >> PGSHIFT;
@@ -653,17 +729,19 @@ unsigned (*mincnt)();
                u.u_procp->p_flag |= SPHYSIO;
                vslock(a = bp->b_un.b_addr, c);
                (*strat)(bp);
                u.u_procp->p_flag |= SPHYSIO;
                vslock(a = bp->b_un.b_addr, c);
                (*strat)(bp);
-               VOID spl6();
+               (void) spl6();
                while ((bp->b_flags&B_DONE) == 0)
                        sleep((caddr_t)bp, PRIBIO);
                vsunlock(a, c, rw);
                u.u_procp->p_flag &= ~SPHYSIO;
                if (bp->b_flags&B_WANTED)
                        wakeup((caddr_t)bp);
                while ((bp->b_flags&B_DONE) == 0)
                        sleep((caddr_t)bp, PRIBIO);
                vsunlock(a, c, rw);
                u.u_procp->p_flag &= ~SPHYSIO;
                if (bp->b_flags&B_WANTED)
                        wakeup((caddr_t)bp);
-               VOID spl0();
+               (void) spl0();
                bp->b_un.b_addr += c;
                u.u_count -= c;
                u.u_offset += c;
                bp->b_un.b_addr += c;
                u.u_count -= c;
                u.u_offset += c;
+               if (bp->b_flags&B_ERROR)
+                       break;
        }
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
        u.u_count = bp->b_resid;
        }
        bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
        u.u_count = bp->b_resid;
@@ -694,3 +772,27 @@ register struct buf *bp;
                if ((u.u_error = bp->b_error)==0)
                        u.u_error = EIO;
 }
                if ((u.u_error = bp->b_error)==0)
                        u.u_error = EIO;
 }
+
+/*
+ * Invalidate in core blocks belonging to closed or umounted filesystem
+ *
+ * This is not nicely done at all - the buffer ought to be removed from the
+ * hash chains & have its dev/blkno fields clobbered, but unfortunately we
+ * can't do that here, as it is quite possible that the block is still
+ * being used for i/o. Eventually, all disc drivers should be forced to
+ * have a close routine, which ought ensure that the queue is empty, then
+ * properly flush the queues. Until that happy day, this suffices for
+ * correctness.                                                ... kre
+ */
+binval(dev)
+dev_t dev;
+{
+       register struct buf *bp;
+       register struct bufhd *hp;
+#define dp ((struct buf *)hp)
+
+       for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
+               for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
+                       if (bp->b_dev == dev)
+                               bp->b_flags |= B_INVAL;
+}