Commit a whole cluster of last minute critical (and one cosmetic) fixes
[unix-history] / sys / kern / kern__physio.c
index 0995b1b..1da5419 100644 (file)
@@ -45,7 +45,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     $Id$
+ *     $Id: kern__physio.c,v 1.6 1994/01/14 16:24:47 davidg Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "vm/vm.h"
 #include "specdev.h"
 
 #include "vm/vm.h"
 #include "specdev.h"
 
-static physio(int (*)(), int, int, int, caddr_t, int *, struct proc *);
-
 /*
  * Driver interface to do "raw" I/O in the address space of a
  * user process directly for read and write operations..
  */
 
 /*
  * Driver interface to do "raw" I/O in the address space of a
  * user process directly for read and write operations..
  */
 
+int
 rawread(dev, uio)
        dev_t dev; struct uio *uio;
 {
 rawread(dev, uio)
        dev_t dev; struct uio *uio;
 {
-       return (uioapply(physio, cdevsw[major(dev)].d_strategy, dev, uio));
+       return (uioapply(physio, (caddr_t) cdevsw[major(dev)].d_strategy,
+                                (caddr_t) (u_long) dev, uio));
 }
 
 }
 
+int
 rawwrite(dev, uio)
        dev_t dev; struct uio *uio;
 {
 rawwrite(dev, uio)
        dev_t dev; struct uio *uio;
 {
-       return (uioapply(physio, cdevsw[major(dev)].d_strategy, dev, uio));
+       return (uioapply(physio, (caddr_t) cdevsw[major(dev)].d_strategy,
+                               (caddr_t) (u_long) dev, uio));
 }
 
 }
 
-static physio(strat, dev, off, rw, base, len, p)
-       int (*strat)(); 
+
+int physio(strat, dev, bp, off, rw, base, len, p)
+       d_strategy_t strat; 
        dev_t dev;
        dev_t dev;
+       struct buf *bp;
        int rw, off;
        caddr_t base;
        int *len;
        struct proc *p;
 {
        int rw, off;
        caddr_t base;
        int *len;
        struct proc *p;
 {
-       register struct buf *bp;
-       int amttodo = *len, error, amtdone;
+       int amttodo = *len;
+       int error, amtdone;
        vm_prot_t ftype;
        vm_prot_t ftype;
-       static zero;
+       vm_offset_t v, lastv;
        caddr_t adr;
        caddr_t adr;
+       int oldflags;
+       int s;
+       
+       int bp_alloc = (bp == 0);
+
+/*
+ * keep the process from being swapped
+ */
+       oldflags = p->p_flag;
+       p->p_flag |= SPHYSIO;
 
        rw = rw == UIO_READ ? B_READ : 0;
 
        /* create and build a buffer header for a transfer */
 
        rw = rw == UIO_READ ? B_READ : 0;
 
        /* create and build a buffer header for a transfer */
-       bp = (struct buf *)malloc(sizeof(*bp), M_TEMP, M_NOWAIT);
-       bzero((char *)bp, sizeof(*bp));                 /* 09 Sep 92*/
+
+       if (bp_alloc) {
+               bp = (struct buf *)getpbuf();
+               bzero((char *)bp, sizeof(*bp));                 /* 09 Sep 92*/
+       } else {
+               s = splbio();
+               while (bp->b_flags & B_BUSY) {
+                       bp->b_flags |= B_WANTED;
+                       tsleep((caddr_t)bp, PRIBIO, "physbw", 0);
+               }
+               bp->b_flags |= B_BUSY;
+               splx(s);
+       }
+
        bp->b_flags = B_BUSY | B_PHYS | rw;
        bp->b_proc = p;
        bp->b_dev = dev;
        bp->b_flags = B_BUSY | B_PHYS | rw;
        bp->b_proc = p;
        bp->b_dev = dev;
@@ -112,12 +138,12 @@ static physio(strat, dev, off, rw, base, len, p)
 
                /* first, check if accessible */
                if (rw == B_READ && !useracc(base, bp->b_bcount, B_WRITE)) {
 
                /* first, check if accessible */
                if (rw == B_READ && !useracc(base, bp->b_bcount, B_WRITE)) {
-                       free(bp, M_TEMP);
-                       return (EFAULT);
+                       error = EFAULT;
+                       goto errrtn;
                }
                if (rw == B_WRITE && !useracc(base, bp->b_bcount, B_READ)) {
                }
                if (rw == B_WRITE && !useracc(base, bp->b_bcount, B_READ)) {
-                       free(bp, M_TEMP);
-                       return (EFAULT);
+                       error = EFAULT;
+                       goto errrtn;
                }
 
                /* update referenced and dirty bits, handle copy objects */
                }
 
                /* update referenced and dirty bits, handle copy objects */
@@ -125,21 +151,79 @@ static physio(strat, dev, off, rw, base, len, p)
                        ftype = VM_PROT_READ | VM_PROT_WRITE;
                else
                        ftype = VM_PROT_READ;
                        ftype = VM_PROT_READ | VM_PROT_WRITE;
                else
                        ftype = VM_PROT_READ;
-/* 09 Sep 92*/ for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount;
+
+               lastv = 0;
+               for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount;
                        adr += NBPG) {
                        adr += NBPG) {
-                       vm_fault(&curproc->p_vmspace->vm_map,
-                               adr, ftype, FALSE);
-                       *(int *) adr += zero;
+       
+/*
+ * make sure that the pde is valid and wired
+ */
+                       v = trunc_page(((vm_offset_t)vtopte(adr)));
+                       if (v != lastv) {
+                               vm_map_pageable(&p->p_vmspace->vm_map, v,
+                                       round_page(v+1), FALSE);
+                               lastv = v;
+                       }
+
+/*
+ * do the vm_fault if needed, do the copy-on-write thing when
+ * reading stuff off device into memory.
+ */
+                       if (ftype & VM_PROT_WRITE) {
+                               /*
+                                * properly handle copy-on-write
+                                */
+                               *(volatile int *) adr += 0;
+                       }
+#if 0
+                       else {
+                               /*
+                                * this clause is not really necessary because 
+                                * vslock does a vm_map_pageable FALSE.
+                                * It is not optimally efficient to reference the
+                                * page with the possiblity of it being paged out, but
+                                * if this page is faulted here, it will be placed on the
+                                * active queue, with the probability of it being paged
+                                * out being very very low.  This is here primarily for
+                                * "symmetry".
+                                */
+                               *(volatile int *) adr;
+                       }
+#endif
                }
                }
