X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/a2057a3157b41dd588b28066bd486ab81565770c..32631928f6b9a3637bf84637adad2abe0a85b1a3:/sys/vm/vm_glue.c diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 4f3ee3a6f9..bd2fd07a54 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -1,6 +1,8 @@ /* * Copyright (c) 1991 Regents of the University of California. * All rights reserved. + * Copyright (c) John S. Dyson + * All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University. @@ -58,31 +60,29 @@ * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00137 - * -------------------- ----- ---------------------- - * - * 08 Apr 93 Bruce Evans Several VM system fixes */ -static char rcsid[] = "$Header: /home/cvs/386BSD/src/sys.386bsd/vm/vm_glue.c,v 1.3 1993/06/30 22:30:55 nate Exp $"; +#include "ddb.h" #include "param.h" #include "systm.h" #include "proc.h" #include "resourcevar.h" #include "buf.h" #include "user.h" +#include "kernel.h" #include "vm.h" #include "vm_page.h" #include "vm_kern.h" +#include "machine/stdarg.h" +extern char kstack[]; int avefree = 0; /* XXX */ -unsigned maxdmap = MAXDSIZ; /* XXX */ int readbuffers = 0; /* XXX allow kgdb to read kernel buffer pool */ +/* vm_map_t upages_map; */ +void swapout(struct proc *p); +int kernacc(addr, len, rw) caddr_t addr; int len, rw; @@ -103,12 +103,10 @@ kernacc(addr, len, rw) * or worse, inconsistencies at the pmap level. We only worry * about the buffer cache for now. */ - if (!readbuffers && rv && (eaddr > (vm_offset_t)buffers && - saddr < (vm_offset_t)buffers + MAXBSIZE * nbuf)) - rv = FALSE; return(rv == TRUE); } +int useracc(addr, len, rw) caddr_t addr; int len, rw; @@ -127,10 +125,12 @@ useracc(addr, len, rw) * only used (as an end address) in trap.c. Use it as an end * address here too. */ - if ((vm_offset_t) addr >= VM_MAXUSER_ADDRESS + if ((vm_offset_t) addr >= VM_MAXUSER_ADDRESS || (vm_offset_t) addr + len > VM_MAXUSER_ADDRESS - || (vm_offset_t) addr + len <= (vm_offset_t) addr) + || (vm_offset_t) addr + len <= (vm_offset_t) addr) { + printf("address wrap\n"); return (FALSE); + } rv = vm_map_check_protection(&curproc->p_vmspace->vm_map, trunc_page(addr), round_page(addr+len), prot); @@ -153,7 +153,7 @@ chgkprot(addr, len, rw) round_page(addr+len), prot, FALSE); } #endif - +void vslock(addr, len) caddr_t addr; u_int len; @@ -162,6 +162,7 @@ vslock(addr, len) round_page(addr+len), FALSE); } +void vsunlock(addr, len, dirtied) caddr_t addr; u_int len; @@ -170,7 +171,7 @@ vsunlock(addr, len, dirtied) #ifdef lint dirtied++; #endif lint - vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr), + vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr), round_page(addr+len), TRUE); } @@ -185,21 +186,22 @@ vsunlock(addr, len, dirtied) * after cpu_fork returns in the child process. We do nothing here * after cpu_fork returns. */ +int vm_fork(p1, p2, isvfork) register struct proc *p1, *p2; int isvfork; { register struct user *up; - vm_offset_t addr; + vm_offset_t addr, ptaddr; + int i; + struct vm_map *vp; -#ifdef i386 /* * avoid copying any of the parent's pagetables or other per-process * objects that reside in the map by marking all of them non-inheritable */ (void)vm_map_inherit(&p1->p_vmspace->vm_map, - UPT_MIN_ADDRESS-UPAGES*NBPG, VM_MAX_ADDRESS, VM_INHERIT_NONE); -#endif + UPT_MIN_ADDRESS - UPAGES * NBPG, VM_MAX_ADDRESS, VM_INHERIT_NONE); p2->p_vmspace = vmspace_fork(p1->p_vmspace); #ifdef SYSVSHM @@ -210,13 +212,38 @@ vm_fork(p1, p2, isvfork) /* * Allocate a wired-down (for now) pcb and kernel stack for the process */ -#ifdef notyet - addr = kmem_alloc_pageable(kernel_map, ctob(UPAGES)); - vm_map_pageable(kernel_map, addr, addr + ctob(UPAGES), FALSE); -#else - addr = kmem_alloc(kernel_map, ctob(UPAGES)); -#endif - up = (struct user *)addr; + + /* addr = UPT_MIN_ADDRESS - UPAGES*NBPG; */ + addr = (vm_offset_t) kstack; + + vp = &p2->p_vmspace->vm_map; + + /* ream out old pagetables and kernel stack */ + (void)vm_deallocate(vp, addr, UPT_MAX_ADDRESS - addr); + + /* get new pagetables and kernel stack */ + (void)vm_allocate(vp, &addr, UPT_MAX_ADDRESS - addr, FALSE); + + /* force in the page table encompassing the UPAGES */ + ptaddr = trunc_page((u_int)vtopte(addr)); + vm_map_pageable(vp, ptaddr, ptaddr + NBPG, FALSE); + + /* and force in (demand-zero) the UPAGES */ + vm_map_pageable(vp, addr, addr + UPAGES * NBPG, FALSE); + + /* get a kernel virtual address for the UPAGES for this proc */ + up = (struct user *)kmem_alloc_pageable(kernel_map, UPAGES * NBPG); + + /* and force-map the upages into the kernel pmap */ + for (i = 0; i < UPAGES; i++) + pmap_enter(vm_map_pmap(kernel_map), + ((vm_offset_t) up) + NBPG * i, + pmap_extract(vp->pmap, addr + NBPG * i), + VM_PROT_READ|VM_PROT_WRITE, 1); + + /* and allow the UPAGES page table entry to be paged (at the vm system level) */ + vm_map_pageable(vp, ptaddr, ptaddr + NBPG, TRUE); + p2->p_addr = up; /* @@ -235,16 +262,7 @@ vm_fork(p1, p2, isvfork) ((caddr_t)&up->u_stats.pstat_endcopy - (caddr_t)&up->u_stats.pstat_startcopy)); -#ifdef i386 - { u_int addr = UPT_MIN_ADDRESS - UPAGES*NBPG; struct vm_map *vp; - - vp = &p2->p_vmspace->vm_map; - - /* ream out old pagetables and kernel stack */ - (void)vm_deallocate(vp, addr, UPT_MAX_ADDRESS - addr); - (void)vm_allocate(vp, &addr, UPT_MAX_ADDRESS - addr, FALSE); - } -#endif + /* * cpu_fork will copy and update the kernel stack and pcb, * and make the child ready to run. It marks the child @@ -259,9 +277,11 @@ vm_fork(p1, p2, isvfork) * Set default limits for VM system. * Called for proc 0, and then inherited by all others. */ +void vm_init_limits(p) register struct proc *p; { + int tmp; /* * Set up the initial limits on process VM. @@ -274,8 +294,11 @@ vm_init_limits(p) p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ; p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ; p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ; - p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max = - ptoa(vm_page_free_count); + tmp = ((2 * vm_page_free_count) / 3) - 32; + if (vm_page_free_count < 512) + tmp = vm_page_free_count; + p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(tmp); + p->p_rlimit[RLIMIT_RSS].rlim_max = RLIM_INFINITY; } #include "../vm/vm_pageout.h" @@ -288,6 +311,64 @@ int swapdebug = 0; #define SDB_SWAPOUT 4 #endif +void +faultin(p) +struct proc *p; +{ + vm_offset_t i; + vm_offset_t vaddr, ptaddr; + vm_offset_t v, v1; + struct user *up; + int s; + int opflag; + + if ((p->p_flag & SLOAD) == 0) { + int rv0, rv1; + vm_map_t map; + + opflag = p->p_flag; + p->p_flag |= SLOCK; + + map = &p->p_vmspace->vm_map; + /* force the page table encompassing the kernel stack (upages) */ + ptaddr = trunc_page((u_int)vtopte(kstack)); + vm_map_pageable(map, ptaddr, ptaddr + NBPG, FALSE); + + /* wire in the UPAGES */ + vm_map_pageable(map, (vm_offset_t) kstack, + (vm_offset_t) kstack + UPAGES * NBPG, FALSE); + + /* and map them nicely into the kernel pmap */ + for (i = 0; i < UPAGES; i++) { + vm_offset_t off = i * NBPG; + vm_offset_t pa = (vm_offset_t) + pmap_extract(&p->p_vmspace->vm_pmap, + (vm_offset_t) kstack + off); + pmap_enter(vm_map_pmap(kernel_map), + ((vm_offset_t)p->p_addr) + off, + pa, VM_PROT_READ|VM_PROT_WRITE, 1); + } + + /* and let the page table pages go (at least above pmap level) */ + vm_map_pageable(map, ptaddr, ptaddr + NBPG, TRUE); + + s = splhigh(); + + if (p->p_stat == SRUN) + setrq(p); + + p->p_flag |= SLOAD; + + /* undo the effect of setting SLOCK above */ + p->p_flag &= ~SLOCK; + p->p_flag |= opflag & SLOCK; + splx(s); + + } + +} + +int swapinreq; /* * Brutally simple: * 1. Attempt to swapin every swaped-out, runnable process in @@ -295,6 +376,7 @@ int swapdebug = 0; * 2. If not enough memory, wake the pageout daemon and let it * clear some space. */ +void sched() { register struct proc *p; @@ -302,9 +384,10 @@ sched() struct proc *pp; int ppri; vm_offset_t addr; - vm_size_t size; + /* printf("vm_page_free_count: %d\n", vm_page_free_count); */ loop: + vmmeter(); #ifdef DEBUG if (!enableswap) { pp = NULL; @@ -330,7 +413,7 @@ noswap: * Nothing to do, back to sleep */ if ((p = pp) == NULL) { - sleep((caddr_t)&proc0, PVM); + tsleep((caddr_t)&proc0, PVM, "sched", 0); goto loop; } @@ -339,24 +422,16 @@ noswap: * This part is really bogus cuz we could deadlock on memory * despite our feeble check. */ - size = round_page(ctob(UPAGES)); - addr = (vm_offset_t) p->p_addr; - if (vm_page_free_count > atop(size)) { -#ifdef DEBUG - if (swapdebug & SDB_SWAPIN) - printf("swapin: pid %d(%s)@%x, pri %d free %d\n", - p->p_pid, p->p_comm, p->p_addr, - ppri, vm_page_free_count); -#endif - vm_map_pageable(kernel_map, addr, addr+size, FALSE); - (void) splclock(); - if (p->p_stat == SRUN) - setrq(p); - p->p_flag |= SLOAD; - (void) spl0(); + (void) splhigh(); + if (((vm_page_free_count + vm_page_inactive_count) >= + (vm_page_inactive_target + vm_page_free_reserved)) || + (vm_page_free_count >= vm_page_free_min)) { + spl0(); + faultin(p); p->p_time = 0; goto loop; - } + } + ++swapinreq; /* * Not enough memory, jab the pageout daemon and wait til the * coast is clear. @@ -366,7 +441,6 @@ noswap: printf("sched: no room for pid %d(%s), free %d\n", p->p_pid, p->p_comm, vm_page_free_count); #endif - (void) splhigh(); VM_WAIT; (void) spl0(); #ifdef DEBUG @@ -377,8 +451,9 @@ noswap: } #define swappable(p) \ - (((p)->p_flag & (SSYS|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD) + (((p)->p_flag & (STRC|SSYS|SLOAD|SLOCK|SKEEP|SWEXIT|SPHYSIO)) == SLOAD) +extern int vm_pageout_free_min; /* * Swapout is driven by the pageout daemon. Very simple, we find eligible * procs and unwire their u-areas. We try to always "swap" at least one @@ -387,39 +462,47 @@ noswap: * they are swapped. Else, we swap the longest-sleeping or stopped process, * if any, otherwise the longest-resident process. */ +void swapout_threads() { register struct proc *p; struct proc *outp, *outp2; int outpri, outpri2; + int tpri; int didswap = 0; extern int maxslp; + int s; #ifdef DEBUG if (!enableswap) return; #endif + outp = outp2 = NULL; - outpri = outpri2 = 0; + outpri = outpri2 = INT_MIN; for (p = allproc; p != NULL; p = p->p_nxt) { if (!swappable(p)) continue; switch (p->p_stat) { case SRUN: - if (p->p_time > outpri2) { + if (p->p_pri < PUSER) + continue; + if ((tpri = p->p_time + p->p_nice * 8) > outpri2) { outp2 = p; - outpri2 = p->p_time; + outpri2 = tpri; } continue; case SSLEEP: case SSTOP: + if (p->p_pri <= PRIBIO) + continue; if (p->p_slptime > maxslp) { swapout(p); didswap++; - } else if (p->p_slptime > outpri) { + } else if ((tpri = p->p_slptime + p->p_nice * 8) > outpri) { outp = p; - outpri = p->p_slptime; + outpri = tpri ; } continue; } @@ -430,24 +513,37 @@ swapout_threads() * if we are real low on memory since we don't gain much by doing * it (UPAGES pages). */ - if (didswap == 0 && - vm_page_free_count <= atop(round_page(ctob(UPAGES)))) { - if ((p = outp) == 0) + if (didswap == 0 && (swapinreq && + vm_page_free_count <= vm_pageout_free_min)) { + if ((p = outp) == 0 && + (vm_page_free_count <= vm_pageout_free_min)) p = outp2; #ifdef DEBUG if (swapdebug & SDB_SWAPOUT) printf("swapout_threads: no duds, try procp %x\n", p); #endif - if (p) + if (p) { swapout(p); + didswap = 1; + } + } + + if (didswap) { + if (swapinreq) + wakeup((caddr_t)&proc0); + swapinreq = 0; } } +void swapout(p) register struct proc *p; { vm_offset_t addr; - vm_size_t size; + struct pmap *pmap = &p->p_vmspace->vm_pmap; + vm_map_t map = &p->p_vmspace->vm_map; + vm_offset_t ptaddr; + int i; #ifdef DEBUG if (swapdebug & SDB_SWAPOUT) @@ -455,37 +551,23 @@ swapout(p) p->p_pid, p->p_comm, p->p_addr, p->p_stat, p->p_slptime, vm_page_free_count); #endif - size = round_page(ctob(UPAGES)); - addr = (vm_offset_t) p->p_addr; -#ifdef notyet -#ifdef hp300 - /* - * Ugh! u-area is double mapped to a fixed address behind the - * back of the VM system and accesses are usually through that - * address rather than the per-process address. Hence reference - * and modify information are recorded at the fixed address and - * lost at context switch time. We assume the u-struct and - * kernel stack are always accessed/modified and force it to be so. - */ - { - register int i; - volatile long tmp; - for (i = 0; i < UPAGES; i++) { - tmp = *(long *)addr; *(long *)addr = tmp; - addr += NBPG; - } - addr = (vm_offset_t) p->p_addr; - } -#endif - vm_map_pageable(kernel_map, addr, addr+size, TRUE); - pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map)); -#endif + (void) splhigh(); p->p_flag &= ~SLOAD; if (p->p_stat == SRUN) remrq(p); (void) spl0(); + + p->p_flag |= SLOCK; +/* let the upages be paged */ + pmap_remove(vm_map_pmap(kernel_map), + (vm_offset_t) p->p_addr, ((vm_offset_t) p->p_addr) + UPAGES * NBPG); + + vm_map_pageable(map, (vm_offset_t) kstack, + (vm_offset_t) kstack + UPAGES * NBPG, TRUE); + + p->p_flag &= ~SLOCK; p->p_time = 0; } @@ -493,6 +575,7 @@ swapout(p) * The rest of these routines fake thread handling */ +#ifndef assert_wait void assert_wait(event, ruptible) int event; @@ -503,61 +586,72 @@ assert_wait(event, ruptible) #endif curproc->p_thread = event; } +#endif void -thread_block() +thread_block(const char *msg) { - int s = splhigh(); - if (curproc->p_thread) - sleep((caddr_t)curproc->p_thread, PVM); - splx(s); + tsleep((caddr_t)curproc->p_thread, PVM, msg, 0); } -thread_sleep(event, lock, ruptible) + +void +thread_sleep_(event, lock, wmesg) int event; simple_lock_t lock; - boolean_t ruptible; + const char *wmesg; { -#ifdef lint - ruptible++; -#endif - int s = splhigh(); curproc->p_thread = event; simple_unlock(lock); - if (curproc->p_thread) - sleep((caddr_t)event, PVM); - splx(s); + if (curproc->p_thread) { + tsleep((caddr_t)event, PVM, wmesg, 0); + } } +#ifndef thread_wakeup +void thread_wakeup(event) int event; { - int s = splhigh(); - wakeup((caddr_t)event); - splx(s); } +#endif /* * DEBUG stuff */ + +/* + * DEBUG stuff + */ + +#if defined(DEBUG) || (NDDB > 0) int indent = 0; /*ARGSUSED2*/ -iprintf(a, b, c, d, e, f, g, h) - char *a; +void +iprintf(const char *fmt, ...) { - register int i; + va_list args; + int i, j = 0; + char indentbuf[indent + 1]; + va_start(args, fmt); i = indent; while (i >= 8) { - printf("\t"); - i -= 8; + indentbuf[j++] = '\t'; + i -= 8; } for (; i > 0; --i) - printf(" "); - printf(a, b, c, d, e, f, g, h); + indentbuf[j++] = ' '; + + indentbuf[j++] = '\0'; + + printf("%s%r", indentbuf, fmt, args); + va_end(args); } +#endif /* defined(DEBUG) || (NDDB > 0) */ +