Annotation of Gnu-Mach/vm/vm_resident.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
1.1.1.4   root       30:  *     File:   vm/vm_resident.c
1.1       root       31:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
                     32:  *
                     33:  *     Resident memory management module.
                     34:  */
1.1.1.3   root       35: 
                     36: #include <kern/printf.h>
                     37: #include <string.h>
1.1       root       38: 
                     39: #include <mach/vm_prot.h>
                     40: #include <kern/counters.h>
1.1.1.3   root       41: #include <kern/debug.h>
1.1.1.6 ! root       42: #include <kern/list.h>
1.1       root       43: #include <kern/sched_prim.h>
                     44: #include <kern/task.h>
                     45: #include <kern/thread.h>
                     46: #include <mach/vm_statistics.h>
1.1.1.3   root       47: #include <machine/vm_param.h>
1.1       root       48: #include <kern/xpr.h>
1.1.1.3   root       49: #include <kern/slab.h>
1.1       root       50: #include <vm/pmap.h>
                     51: #include <vm/vm_map.h>
                     52: #include <vm/vm_page.h>
                     53: #include <vm/vm_pageout.h>
                     54: #include <vm/vm_kern.h>
                     55: 
                     56: #if    MACH_VM_DEBUG
                     57: #include <mach/kern_return.h>
                     58: #include <mach_debug/hash_info.h>
                     59: #include <vm/vm_user.h>
                     60: #endif
                     61: 
1.1.1.3   root       62: #if    MACH_KDB
                     63: #include <ddb/db_output.h>
                     64: #include <vm/vm_print.h>
                     65: #endif /* MACH_KDB */
                     66: 
1.1       root       67: 
                     68: /*
1.1.1.4   root       69:  *     Associated with each page of user-allocatable memory is a
1.1       root       70:  *     page structure.
                     71:  */
                     72: 
                     73: /*
                     74:  *     These variables record the values returned by vm_page_bootstrap,
                     75:  *     for debugging purposes.  The implementation of pmap_steal_memory
1.1.1.5   root       76:  *     here also uses them internally.
1.1       root       77:  */
                     78: 
                     79: vm_offset_t virtual_space_start;
                     80: vm_offset_t virtual_space_end;
                     81: 
                     82: /*
                     83:  *     The vm_page_lookup() routine, which provides for fast
                     84:  *     (virtual memory object, offset) to page lookup, employs
                     85:  *     the following hash table.  The vm_page_{insert,remove}
                     86:  *     routines install and remove associations in the table.
                     87:  *     [This table is often called the virtual-to-physical,
                     88:  *     or VP, table.]
                     89:  */
                     90: typedef struct {
                     91:        decl_simple_lock_data(,lock)
                     92:        vm_page_t pages;
                     93: } vm_page_bucket_t;
                     94: 
                     95: vm_page_bucket_t *vm_page_buckets;             /* Array of buckets */
1.1.1.6 ! root       96: unsigned long  vm_page_bucket_count = 0;       /* How big is array? */
        !            97: unsigned long  vm_page_hash_mask;              /* Mask for hash function */
1.1       root       98: 
1.1.1.6 ! root       99: static struct list     vm_page_queue_fictitious;
1.1       root      100: decl_simple_lock_data(,vm_page_queue_free_lock)
                    101: int            vm_page_fictitious_count;
1.1.1.6 ! root      102: int            vm_object_external_count;
        !           103: int            vm_object_external_pages;
1.1       root      104: 
                    105: /*
                    106:  *     Occasionally, the virtual memory system uses
                    107:  *     resident page structures that do not refer to
                    108:  *     real pages, for example to leave a page with
                    109:  *     important state information in the VP table.
                    110:  *
                    111:  *     These page structures are allocated the way
                    112:  *     most other kernel structures are.
                    113:  */
1.1.1.3   root      114: struct kmem_cache      vm_page_cache;
1.1       root      115: 
                    116: /*
                    117:  *     Fictitious pages don't have a physical address,
                    118:  *     but we must initialize phys_addr to something.
                    119:  *     For debugging, this should be a strange value
                    120:  *     that the pmap module can recognize in assertions.
                    121:  */
1.1.1.6 ! root      122: phys_addr_t vm_page_fictitious_addr = (phys_addr_t) -1;
1.1       root      123: 
                    124: /*
                    125:  *     Resident page structures are also chained on
                    126:  *     queues that are used by the page replacement
                    127:  *     system (pageout daemon).  These queues are
                    128:  *     defined here, but are shared by the pageout
                    129:  *     module.
                    130:  */
                    131: decl_simple_lock_data(,vm_page_queue_lock)
                    132: int    vm_page_active_count;
                    133: int    vm_page_inactive_count;
                    134: int    vm_page_wire_count;
                    135: 
                    136: /*
                    137:  *     Several page replacement parameters are also
                    138:  *     shared with this module, so that page allocation
                    139:  *     (done here in vm_page_alloc) can trigger the
                    140:  *     pageout daemon.
                    141:  */
                    142: int    vm_page_laundry_count = 0;
