X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/600f7f072ed61fd173a4d410ea60644c533a32e5..da6ece2ed8559ae1a7dedcb951b3947df90cb0c0:/sys/kern/kern__physio.c diff --git a/sys/kern/kern__physio.c b/sys/kern/kern__physio.c index 0995b1b604..1da54190fd 100644 --- a/sys/kern/kern__physio.c +++ b/sys/kern/kern__physio.c @@ -45,7 +45,7 @@ * 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" @@ -58,44 +58,70 @@ #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.. */ +int 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; { - 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; + struct buf *bp; 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; - static zero; + vm_offset_t v, lastv; 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 */ - 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; @@ -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)) { - free(bp, M_TEMP); - return (EFAULT); + error = EFAULT; + goto errrtn; } 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 */ @@ -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; -/* 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) { - 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); - /* unlock */ + /* unlock (perform vm_map_pageable, TRUE) */ 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; @@ -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; - free(bp, M_TEMP); +errrtn: + if (bp_alloc) { + relpbuf(bp); + } else { + bp->b_flags &= ~B_BUSY; + wakeup((caddr_t)bp); + } *len = amttodo; + +/* + * allow the process to be swapped + */ + p->p_flag &= ~SPHYSIO; + p->p_flag |= (oldflags & SPHYSIO); + return (error); }