+/*
+ * if the process has been blocked by the wiring of the page table pages
+ * above or faults of other pages, then the vm_map_pageable contained in the
+ * vslock will fault the pages back in if they have been paged out since
+ * being referenced in the loop above. (vm_map_pageable calls vm_fault_wire
+ * which calls vm_fault to get the pages if needed.)
+ */
 
 
-               /* lock in core */
+               /* lock in core (perform vm_map_pageable, FALSE) */
                vslock (base, bp->b_bcount);
 
                /* perform transfer */
                physstrat(bp, strat, PRIBIO);
 
                vslock (base, bp->b_bcount);
 
                /* perform transfer */
                physstrat(bp, strat, PRIBIO);
 
-               /* unlock */
+               /* unlock (perform vm_map_pageable, TRUE) */
                vsunlock (base, bp->b_bcount, 0);
                vsunlock (base, bp->b_bcount, 0);
+
+               lastv = 0;
+
+/*
+ * unwire the pde
+ */
+               for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount;
+                       adr += NBPG) {
+                       v = trunc_page(((vm_offset_t)vtopte(adr)));
+                       if (v != lastv) {
+                               vm_map_pageable(&p->p_vmspace->vm_map, v, round_page(v+1), TRUE);
+                               lastv = v;
+                       }
+               }
+                       
+
                amtdone = bp->b_bcount - bp->b_resid;
                amttodo -= amtdone;
                base += amtdone;
                amtdone = bp->b_bcount - bp->b_resid;
                amttodo -= amtdone;
                base += amtdone;
@@ -147,7 +231,20 @@ static physio(strat, dev, off, rw, base, len, p)
        } while (amttodo && (bp->b_flags & B_ERROR) == 0 && amtdone > 0);
 
        error = bp->b_error;
        } while (amttodo && (bp->b_flags & B_ERROR) == 0 && amtdone > 0);
 
        error = bp->b_error;
-       free(bp, M_TEMP);
+errrtn:
+       if (bp_alloc) {
+               relpbuf(bp);
+       } else {
+               bp->b_flags &= ~B_BUSY;
+               wakeup((caddr_t)bp);
+       }
        *len = amttodo;
        *len = amttodo;
+
+/*
+ * allow the process to be swapped
+ */
+       p->p_flag &= ~SPHYSIO;
+       p->p_flag |= (oldflags & SPHYSIO);
+
        return (error);
 }
        return (error);
 }