1.1.1.6 ! root      143: int    vm_page_external_laundry_count = 0;
1.1.1.2   root      144: 
1.1       root      145: 
                    146: /*
                    147:  *     The VM system has a couple of heuristics for deciding
                    148:  *     that pages are "uninteresting" and should be placed
                    149:  *     on the inactive queue as likely candidates for replacement.
                    150:  *     These variables let the heuristics be controlled at run-time
                    151:  *     to make experimentation easier.
                    152:  */
                    153: 
                    154: boolean_t vm_page_deactivate_behind = TRUE;
                    155: boolean_t vm_page_deactivate_hint = TRUE;
                    156: 
                    157: /*
                    158:  *     vm_page_bootstrap:
                    159:  *
                    160:  *     Initializes the resident memory module.
                    161:  *
                    162:  *     Allocates memory for the page cells, and
                    163:  *     for the object/offset-to-page hash table headers.
                    164:  *     Each page cell is initialized and placed on the free list.
                    165:  *     Returns the range of available kernel virtual memory.
                    166:  */
                    167: 
                    168: void vm_page_bootstrap(
                    169:        vm_offset_t *startp,
                    170:        vm_offset_t *endp)
                    171: {
                    172:        int i;
                    173: 
                    174:        /*
                    175:         *      Initialize the page queues.
                    176:         */
                    177: 
                    178:        simple_lock_init(&vm_page_queue_free_lock);
                    179:        simple_lock_init(&vm_page_queue_lock);
                    180: 
1.1.1.6 ! root      181:        list_init(&vm_page_queue_fictitious);
1.1       root      182: 
                    183:        /*
                    184:         *      Allocate (and initialize) the virtual-to-physical
                    185:         *      table hash buckets.
                    186:         *
                    187:         *      The number of buckets should be a power of two to
                    188:         *      get a good hash function.  The following computation
                    189:         *      chooses the first power of two that is greater
                    190:         *      than the number of physical pages in the system.
                    191:         */
                    192: 
                    193:        if (vm_page_bucket_count == 0) {
1.1.1.6 ! root      194:                unsigned long npages = vm_page_table_size();
1.1       root      195: 
                    196:                vm_page_bucket_count = 1;
                    197:                while (vm_page_bucket_count < npages)
                    198:                        vm_page_bucket_count <<= 1;
                    199:        }
                    200: 
                    201:        vm_page_hash_mask = vm_page_bucket_count - 1;
                    202: 
                    203:        if (vm_page_hash_mask & vm_page_bucket_count)
                    204:                printf("vm_page_bootstrap: WARNING -- strange page hash\n");
                    205: 
                    206:        vm_page_buckets = (vm_page_bucket_t *)
                    207:                pmap_steal_memory(vm_page_bucket_count *
                    208:                                  sizeof(vm_page_bucket_t));
                    209: 
                    210:        for (i = 0; i < vm_page_bucket_count; i++) {
1.1.1.4   root      211:                vm_page_bucket_t *bucket = &vm_page_buckets[i];
1.1       root      212: 
                    213:                bucket->pages = VM_PAGE_NULL;
                    214:                simple_lock_init(&bucket->lock);
                    215:        }
                    216: 
1.1.1.5   root      217:        vm_page_setup();
1.1       root      218: 
                    219:        virtual_space_start = round_page(virtual_space_start);
                    220:        virtual_space_end = trunc_page(virtual_space_end);
                    221: 
                    222:        *startp = virtual_space_start;
                    223:        *endp = virtual_space_end;
                    224: }
                    225: 
                    226: #ifndef        MACHINE_PAGES
                    227: /*
1.1.1.5   root      228:  *     We implement pmap_steal_memory with the help
                    229:  *     of two simpler functions, pmap_virtual_space and vm_page_bootalloc.
1.1       root      230:  */
                    231: 
                    232: vm_offset_t pmap_steal_memory(
                    233:        vm_size_t size)
                    234: {
                    235:        vm_offset_t addr, vaddr, paddr;
                    236: 
1.1.1.5   root      237:        size = round_page(size);
1.1       root      238: 
                    239:        /*
                    240:         *      If this is the first call to pmap_steal_memory,
                    241:         *      we have to initialize ourself.
                    242:         */
                    243: 
                    244:        if (virtual_space_start == virtual_space_end) {
                    245:                pmap_virtual_space(&virtual_space_start, &virtual_space_end);
                    246: 
                    247:                /*
                    248:                 *      The initial values must be aligned properly, and
                    249:                 *      we don't trust the pmap module to do it right.
                    250:                 */
                    251: 
                    252:                virtual_space_start = round_page(virtual_space_start);
                    253:                virtual_space_end = trunc_page(virtual_space_end);
                    254:        }
                    255: 
                    256:        /*
                    257:         *      Allocate virtual memory for this request.
                    258:         */
                    259: 
                    260:        addr = virtual_space_start;
                    261:        virtual_space_start += size;
                    262: 
                    263:        /*
                    264:         *      Allocate and map physical pages to back new virtual pages.
                    265:         */
                    266: 
                    267:        for (vaddr = round_page(addr);
                    268:             vaddr < addr + size;
                    269:             vaddr += PAGE_SIZE) {
1.1.1.5   root      270:                paddr = vm_page_bootalloc(PAGE_SIZE);
1.1       root      271: 
                    272:                /*
                    273:                 *      XXX Logically, these mappings should be wired,
                    274:                 *      but some pmap modules barf if they are.
                    275:                 */
                    276: 
                    277:                pmap_enter(kernel_pmap, vaddr, paddr,
                    278:                           VM_PROT_READ|VM_PROT_WRITE, FALSE);
                    279:        }
                    280: 
                    281:        return addr;
                    282: }
                    283: #endif /* MACHINE_PAGES */
                    284: 
                    285: /*
                    286:  *     Routine:        vm_page_module_init
                    287:  *     Purpose:
                    288:  *             Second initialization pass, to be done after
                    289:  *             the basic VM system is ready.
                    290:  */
                    291: void           vm_page_module_init(void)
                    292: {
1.1.1.3   root      293:        kmem_cache_init(&vm_page_cache, "vm_page", sizeof(struct vm_page), 0,
1.1.1.5   root      294:                        NULL, 0);
1.1       root      295: }
                    296: 
                    297: /*
                    298:  *     vm_page_hash:
                    299:  *
                    300:  *     Distributes the object/offset key pair among hash buckets.
                    301:  *
                    302:  *     NOTE:   To get a good hash function, the bucket count should
                    303:  *             be a power of two.
                    304:  */
                    305: #define vm_page_hash(object, offset) \
                    306:        (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \
                    307:                & vm_page_hash_mask)
                    308: 
                    309: /*
                    310:  *     vm_page_insert:         [ internal use only ]
                    311:  *
                    312:  *     Inserts the given mem entry into the object/object-page
                    313:  *     table and object list.
                    314:  *
                    315:  *     The object and page must be locked.
1.1.1.6 ! root      316:  *     The free page queue must not be locked.
1.1       root      317:  */
                    318: 
                    319: void vm_page_insert(
1.1.1.4   root      320:        vm_page_t       mem,
                    321:        vm_object_t     object,
                    322:        vm_offset_t     offset)
