[BACK]Return to uvm_glue.c CVS log [TXT][DIR] Up to [local] / sys / uvm

Annotation of sys/uvm/uvm_glue.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: uvm_glue.c,v 1.47 2007/05/26 20:26:51 pedro Exp $     */
                      2: /*     $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $        */
                      3:
                      4: /*
                      5:  * Copyright (c) 1997 Charles D. Cranor and Washington University.
                      6:  * Copyright (c) 1991, 1993, The Regents of the University of California.
                      7:  *
                      8:  * All rights reserved.
                      9:  *
                     10:  * This code is derived from software contributed to Berkeley by
                     11:  * The Mach Operating System project at Carnegie-Mellon University.
                     12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  * 3. All advertising materials mentioning features or use of this software
                     22:  *    must display the following acknowledgement:
                     23:  *     This product includes software developed by Charles D. Cranor,
                     24:  *      Washington University, the University of California, Berkeley and
                     25:  *      its contributors.
                     26:  * 4. Neither the name of the University nor the names of its contributors
                     27:  *    may be used to endorse or promote products derived from this software
                     28:  *    without specific prior written permission.
                     29:  *
                     30:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     31:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     32:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     33:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     34:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     35:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     36:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     37:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     38:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     39:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     40:  * SUCH DAMAGE.
                     41:  *
                     42:  *     @(#)vm_glue.c   8.6 (Berkeley) 1/5/94
                     43:  * from: Id: uvm_glue.c,v 1.1.2.8 1998/02/07 01:16:54 chs Exp
                     44:  *
                     45:  *
                     46:  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
                     47:  * All rights reserved.
                     48:  *
                     49:  * Permission to use, copy, modify and distribute this software and
                     50:  * its documentation is hereby granted, provided that both the copyright
                     51:  * notice and this permission notice appear in all copies of the
                     52:  * software, derivative works or modified versions, and any portions
                     53:  * thereof, and that both notices appear in supporting documentation.
                     54:  *
                     55:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     56:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
                     57:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     58:  *
                     59:  * Carnegie Mellon requests users of this software to return to
                     60:  *
                     61:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
                     62:  *  School of Computer Science
                     63:  *  Carnegie Mellon University
                     64:  *  Pittsburgh PA 15213-3890
                     65:  *
                     66:  * any improvements or extensions that they make and grant Carnegie the
                     67:  * rights to redistribute these changes.
                     68:  */
                     69:
                     70: /*
                     71:  * uvm_glue.c: glue functions
                     72:  */
                     73:
                     74: #include <sys/param.h>
                     75: #include <sys/systm.h>
                     76: #include <sys/proc.h>
                     77: #include <sys/resourcevar.h>
                     78: #include <sys/buf.h>
                     79: #include <sys/user.h>
                     80: #ifdef SYSVSHM
                     81: #include <sys/shm.h>
                     82: #endif
                     83: #include <sys/sched.h>
                     84:
                     85: #include <uvm/uvm.h>
                     86:
                     87: #include <machine/cpu.h>
                     88:
                     89: /*
                     90:  * XXXCDC: do these really belong here?
                     91:  */
                     92:
                     93: int readbuffers = 0;           /* allow KGDB to read kern buffer pool */
                     94:                                /* XXX: see uvm_kernacc */
                     95:
                     96:
                     97: /*
                     98:  * uvm_kernacc: can the kernel access a region of memory
                     99:  *
                    100:  * - called from malloc [DIAGNOSTIC], and /dev/kmem driver (mem.c)
                    101:  */
                    102:
                    103: boolean_t
                    104: uvm_kernacc(addr, len, rw)
                    105:        caddr_t addr;
                    106:        size_t len;
                    107:        int rw;
                    108: {
                    109:        boolean_t rv;
                    110:        vaddr_t saddr, eaddr;
                    111:        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
                    112:
                    113:        saddr = trunc_page((vaddr_t)addr);
                    114:        eaddr = round_page((vaddr_t)addr + len);
                    115:        vm_map_lock_read(kernel_map);
                    116:        rv = uvm_map_checkprot(kernel_map, saddr, eaddr, prot);
                    117:        vm_map_unlock_read(kernel_map);
                    118:
                    119:        return(rv);
                    120: }
                    121:
                    122: #ifdef KGDB
                    123: /*
                    124:  * Change protections on kernel pages from addr to addr+len
                    125:  * (presumably so debugger can plant a breakpoint).
                    126:  *
                    127:  * We force the protection change at the pmap level.  If we were
                    128:  * to use vm_map_protect a change to allow writing would be lazily-
                    129:  * applied meaning we would still take a protection fault, something
                    130:  * we really don't want to do.  It would also fragment the kernel
                    131:  * map unnecessarily.  We cannot use pmap_protect since it also won't
                    132:  * enforce a write-enable request.  Using pmap_enter is the only way
                    133:  * we can ensure the change takes place properly.
                    134:  */
                    135: void
                    136: uvm_chgkprot(addr, len, rw)
                    137:        caddr_t addr;
                    138:        size_t len;
                    139:        int rw;
                    140: {
                    141:        vm_prot_t prot;
                    142:        paddr_t pa;
                    143:        vaddr_t sva, eva;
                    144:
                    145:        prot = rw == B_READ ? VM_PROT_READ : VM_PROT_READ|VM_PROT_WRITE;
                    146:        eva = round_page((vaddr_t)addr + len);
                    147:        for (sva = trunc_page((vaddr_t)addr); sva < eva; sva += PAGE_SIZE) {
                    148:                /*
                    149:                 * Extract physical address for the page.
                    150:                 * We use a cheezy hack to differentiate physical
                    151:                 * page 0 from an invalid mapping, not that it
                    152:                 * really matters...
                    153:                 */
                    154:                if (pmap_extract(pmap_kernel(), sva, &pa) == FALSE)
                    155:                        panic("chgkprot: invalid page");
                    156:                pmap_enter(pmap_kernel(), sva, pa, prot, PMAP_WIRED);
                    157:        }
                    158:        pmap_update(pmap_kernel());
                    159: }
                    160: #endif
                    161:
                    162: /*
                    163:  * uvm_vslock: wire user memory for I/O
                    164:  *
                    165:  * - called from physio and sys___sysctl
                    166:  * - XXXCDC: consider nuking this (or making it a macro?)
                    167:  */
                    168:
                    169: int
                    170: uvm_vslock(p, addr, len, access_type)
                    171:        struct proc *p;
                    172:        caddr_t addr;
                    173:        size_t  len;
                    174:        vm_prot_t access_type;
                    175: {
                    176:        vm_map_t map;
                    177:        vaddr_t start, end;
                    178:        int rv;
                    179:
                    180:        map = &p->p_vmspace->vm_map;
                    181:        start = trunc_page((vaddr_t)addr);
                    182:        end = round_page((vaddr_t)addr + len);
                    183:        if (end <= start)
                    184:                return (EINVAL);
                    185:
                    186:        rv = uvm_fault_wire(map, start, end, access_type);
                    187:
                    188:        return (rv);
                    189: }
                    190:
                    191: /*
                    192:  * uvm_vsunlock: unwire user memory wired by uvm_vslock()
                    193:  *
                    194:  * - called from physio and sys___sysctl
                    195:  * - XXXCDC: consider nuking this (or making it a macro?)
                    196:  */
                    197:
                    198: void
                    199: uvm_vsunlock(p, addr, len)
                    200:        struct proc *p;
                    201:        caddr_t addr;
                    202:        size_t  len;
                    203: {
                    204:        vaddr_t start, end;
                    205:
                    206:        start = trunc_page((vaddr_t)addr);
                    207:        end = round_page((vaddr_t)addr + len);
                    208:        if (end <= start)
                    209:                return;
                    210:
                    211:        uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
                    212: }
                    213:
                    214: /*
                    215:  * uvm_fork: fork a virtual address space
                    216:  *
                    217:  * - the address space is copied as per parent map's inherit values
                    218:  * - a new "user" structure is allocated for the child process
                    219:  *     [filled in by MD layer...]
                    220:  * - if specified, the child gets a new user stack described by
                    221:  *     stack and stacksize
                    222:  * - NOTE: the kernel stack may be at a different location in the child
                    223:  *     process, and thus addresses of automatic variables may be invalid
                    224:  *     after cpu_fork returns in the child process.  We do nothing here
                    225:  *     after cpu_fork returns.
                    226:  * - XXXCDC: we need a way for this to return a failure value rather
                    227:  *   than just hang
                    228:  */
                    229: void
                    230: uvm_fork(p1, p2, shared, stack, stacksize, func, arg)
                    231:        struct proc *p1, *p2;
                    232:        boolean_t shared;
                    233:        void *stack;
                    234:        size_t stacksize;
                    235:        void (*func)(void *);
                    236:        void *arg;
                    237: {
                    238:        struct user *up = p2->p_addr;
                    239:
                    240:        if (shared == TRUE) {
                    241:                p2->p_vmspace = NULL;
                    242:                uvmspace_share(p1, p2);                 /* share vmspace */
                    243:        } else
                    244:                p2->p_vmspace = uvmspace_fork(p1->p_vmspace); /* fork vmspace */
                    245:
                    246: #ifdef PMAP_UAREA
                    247:        /* Tell the pmap this is a u-area mapping */
                    248:        PMAP_UAREA((vaddr_t)up);
                    249: #endif
                    250:
                    251:        /*
                    252:         * p_stats currently points at a field in the user struct.  Copy
                    253:         * parts of p_stats, and zero out the rest.
                    254:         */
                    255:        p2->p_stats = &up->u_stats;
                    256:        memset(&up->u_stats.pstat_startzero, 0,
                    257:               ((caddr_t)&up->u_stats.pstat_endzero -
                    258:                (caddr_t)&up->u_stats.pstat_startzero));
                    259:        memcpy(&up->u_stats.pstat_startcopy, &p1->p_stats->pstat_startcopy,
                    260:               ((caddr_t)&up->u_stats.pstat_endcopy -
                    261:                (caddr_t)&up->u_stats.pstat_startcopy));
                    262:
                    263:        /*
                    264:         * cpu_fork() copy and update the pcb, and make the child ready
                    265:         * to run.  If this is a normal user fork, the child will exit
                    266:         * directly to user mode via child_return() on its first time
                    267:         * slice and will not return here.  If this is a kernel thread,
                    268:         * the specified entry point will be executed.
                    269:         */
                    270:        cpu_fork(p1, p2, stack, stacksize, func, arg);
                    271: }
                    272:
                    273: /*
                    274:  * uvm_exit: exit a virtual address space
                    275:  *
                    276:  * - the process passed to us is a dead (pre-zombie) process; we
                    277:  *   are running on a different context now (the reaper).
                    278:  * - we must run in a separate thread because freeing the vmspace
                    279:  *   of the dead process may block.
                    280:  */
                    281: void
                    282: uvm_exit(struct proc *p)
                    283: {
                    284:        uvmspace_free(p->p_vmspace);
                    285:        uvm_km_free(kernel_map, (vaddr_t)p->p_addr, USPACE);
                    286:        p->p_addr = NULL;
                    287: }
                    288:
                    289: /*
                    290:  * uvm_init_limit: init per-process VM limits
                    291:  *
                    292:  * - called for process 0 and then inherited by all others.
                    293:  */
                    294: void
                    295: uvm_init_limits(struct proc *p)
                    296: {
                    297:
                    298:        /*
                    299:         * Set up the initial limits on process VM.  Set the maximum
                    300:         * resident set size to be all of (reasonably) available memory.
                    301:         * This causes any single, large process to start random page
                    302:         * replacement once it fills memory.
                    303:         */
                    304:
                    305:        p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
                    306:        p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
                    307:        p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
                    308:        p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
                    309:        p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(uvmexp.free);
                    310: }
                    311:
                    312: #ifdef DEBUG
                    313: int    enableswap = 1;
                    314: int    swapdebug = 0;
                    315: #define        SDB_FOLLOW      1
                    316: #define SDB_SWAPIN     2
                    317: #define SDB_SWAPOUT    4
                    318: #endif
                    319:
                    320: /*
                    321:  * uvm_scheduler: process zero main loop
                    322:  *
                    323:  * - if not enough memory, wake the pagedaemon and let it clear space.
                    324:  */
                    325:
                    326: void
                    327: uvm_scheduler(void)
                    328: {
                    329:        /*
                    330:         * Nothing to do, back to sleep
                    331:         */
                    332:        while (1)
                    333:                tsleep(&proc0, PVM, "scheduler", 0);
                    334: }
                    335:
                    336: /*
                    337:  * swappable: is process "p" swappable?
                    338:  */
                    339:
                    340: #define        swappable(p) (((p)->p_flag & (P_SYSTEM | P_WEXIT)) == 0)
                    341:
                    342: /*
                    343:  * swapout_threads: find threads that can be swapped
                    344:  *
                    345:  * - called by the pagedaemon
                    346:  * - try and swap at least one processs
                    347:  * - processes that are sleeping or stopped for maxslp or more seconds
                    348:  *   are swapped... otherwise the longest-sleeping or stopped process
                    349:  *   is swapped, otherwise the longest resident process...
                    350:  */
                    351: void
                    352: uvm_swapout_threads(void)
                    353: {
                    354:        struct proc *p;
                    355:        struct proc *outp, *outp2;
                    356:        int outpri, outpri2;
                    357:        int didswap = 0;
                    358:        extern int maxslp;
                    359:        /* XXXCDC: should move off to uvmexp. or uvm., also in uvm_meter */
                    360:
                    361: #ifdef DEBUG
                    362:        if (!enableswap)
                    363:                return;
                    364: #endif
                    365:
                    366:        /*
                    367:         * outp/outpri  : stop/sleep process with largest sleeptime < maxslp
                    368:         * outp2/outpri2: the longest resident process (its swap time)
                    369:         */
                    370:        outp = outp2 = NULL;
                    371:        outpri = outpri2 = 0;
                    372:        LIST_FOREACH(p, &allproc, p_list) {
                    373:                if (!swappable(p))
                    374:                        continue;
                    375:                switch (p->p_stat) {
                    376:                case SRUN:
                    377:                        if (p->p_swtime > outpri2) {
                    378:                                outp2 = p;
                    379:                                outpri2 = p->p_swtime;
                    380:                        }
                    381:                        continue;
                    382:
                    383:                case SSLEEP:
                    384:                case SSTOP:
                    385:                        if (p->p_slptime >= maxslp) {
                    386:                                pmap_collect(p->p_vmspace->vm_map.pmap);
                    387:                                didswap++;
                    388:                        } else if (p->p_slptime > outpri) {
                    389:                                outp = p;
                    390:                                outpri = p->p_slptime;
                    391:                        }
                    392:                        continue;
                    393:                }
                    394:        }
                    395:
                    396:        /*
                    397:         * If we didn't get rid of any real duds, toss out the next most
                    398:         * likely sleeping/stopped or running candidate.  We only do this
                    399:         * if we are real low on memory since we don't gain much by doing
                    400:         * it.
                    401:         */
                    402:        if (didswap == 0 && uvmexp.free <= atop(round_page(USPACE))) {
                    403:                if ((p = outp) == NULL)
                    404:                        p = outp2;
                    405: #ifdef DEBUG
                    406:                if (swapdebug & SDB_SWAPOUT)
                    407:                        printf("swapout_threads: no duds, try procp %p\n", p);
                    408: #endif
                    409:                if (p)
                    410:                        pmap_collect(p->p_vmspace->vm_map.pmap);
                    411:        }
                    412: }

CVSweb