1.1       root      323: {
1.1.1.4   root      324:        vm_page_bucket_t *bucket;
1.1       root      325: 
                    326:        VM_PAGE_CHECK(mem);
                    327: 
1.1.1.6 ! root      328:        assert(!mem->active && !mem->inactive);
        !           329:        assert(!mem->external);
        !           330: 
        !           331:        if (!object->internal) {
        !           332:                mem->external = TRUE;
        !           333:                vm_object_external_pages++;
        !           334:        }
        !           335: 
1.1       root      336:        if (mem->tabled)
                    337:                panic("vm_page_insert");
                    338: 
                    339:        /*
                    340:         *      Record the object/offset pair in this page
                    341:         */
                    342: 
                    343:        mem->object = object;
                    344:        mem->offset = offset;
                    345: 
                    346:        /*
                    347:         *      Insert it into the object_object/offset hash table
                    348:         */
                    349: 
                    350:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
                    351:        simple_lock(&bucket->lock);
                    352:        mem->next = bucket->pages;
                    353:        bucket->pages = mem;
                    354:        simple_unlock(&bucket->lock);
                    355: 
                    356:        /*
                    357:         *      Now link into the object's list of backed pages.
                    358:         */
                    359: 
                    360:        queue_enter(&object->memq, mem, vm_page_t, listq);
                    361:        mem->tabled = TRUE;
                    362: 
                    363:        /*
                    364:         *      Show that the object has one more resident page.
                    365:         */
                    366: 
                    367:        object->resident_page_count++;
1.1.1.5   root      368:        assert(object->resident_page_count != 0);
1.1.1.3   root      369: 
1.1       root      370:        /*
                    371:         *      Detect sequential access and inactivate previous page.
                    372:         *      We ignore busy pages.
                    373:         */
                    374: 
                    375:        if (vm_page_deactivate_behind &&
                    376:            (offset == object->last_alloc + PAGE_SIZE)) {
                    377:                vm_page_t       last_mem;
                    378: 
                    379:                last_mem = vm_page_lookup(object, object->last_alloc);
                    380:                if ((last_mem != VM_PAGE_NULL) && !last_mem->busy)
                    381:                        vm_page_deactivate(last_mem);
                    382:        }
                    383:        object->last_alloc = offset;
                    384: }
                    385: 
                    386: /*
                    387:  *     vm_page_replace:
                    388:  *
                    389:  *     Exactly like vm_page_insert, except that we first
                    390:  *     remove any existing page at the given offset in object
                    391:  *     and we don't do deactivate-behind.
                    392:  *
                    393:  *     The object and page must be locked.
1.1.1.6 ! root      394:  *     The free page queue must not be locked.
1.1       root      395:  */
                    396: 
                    397: void vm_page_replace(
1.1.1.4   root      398:        vm_page_t       mem,
                    399:        vm_object_t     object,
                    400:        vm_offset_t     offset)
1.1       root      401: {
1.1.1.4   root      402:        vm_page_bucket_t *bucket;
1.1       root      403: 
                    404:        VM_PAGE_CHECK(mem);
                    405: 
1.1.1.6 ! root      406:        assert(!mem->active && !mem->inactive);
        !           407:        assert(!mem->external);
        !           408: 
        !           409:        if (!object->internal) {
        !           410:                mem->external = TRUE;
        !           411:                vm_object_external_pages++;
        !           412:        }
        !           413: 
1.1       root      414:        if (mem->tabled)
                    415:                panic("vm_page_replace");
                    416: 
                    417:        /*
                    418:         *      Record the object/offset pair in this page
                    419:         */
                    420: 
                    421:        mem->object = object;
                    422:        mem->offset = offset;
                    423: 
                    424:        /*
                    425:         *      Insert it into the object_object/offset hash table,
                    426:         *      replacing any page that might have been there.
                    427:         */
                    428: 
                    429:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
                    430:        simple_lock(&bucket->lock);
                    431:        if (bucket->pages) {
                    432:                vm_page_t *mp = &bucket->pages;
1.1.1.4   root      433:                vm_page_t m = *mp;
1.1       root      434:                do {
                    435:                        if (m->object == object && m->offset == offset) {
                    436:                                /*
                    437:                                 * Remove page from bucket and from object,
                    438:                                 * and return it to the free list.
                    439:                                 */
                    440:                                *mp = m->next;
                    441:                                queue_remove(&object->memq, m, vm_page_t,
                    442:                                             listq);
                    443:                                m->tabled = FALSE;
                    444:                                object->resident_page_count--;
1.1.1.6 ! root      445:                                VM_PAGE_QUEUES_REMOVE(m);
1.1       root      446: 
1.1.1.6 ! root      447:                                if (m->external) {
        !           448:                                        m->external = FALSE;
        !           449:                                        vm_object_external_pages--;
        !           450:                                }
1.1.1.3   root      451: 
1.1       root      452:                                /*
                    453:                                 * Return page to the free list.
                    454:                                 * Note the page is not tabled now, so this
                    455:                                 * won't self-deadlock on the bucket lock.
                    456:                                 */
                    457: 
                    458:                                vm_page_free(m);
                    459:                                break;
                    460:                        }
                    461:                        mp = &m->next;
                    462:                } while ((m = *mp) != 0);
                    463:                mem->next = bucket->pages;
                    464:        } else {
                    465:                mem->next = VM_PAGE_NULL;
                    466:        }
                    467:        bucket->pages = mem;
                    468:        simple_unlock(&bucket->lock);
                    469: 
                    470:        /*
                    471:         *      Now link into the object's list of backed pages.
                    472:         */
                    473: 
                    474:        queue_enter(&object->memq, mem, vm_page_t, listq);
                    475:        mem->tabled = TRUE;
                    476: 
                    477:        /*
                    478:         *      And show that the object has one more resident
                    479:         *      page.
                    480:         */
                    481: 
                    482:        object->resident_page_count++;
1.1.1.5   root      483:        assert(object->resident_page_count != 0);
1.1       root      484: }
                    485: 
                    486: /*
                    487:  *     vm_page_remove:         [ internal use only ]
                    488:  *
                    489:  *     Removes the given mem entry from the object/offset-page
1.1.1.6 ! root      490:  *     table, the object page list, and the page queues.
1.1       root      491:  *
                    492:  *     The object and page must be locked.
1.1.1.6 ! root      493:  *     The free page queue must not be locked.
1.1       root      494:  */
                    495: 
                    496: void vm_page_remove(
1.1.1.4   root      497:        vm_page_t               mem)
1.1       root      498: {
1.1.1.4   root      499:        vm_page_bucket_t        *bucket;
                    500:        vm_page_t               this;
1.1       root      501: 
                    502:        assert(mem->tabled);
                    503:        VM_PAGE_CHECK(mem);
                    504: 
                    505:        /*
                    506:         *      Remove from the object_object/offset hash table
                    507:         */
                    508: 
                    509:        bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
                    510:        simple_lock(&bucket->lock);
                    511:        if ((this = bucket->pages) == mem) {
                    512:                /* optimize for common case */
                    513: 
                    514:                bucket->pages = mem->next;
                    515:        } else {
1.1.1.4   root      516:                vm_page_t       *prev;
1.1       root      517: 
                    518:                for (prev = &this->next;
                    519:                     (this = *prev) != mem;
                    520:                     prev = &this->next)
                    521:                        continue;
                    522:                *prev = this->next;
                    523:        }
                    524:        simple_unlock(&bucket->lock);
                    525: 
                    526:        /*
                    527:         *      Now remove from the object's list of backed pages.
                    528:         */
                    529: 
                    530:        queue_remove(&mem->object->memq, mem, vm_page_t, listq);
                    531: 
                    532:        /*
                    533:         *      And show that the object has one fewer resident
                    534:         *      page.
                    535:         */
                    536: 
                    537:        mem->object->resident_page_count--;
                    538: 
                    539:        mem->tabled = FALSE;
1.1.1.3   root      540: 
1.1.1.6 ! root      541:        VM_PAGE_QUEUES_REMOVE(mem);
        !           542: 
        !           543:        if (mem->external) {
        !           544:                mem->external = FALSE;
        !           545:                vm_object_external_pages--;
        !           546:        }
1.1       root      547: }
                    548: 
                    549: /*
                    550:  *     vm_page_lookup:
                    551:  *
                    552:  *     Returns the page associated with the object/offset
                    553:  *     pair specified; if none is found, VM_PAGE_NULL is returned.
                    554:  *
                    555:  *     The object must be locked.  No side effects.
                    556:  */
                    557: 
                    558: vm_page_t vm_page_lookup(
1.1.1.4   root      559:        vm_object_t             object,
                    560:        vm_offset_t             offset)
1.1       root      561: {
1.1.1.4   root      562:        vm_page_t               mem;
                    563:        vm_page_bucket_t        *bucket;
1.1       root      564: 
                    565:        /*
                    566:         *      Search the hash table for this object/offset pair
                    567:         */
                    568: 
                    569:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
                    570: 
                    571:        simple_lock(&bucket->lock);
                    572:        for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
                    573:                VM_PAGE_CHECK(mem);
                    574:                if ((mem->object == object) && (mem->offset == offset))
                    575:                        break;
                    576:        }
                    577:        simple_unlock(&bucket->lock);
                    578:        return mem;
                    579: }
                    580: 
                    581: /*
                    582:  *     vm_page_rename:
                    583:  *
                    584:  *     Move the given memory entry from its
                    585:  *     current object to the specified target object/offset.
                    586:  *
                    587:  *     The object must be locked.
                    588:  */
                    589: void vm_page_rename(
1.1.1.4   root      590:        vm_page_t       mem,
                    591:        vm_object_t     new_object,
                    592:        vm_offset_t     new_offset)
1.1       root      593: {
                    594:        /*
                    595:         *      Changes to mem->object require the page lock because
                    596:         *      the pageout daemon uses that lock to get the object.
                    597:         */
                    598: 
                    599:        vm_page_lock_queues();
                    600:        vm_page_remove(mem);
                    601:        vm_page_insert(mem, new_object, new_offset);
                    602:        vm_page_unlock_queues();
                    603: }
                    604: 
1.1.1.5   root      605: static void vm_page_init_template(vm_page_t m)
                    606: {
                    607:        m->object = VM_OBJECT_NULL;     /* reset later */
                    608:        m->offset = 0;                  /* reset later */
                    609:        m->wire_count = 0;
                    610: 
                    611:        m->inactive = FALSE;
                    612:        m->active = FALSE;
                    613:        m->laundry = FALSE;
1.1.1.6 ! root      614:        m->external_laundry = FALSE;
1.1.1.5   root      615:        m->free = FALSE;
                    616:        m->external = FALSE;
                    617: 
                    618:        m->busy = TRUE;
                    619:        m->wanted = FALSE;
                    620:        m->tabled = FALSE;
                    621:        m->fictitious = FALSE;
                    622:        m->private = FALSE;
                    623:        m->absent = FALSE;
                    624:        m->error = FALSE;
                    625:        m->dirty = FALSE;
                    626:        m->precious = FALSE;
                    627:        m->reference = FALSE;
                    628: 
                    629:        m->page_lock = VM_PROT_NONE;
                    630:        m->unlock_request = VM_PROT_NONE;
                    631: }
                    632: 
1.1       root      633: /*
                    634:  *     vm_page_init:
                    635:  *
                    636:  *     Initialize the fields in a new page.
                    637:  *     This takes a structure with random values and initializes it
                    638:  *     so that it can be given to vm_page_release or vm_page_insert.
                    639:  */
                    640: void vm_page_init(
1.1.1.5   root      641:        vm_page_t       mem)
1.1       root      642: {
1.1.1.5   root      643:        vm_page_init_template(mem);
1.1       root      644: }
                    645: 
                    646: /*
                    647:  *     vm_page_grab_fictitious:
                    648:  *
                    649:  *     Remove a fictitious page from the free list.
                    650:  *     Returns VM_PAGE_NULL if there are no free pages.
                    651:  */
                    652: 
                    653: vm_page_t vm_page_grab_fictitious(void)
                    654: {
1.1.1.4   root      655:        vm_page_t m;
1.1       root      656: 
                    657:        simple_lock(&vm_page_queue_free_lock);
1.1.1.6 ! root      658:        if (list_empty(&vm_page_queue_fictitious)) {
        !           659:                m = VM_PAGE_NULL;
        !           660:        } else {
        !           661:                m = list_first_entry(&vm_page_queue_fictitious,
        !           662:                                     struct vm_page, node);
        !           663:                assert(m->fictitious);
        !           664:                list_remove(&m->node);
1.1       root      665:                m->free = FALSE;
1.1.1.6 ! root      666:                vm_page_fictitious_count--;
1.1       root      667:        }
                    668:        simple_unlock(&vm_page_queue_free_lock);
                    669: 
                    670:        return m;
                    671: }
                    672: 
                    673: /*
                    674:  *     vm_page_release_fictitious:
                    675:  *
                    676:  *     Release a fictitious page to the free list.
                    677:  */
                    678: 
1.1.1.5   root      679: static void vm_page_release_fictitious(
1.1.1.4   root      680:        vm_page_t m)
1.1       root      681: {
                    682:        simple_lock(&vm_page_queue_free_lock);
                    683:        if (m->free)
                    684:                panic("vm_page_release_fictitious");
                    685:        m->free = TRUE;
1.1.1.6 ! root      686:        list_insert_head(&vm_page_queue_fictitious, &m->node);
1.1       root      687:        vm_page_fictitious_count++;
                    688:        simple_unlock(&vm_page_queue_free_lock);
                    689: }
                    690: 
                    691: /*
                    692:  *     vm_page_more_fictitious:
                    693:  *
                    694:  *     Add more fictitious pages to the free list.
                    695:  *     Allowed to block.
                    696:  */
                    697: 
                    698: int vm_page_fictitious_quantum = 5;
                    699: 
                    700: void vm_page_more_fictitious(void)
                    701: {
1.1.1.4   root      702:        vm_page_t m;
1.1       root      703:        int i;
                    704: 
                    705:        for (i = 0; i < vm_page_fictitious_quantum; i++) {
1.1.1.3   root      706:                m = (vm_page_t) kmem_cache_alloc(&vm_page_cache);
1.1       root      707:                if (m == VM_PAGE_NULL)
                    708:                        panic("vm_page_more_fictitious");
                    709: 
1.1.1.5   root      710:                vm_page_init(m);
                    711:                m->phys_addr = vm_page_fictitious_addr;
1.1       root      712:                m->fictitious = TRUE;
                    713:                vm_page_release_fictitious(m);
                    714:        }
                    715: }
                    716: 
                    717: /*
                    718:  *     vm_page_convert:
                    719:  *
                    720:  *     Attempt to convert a fictitious page into a real page.
1.1.1.5   root      721:  *
                    722:  *     The object referenced by *MP must be locked.
1.1       root      723:  */
                    724: 
1.1.1.6 ! root      725: boolean_t vm_page_convert(struct vm_page **mp)
1.1       root      726: {
1.1.1.5   root      727:        struct vm_page *real_m, *fict_m;
                    728:        vm_object_t object;
                    729:        vm_offset_t offset;
                    730: 
                    731:        fict_m = *mp;
                    732: 
                    733:        assert(fict_m->fictitious);
                    734:        assert(fict_m->phys_addr == vm_page_fictitious_addr);
                    735:        assert(!fict_m->active);
                    736:        assert(!fict_m->inactive);
1.1       root      737: 
1.1.1.6 ! root      738:        real_m = vm_page_grab();
1.1       root      739:        if (real_m == VM_PAGE_NULL)
                    740:                return FALSE;
                    741: 
1.1.1.5   root      742:        object = fict_m->object;
                    743:        offset = fict_m->offset;
                    744:        vm_page_remove(fict_m);
                    745: 
                    746:        memcpy(&real_m->vm_page_header,
                    747:               &fict_m->vm_page_header,
                    748:               sizeof(*fict_m) - VM_PAGE_HEADER_SIZE);
                    749:        real_m->fictitious = FALSE;
                    750: 
                    751:        vm_page_insert(real_m, object, offset);
                    752: 
                    753:        assert(real_m->phys_addr != vm_page_fictitious_addr);
                    754:        assert(fict_m->fictitious);
                    755:        assert(fict_m->phys_addr == vm_page_fictitious_addr);
1.1       root      756: 
1.1.1.5   root      757:        vm_page_release_fictitious(fict_m);
                    758:        *mp = real_m;
1.1       root      759:        return TRUE;
                    760: }
                    761: 
                    762: /*
                    763:  *     vm_page_grab:
                    764:  *
                    765:  *     Remove a page from the free list.
                    766:  *     Returns VM_PAGE_NULL if the free list is too small.
                    767:  */
                    768: 
1.1.1.6 ! root      769: vm_page_t vm_page_grab(void)
1.1       root      770: {
1.1.1.4   root      771:        vm_page_t       mem;
1.1       root      772: 
                    773:        simple_lock(&vm_page_queue_free_lock);
                    774: 
                    775:        /*
1.1.1.6 ! root      776:         * XXX Mach has many modules that merely assume memory is
        !           777:         * directly mapped in kernel space. Instead of updating all
        !           778:         * users, we assume those which need specific physical memory
        !           779:         * properties will wire down their pages, either because
        !           780:         * they can't be paged (not part of an object), or with
        !           781:         * explicit VM calls. The strategy is then to let memory
        !           782:         * pressure balance the physical segments with pageable pages.
1.1       root      783:         */
1.1.1.5   root      784:        mem = vm_page_alloc_pa(0, VM_PAGE_SEL_DIRECTMAP, VM_PT_KERNEL);
                    785: 
                    786:        if (mem == NULL) {
                    787:                simple_unlock(&vm_page_queue_free_lock);
                    788:                return NULL;
                    789:        }
1.1       root      790: 
                    791:        mem->free = FALSE;
                    792:        simple_unlock(&vm_page_queue_free_lock);
                    793: 
                    794:        return mem;
                    795: }
                    796: 
1.1.1.6 ! root      797: phys_addr_t vm_page_grab_phys_addr(void)
1.1       root      798: {
1.1.1.6 ! root      799:        vm_page_t p = vm_page_grab();
1.1       root      800:        if (p == VM_PAGE_NULL)
                    801:                return -1;
                    802:        else
                    803:                return p->phys_addr;
                    804: }
                    805: 
                    806: /*
1.1.1.5   root      807:  *     vm_page_release:
1.1       root      808:  *
1.1.1.5   root      809:  *     Return a page to the free list.
1.1       root      810:  */
                    811: 
1.1.1.6 ! root      812: void vm_page_release(
1.1.1.5   root      813:        vm_page_t       mem,
1.1.1.6 ! root      814:        boolean_t       laundry,
        !           815:        boolean_t       external_laundry)
1.1       root      816: {
1.1.1.5   root      817:        simple_lock(&vm_page_queue_free_lock);
                    818:        if (mem->free)
                    819:                panic("vm_page_release");
                    820:        mem->free = TRUE;
                    821:        vm_page_free_pa(mem, 0);
1.1.1.6 ! root      822:        if (laundry) {
        !           823:                vm_page_laundry_count--;
1.1       root      824: 
1.1.1.6 ! root      825:                if (vm_page_laundry_count == 0) {
        !           826:                        vm_pageout_resume();
        !           827:                }
        !           828:        }
        !           829:        if (external_laundry) {
        !           830: 
        !           831:                /*
        !           832:                 *      If vm_page_external_laundry_count is negative,
        !           833:                 *      the pageout daemon isn't expecting to be
        !           834:                 *      notified.
        !           835:                 */
1.1       root      836: 
1.1.1.6 ! root      837:                if (vm_page_external_laundry_count > 0) {
        !           838:                        vm_page_external_laundry_count--;
        !           839: 
        !           840:                        if (vm_page_external_laundry_count == 0) {
        !           841:                                vm_pageout_resume();
        !           842:                        }
        !           843:                }
1.1.1.5   root      844:        }
1.1       root      845: 
1.1.1.5   root      846:        simple_unlock(&vm_page_queue_free_lock);
                    847: }
1.1       root      848: 
1.1.1.5   root      849: /*
                    850:  *     vm_page_grab_contig:
                    851:  *
                    852:  *     Remove a block of contiguous pages from the free list.
                    853:  *     Returns VM_PAGE_NULL if the request fails.
                    854:  */
1.1       root      855: 
1.1.1.5   root      856: vm_page_t vm_page_grab_contig(
                    857:        vm_size_t size,
                    858:        unsigned int selector)
                    859: {
                    860:        unsigned int i, order, nr_pages;
                    861:        vm_page_t mem;
1.1       root      862: 
1.1.1.5   root      863:        order = vm_page_order(size);
                    864:        nr_pages = 1 << order;
1.1       root      865: 
                    866:        simple_lock(&vm_page_queue_free_lock);
                    867: 
1.1.1.5   root      868:        /* TODO Allow caller to pass type */
                    869:        mem = vm_page_alloc_pa(order, selector, VM_PT_KERNEL);
1.1       root      870: 
1.1.1.5   root      871:        if (mem == NULL) {
                    872:                simple_unlock(&vm_page_queue_free_lock);
                    873:                return NULL;
1.1       root      874:        }
                    875: 
1.1.1.5   root      876:        for (i = 0; i < nr_pages; i++) {
                    877:                mem[i].free = FALSE;
1.1       root      878:        }
                    879: 
                    880:        simple_unlock(&vm_page_queue_free_lock);
                    881: 
1.1.1.5   root      882:        return mem;
1.1       root      883: }
                    884: 
                    885: /*
1.1.1.5   root      886:  *     vm_page_free_contig:
1.1       root      887:  *
1.1.1.5   root      888:  *     Return a block of contiguous pages to the free list.
1.1       root      889:  */
                    890: 
1.1.1.5   root      891: void vm_page_free_contig(vm_page_t mem, vm_size_t size)
1.1       root      892: {
1.1.1.5   root      893:        unsigned int i, order, nr_pages;
                    894: 
                    895:        order = vm_page_order(size);
                    896:        nr_pages = 1 << order;
                    897: 
1.1       root      898:        simple_lock(&vm_page_queue_free_lock);
                    899: 
1.1.1.5   root      900:        for (i = 0; i < nr_pages; i++) {
                    901:                if (mem[i].free)
                    902:                        panic("vm_page_free_contig");
                    903: 
                    904:                mem[i].free = TRUE;
                    905:        }
                    906: 
                    907:        vm_page_free_pa(mem, order);
1.1       root      908: 
                    909:        simple_unlock(&vm_page_queue_free_lock);
                    910: }
                    911: 
                    912: /*
                    913:  *     vm_page_alloc:
                    914:  *
                    915:  *     Allocate and return a memory cell associated
                    916:  *     with this VM object/offset pair.
                    917:  *
                    918:  *     Object must be locked.
                    919:  */
                    920: 
                    921: vm_page_t vm_page_alloc(
                    922:        vm_object_t     object,
                    923:        vm_offset_t     offset)
                    924: {
1.1.1.4   root      925:        vm_page_t       mem;
1.1       root      926: 
1.1.1.6 ! root      927:        mem = vm_page_grab();
1.1       root      928:        if (mem == VM_PAGE_NULL)
                    929:                return VM_PAGE_NULL;
                    930: 
                    931:        vm_page_lock_queues();
                    932:        vm_page_insert(mem, object, offset);
                    933:        vm_page_unlock_queues();
                    934: 
                    935:        return mem;
                    936: }
                    937: 
                    938: /*
                    939:  *     vm_page_free:
                    940:  *
                    941:  *     Returns the given page to the free list,
                    942:  *     disassociating it with any VM object.
                    943:  *
                    944:  *     Object and page queues must be locked prior to entry.
                    945:  */
                    946: void vm_page_free(
1.1.1.4   root      947:        vm_page_t       mem)
1.1       root      948: {
                    949:        if (mem->free)
                    950:                panic("vm_page_free");
                    951: 
1.1.1.6 ! root      952:        if (mem->tabled) {
1.1       root      953:                vm_page_remove(mem);
1.1.1.6 ! root      954:        }
        !           955: 
        !           956:        assert(!mem->active && !mem->inactive);
1.1       root      957: 
                    958:        if (mem->wire_count != 0) {
                    959:                if (!mem->private && !mem->fictitious)
                    960:                        vm_page_wire_count--;
                    961:                mem->wire_count = 0;
                    962:        }
                    963: 
                    964:        PAGE_WAKEUP_DONE(mem);
                    965: 
                    966:        if (mem->absent)
                    967:                vm_object_absent_release(mem->object);
                    968: 
                    969:        /*
                    970:         *      XXX The calls to vm_page_init here are
                    971:         *      really overkill.
                    972:         */
                    973: 
                    974:        if (mem->private || mem->fictitious) {
1.1.1.5   root      975:                vm_page_init(mem);
                    976:                mem->phys_addr = vm_page_fictitious_addr;
1.1       root      977:                mem->fictitious = TRUE;
                    978:                vm_page_release_fictitious(mem);
                    979:        } else {
1.1.1.6 ! root      980:                boolean_t laundry = mem->laundry;
        !           981:                boolean_t external_laundry = mem->external_laundry;
1.1.1.5   root      982:                vm_page_init(mem);
1.1.1.6 ! root      983:                vm_page_release(mem, laundry, external_laundry);
1.1       root      984:        }
                    985: }
                    986: 
                    987: /*
                    988:  *     vm_page_zero_fill:
                    989:  *
                    990:  *     Zero-fill the specified page.
                    991:  */
                    992: void vm_page_zero_fill(
                    993:        vm_page_t       m)
                    994: {
                    995:        VM_PAGE_CHECK(m);
                    996: 
                    997:        pmap_zero_page(m->phys_addr);
                    998: }
                    999: 
                   1000: /*
                   1001:  *     vm_page_copy:
                   1002:  *
                   1003:  *     Copy one page to another
                   1004:  */
                   1005: 
                   1006: void vm_page_copy(
                   1007:        vm_page_t       src_m,
                   1008:        vm_page_t       dest_m)
                   1009: {
                   1010:        VM_PAGE_CHECK(src_m);
                   1011:        VM_PAGE_CHECK(dest_m);
                   1012: 
                   1013:        pmap_copy_page(src_m->phys_addr, dest_m->phys_addr);
                   1014: }
                   1015: 
                   1016: #if    MACH_VM_DEBUG
                   1017: /*
                   1018:  *     Routine:        vm_page_info
                   1019:  *     Purpose:
                   1020:  *             Return information about the global VP table.
                   1021:  *             Fills the buffer with as much information as possible
                   1022:  *             and returns the desired size of the buffer.
                   1023:  *     Conditions:
                   1024:  *             Nothing locked.  The caller should provide
                   1025:  *             possibly-pageable memory.
                   1026:  */
                   1027: 
                   1028: unsigned int
                   1029: vm_page_info(
                   1030:        hash_info_bucket_t *info,
                   1031:        unsigned int    count)
                   1032: {
                   1033:        int i;
                   1034: 
                   1035:        if (vm_page_bucket_count < count)
                   1036:                count = vm_page_bucket_count;
                   1037: 
                   1038:        for (i = 0; i < count; i++) {
                   1039:                vm_page_bucket_t *bucket = &vm_page_buckets[i];
                   1040:                unsigned int bucket_count = 0;
                   1041:                vm_page_t m;
                   1042: 
                   1043:                simple_lock(&bucket->lock);
                   1044:                for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next)
                   1045:                        bucket_count++;
                   1046:                simple_unlock(&bucket->lock);
                   1047: 
                   1048:                /* don't touch pageable memory while holding locks */
                   1049:                info[i].hib_count = bucket_count;
                   1050:        }
                   1051: 
                   1052:        return vm_page_bucket_count;
                   1053: }
                   1054: #endif /* MACH_VM_DEBUG */
                   1055: 
1.1.1.3   root     1056: 
1.1       root     1057: #if    MACH_KDB
                   1058: #define        printf  kdbprintf
                   1059: 
                   1060: /*
                   1061:  *     Routine:        vm_page_print [exported]
                   1062:  */
                   1063: void           vm_page_print(p)
1.1.1.4   root     1064:        const vm_page_t p;
1.1       root     1065: {
                   1066:        iprintf("Page 0x%X: object 0x%X,", (vm_offset_t) p, (vm_offset_t) p->object);
1.1.1.4   root     1067:         printf(" offset 0x%X", p->offset);
1.1       root     1068:         printf("wire_count %d,", p->wire_count);
                   1069:         printf(" %s",
                   1070:                (p->active ? "active" : (p->inactive ? "inactive" : "loose")));
                   1071:         printf("%s",
                   1072:                (p->free ? " free" : ""));
                   1073:         printf("%s ",
                   1074:                (p->laundry ? " laundry" : ""));
                   1075:         printf("%s",
                   1076:                (p->dirty ? "dirty" : "clean"));
                   1077:         printf("%s",
                   1078:                (p->busy ? " busy" : ""));
                   1079:         printf("%s",
                   1080:                (p->absent ? " absent" : ""));
                   1081:         printf("%s",
                   1082:                (p->error ? " error" : ""));
                   1083:         printf("%s",
                   1084:                (p->fictitious ? " fictitious" : ""));
                   1085:         printf("%s",
                   1086:                (p->private ? " private" : ""));
                   1087:         printf("%s",
                   1088:                (p->wanted ? " wanted" : ""));
                   1089:         printf("%s,",
                   1090:                (p->tabled ? "" : "not_tabled"));
                   1091:         printf("phys_addr = 0x%X, lock = 0x%X, unlock_request = 0x%X\n",
1.1.1.4   root     1092:                p->phys_addr,
1.1       root     1093:                (vm_offset_t) p->page_lock,
                   1094:                (vm_offset_t) p->unlock_request);
                   1095: }
                   1096: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.