Annotation of kernel/vm/vm_resident.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1993-1987 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: /*
        !            51:  *     File:   vm/vm_page.c
        !            52:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            53:  *
        !            54:  *     Resident memory management module.
        !            55:  */
        !            56: 
        !            57: #import <mach/features.h>
        !            58: 
        !            59: #include <mach/vm_prot.h>
        !            60: #include <kern/counters.h>
        !            61: #include <kern/sched_prim.h>
        !            62: #include <kern/task.h>
        !            63: #include <kern/thread.h>
        !            64: #include <mach/vm_statistics.h>
        !            65: #include <kern/xpr.h>
        !            66: #include <kern/zalloc.h>
        !            67: #include <vm/pmap.h>
        !            68: #include <vm/vm_map.h>
        !            69: #include <vm/vm_page.h>
        !            70: #include <vm/vm_pageout.h>
        !            71: 
        !            72: #include <mach/vm_policy.h>
        !            73: 
        !            74: /*
        !            75:  *     Associated with eacn page of user-allocatable memory is a
        !            76:  *     page structure.
        !            77:  */
        !            78: 
        !            79: /*
        !            80:  *     These variables record the values returned by vm_page_bootstrap,
        !            81:  *     for debugging purposes.  The implementation of pmap_steal_memory
        !            82:  *     and pmap_startup here also uses them internally.
        !            83:  */
        !            84: 
        !            85: vm_offset_t virtual_space_start;
        !            86: vm_offset_t virtual_space_end;
        !            87: 
        !            88: /*
        !            89:  *     The vm_page_lookup() routine, which provides for fast
        !            90:  *     (virtual memory object, offset) to page lookup, employs
        !            91:  *     the following hash table.  The vm_page_{insert,remove}
        !            92:  *     routines install and remove associations in the table.
        !            93:  *     [This table is often called the virtual-to-physical,
        !            94:  *     or VP, table.]
        !            95:  */
        !            96: typedef struct {
        !            97:        decl_simple_lock_data(,lock)
        !            98:        vm_page_t pages;
        !            99: } vm_page_bucket_t;
        !           100: 
        !           101: vm_page_bucket_t *vm_page_buckets;             /* Array of buckets */
        !           102: unsigned int   vm_page_bucket_count = 0;       /* How big is array? */
        !           103: unsigned int   vm_page_hash_mask;              /* Mask for hash function */
        !           104: 
        !           105: /*
        !           106:  *     The virtual page size is currently implemented as a runtime
        !           107:  *     variable, but is constant once initialized using vm_set_page_size.
        !           108:  *     This initialization must be done in the machine-dependent
        !           109:  *     bootstrap sequence, before calling other machine-independent
        !           110:  *     initializations.
        !           111:  *
        !           112:  *     All references to the virtual page size outside this
        !           113:  *     module must use the PAGE_SIZE constant.
        !           114:  */
        !           115: vm_size_t      page_size  = 0;
        !           116: vm_size_t      page_mask;
        !           117: int            page_shift;
        !           118: 
        !           119: vm_offset_t    map_data;
        !           120: vm_size_t      map_data_size;
        !           121: 
        !           122: vm_offset_t    kentry_data;
        !           123: vm_size_t      kentry_data_size;
        !           124: 
        !           125: extern vm_offset_t     zdata;
        !           126: extern vm_size_t       zdata_size;
        !           127: 
        !           128: queue_head_t   vm_page_queue_free;
        !           129: queue_head_t   vm_page_queue_active;
        !           130: queue_head_t   vm_page_queue_inactive;
        !           131: simple_lock_data_t     vm_page_queue_lock;
        !           132: simple_lock_data_t     vm_page_queue_free_lock;
        !           133: 
        !           134: vm_page_t      vm_page_array;
        !           135: long           first_page;
        !           136: long           last_page;
        !           137: vm_offset_t    first_phys_addr;
        !           138: vm_offset_t    last_phys_addr;
        !           139: 
        !           140: int    vm_page_free_count;
        !           141: int    vm_page_active_count;
        !           142: int    vm_page_inactive_count;
        !           143: int    vm_page_wire_count;
        !           144: 
        !           145: /*
        !           146:  *     Several page replacement parameters are also
        !           147:  *     shared with this module, so that page allocation
        !           148:  *     (done here in vm_page_alloc) can trigger the
        !           149:  *     pageout daemon.
        !           150:  */
        !           151: int    vm_page_free_target = 0;
        !           152: int    vm_page_free_min = 0;
        !           153: int    vm_page_inactive_target = 0;
        !           154: int    vm_page_free_reserved = 0;
        !           155: int    vm_page_laundry_count = 0;
        !           156: 
        !           157: struct vm_page vm_page_template;
        !           158: 
        !           159: #if    SHOW_SPACE
        !           160: extern int     show_space;
        !           161: #endif SHOW_SPACE
        !           162: 
        !           163: /*
        !           164:  *     vm_set_page_size:
        !           165:  *
        !           166:  *     Sets the page size, perhaps based upon the memory
        !           167:  *     size.  Must be called before any use of page-size
        !           168:  *     dependent functions.
        !           169:  *
        !           170:  *     Sets page_shift and page_mask from page_size.
        !           171:  */
        !           172: void vm_set_page_size(void)
        !           173: {
        !           174:        page_mask = page_size - 1;
        !           175: 
        !           176:        if ((page_mask & page_size) != 0)
        !           177:                panic("vm_set_page_size: page size not a power of two");
        !           178: 
        !           179:        for (page_shift = 0; ; page_shift++)
        !           180:                if ((1 << page_shift) == page_size)
        !           181:                        break;
        !           182: }
        !           183: 
        !           184: /*
        !           185:  *     vm_page_startup:
        !           186:  *
        !           187:  *     Initializes the resident memory module.
        !           188:  *
        !           189:  *     Allocates memory for the page cells, and
        !           190:  *     for the object/offset-to-page hash table headers.
        !           191:  *     Each page cell is initialized and placed on the free list.
        !           192:  */
        !           193: 
        !           194: #if    SHOW_SPACE
        !           195: #define        PALLOC(name, type, num)                                 \
        !           196: MACRO_BEGIN                                                    \
        !           197:        (type *)(name) = (type *)                               \
        !           198:                vm_alloc_from_regions((num) * sizeof(type),     \
        !           199:                                       __alignof__(type));      \
        !           200:        bzero((name), (num) * sizeof(type));                    \
        !           201:        if (show_space) {                                       \
        !           202:                printf(#name " = %d (0x%x) bytes @%x,"          \
        !           203:                  " %d cells of %d bytes\n",                    \
        !           204:                  (num)*sizeof(type), (num)*sizeof(type), name, \
        !           205:                  num, sizeof(type));                           \
        !           206:        }                                                       \
        !           207: MACRO_END
        !           208: 
        !           209: #define        PALLOC_SIZE(name, size, type, num)                      \
        !           210: MACRO_BEGIN                                                    \
        !           211:        (size) = (num) * sizeof(type);                          \
        !           212:        (type *)(name) = (type *)                               \
        !           213:                vm_alloc_from_regions((size),                   \
        !           214:                                      __alignof__(type));       \
        !           215:        bzero((name), (size));                                  \
        !           216:        if (show_space) {                                       \
        !           217:                printf(#name " = %d (0x%x) bytes @%x,"          \
        !           218:                  " %d cells of %d bytes\n",                    \
        !           219:                  (size), (size), name,                         \
        !           220:                  num, sizeof(type));                           \
        !           221:        }                                                       \
        !           222: MACRO_END
        !           223: 
        !           224: #define        PALLOC_PAGES(name, type, size)                          \
        !           225: MACRO_BEGIN                                                    \
        !           226:        (size) = round_page(size);                              \
        !           227:        (type *)(name) = (type *)                               \
        !           228:                vm_alloc_from_regions((size), PAGE_SIZE);       \
        !           229:        bzero((name), (size));                                  \
        !           230:        if (show_space) {                                       \
        !           231:                printf(#name " = %d (0x%x) bytes @%x,"          \
        !           232:                  " %d pages of %d bytes\n",                    \
        !           233:                  (size), (size), name,                         \
        !           234:                  (size) / PAGE_SIZE, PAGE_SIZE);               \
        !           235:        }                                                       \
        !           236: MACRO_END
        !           237: #else  SHOW_SPACE
        !           238: #define        PALLOC(name, type, num)                                 \
        !           239: MACRO_BEGIN                                                    \
        !           240:        (type *)(name) = (type *)                               \
        !           241:                vm_alloc_from_regions((num) * sizeof(type),     \
        !           242:                                       __alignof__(type));      \
        !           243:        bzero((name), (num) * sizeof(type));                    \
        !           244: MACRO_END
        !           245: 
        !           246: #define        PALLOC_SIZE(name, size, type, num)                      \
        !           247: MACRO_BEGIN                                                    \
        !           248:        (size) = (num) * sizeof(type);                          \
        !           249:        (type *)(name) = (type *)                               \
        !           250:                vm_alloc_from_regions((size),                   \
        !           251:                                       __alignof__(type));      \
        !           252:        bzero((name), (size));                                  \
        !           253: MACRO_END
        !           254: 
        !           255: #define        PALLOC_PAGES(name, type, size)                          \
        !           256: MACRO_BEGIN                                                    \
        !           257:        (size) = round_page(size);                              \
        !           258:        (type *)(name) = (type *)                               \
        !           259:                vm_alloc_from_regions((size), PAGE_SIZE);       \
        !           260:        bzero((name), (size));                                  \
        !           261: MACRO_END
        !           262: #endif SHOW_SPACE
        !           263: 
        !           264: vm_offset_t vm_page_startup(mem_region, num_regions, vavail)
        !           265:        mem_region_t            mem_region;
        !           266:        int                     num_regions;
        !           267:        vm_offset_t             vavail;
        !           268: {
        !           269:        int                     mem_size;
        !           270:        mem_region_t            rp;
        !           271:        vm_page_t               m;
        !           272:        queue_t                 bucket;
        !           273:        int                     i;
        !           274:        vm_offset_t             pa;
        !           275:        extern vm_offset_t      virtual_avail;
        !           276: 
        !           277:        /*
        !           278:         *      Initialize the vm_page template.
        !           279:         */
        !           280: 
        !           281:        m = &vm_page_template;
        !           282:        m->object = VM_OBJECT_NULL;     /* reset later */
        !           283:        m->offset = 0;                  /* reset later */
        !           284:        m->wire_count = 0;
        !           285: 
        !           286: #if    OLD_VM_CODE
        !           287:        m->clean = TRUE;
        !           288:        m->nfspagereq = FALSE;
        !           289:        m->copy_on_write = FALSE;
        !           290:        m->asyncrw = FALSE;
        !           291: #endif
        !           292:        m->inactive = FALSE;
        !           293:        m->active = FALSE;
        !           294:        m->laundry = FALSE;
        !           295:        m->free = FALSE;
        !           296: 
        !           297:        m->busy = TRUE;
        !           298:        m->wanted = FALSE;
        !           299:        m->tabled = FALSE;
        !           300:        m->fictitious = FALSE;
        !           301:        m->private = FALSE;
        !           302:        m->absent = FALSE;
        !           303:        m->error = FALSE;
        !           304:        m->dirty = FALSE;
        !           305:        m->precious = FALSE;
        !           306:        m->reference = FALSE;
        !           307: 
        !           308:        m->phys_addr = 0;               /* reset later */
        !           309: 
        !           310:        m->page_lock = VM_PROT_NONE;
        !           311:        m->unlock_request = VM_PROT_NONE;
        !           312: 
        !           313:        /*
        !           314:         *      Initialize the locks
        !           315:         */
        !           316: 
        !           317:        simple_lock_init(&vm_page_queue_free_lock);
        !           318:        simple_lock_init(&vm_page_queue_lock);
        !           319: 
        !           320:        /*
        !           321:         *      Initialize the queue headers for the free queue,
        !           322:         *      the active queue and the inactive queue.
        !           323:         */
        !           324: 
        !           325:        queue_init(&vm_page_queue_free);
        !           326:        queue_init(&vm_page_queue_active);
        !           327:        queue_init(&vm_page_queue_inactive);
        !           328: 
        !           329:        /*
        !           330:         *      Allocate (and initialize) the virtual-to-physical
        !           331:         *      table hash buckets.
        !           332:         *
        !           333:         *      The number of buckets should be a power of two to
        !           334:         *      get a good hash function.  The following computation
        !           335:         *      chooses the first power of two that is greater
        !           336:         *      than the number of physical pages in the system.
        !           337:         */
        !           338:        mem_size = 0;
        !           339:        for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) {
        !           340:                mem_size += trunc_page(rp->last_phys_addr)
        !           341:                  - round_page(rp->first_phys_addr);
        !           342:        }
        !           343: 
        !           344:        if (vm_page_bucket_count == 0) {
        !           345:                vm_page_bucket_count = 1;
        !           346:                while (vm_page_bucket_count < atop(mem_size))
        !           347:                        vm_page_bucket_count <<= 1;
        !           348:        }
        !           349: 
        !           350:        vm_page_hash_mask = vm_page_bucket_count - 1;
        !           351: 
        !           352:        if (vm_page_hash_mask & vm_page_bucket_count)
        !           353:                printf("vm_page_bootstrap: WARNING -- strange page hash\n");
        !           354: 
        !           355:        PALLOC(vm_page_buckets, vm_page_bucket_t, vm_page_bucket_count);
        !           356: 
        !           357:        for (i = 0; i < vm_page_bucket_count; i++) {
        !           358:                register vm_page_bucket_t *bucket = &vm_page_buckets[i];
        !           359: 
        !           360:                bucket->pages = VM_PAGE_NULL;
        !           361:                simple_lock_init(&bucket->lock);
        !           362:        }
        !           363: 
        !           364:        /*
        !           365:         *      Steal pages for some zones that cannot be
        !           366:         *      dynamically allocated.
        !           367:         */
        !           368: #if    1
        !           369:        zdata_size = 8*PAGE_SIZE;
        !           370:        PALLOC_PAGES(zdata, void, zdata_size);
        !           371: #else
        !           372:        PALLOC_SIZE(zdata, zdata_size, struct zone, 40);
        !           373: #endif
        !           374:        PALLOC_SIZE(map_data, map_data_size, struct vm_map, 10);
        !           375: 
        !           376:        /*
        !           377:         *      Allow 2048 kernel map entries... this should be plenty
        !           378:         *      since people shouldn't be cluttering up the kernel
        !           379:         *      map (they should use their own maps).
        !           380:         */
        !           381:        PALLOC_SIZE(kentry_data, kentry_data_size, struct vm_map_entry, 2048);
        !           382: 
        !           383:        /*
        !           384:         * First make a pass over each region and allocate
        !           385:         * vm_page_arrays.  Later go back and size the pages in the
        !           386:         * region (since some of the region may have been taken
        !           387:         * by the vm_page_array).
        !           388:         */
        !           389:        for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) {
        !           390:                ASSERT(rp->first_phys_addr <= rp->last_phys_addr);
        !           391:                PALLOC(rp->vm_page_array, struct vm_page,
        !           392:                       atop(trunc_page(rp->last_phys_addr) -
        !           393:                            round_page(rp->first_phys_addr)));
        !           394:        }
        !           395:        vm_page_free_count = 0;
        !           396:        for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) {
        !           397:                rp->first_phys_addr = round_page(rp->first_phys_addr);
        !           398:                rp->last_phys_addr = trunc_page(rp->last_phys_addr);
        !           399:                rp->first_page = atop(rp->first_phys_addr);
        !           400:                rp->last_page = atop(rp->last_phys_addr);
        !           401:                rp->num_pages = rp->last_page - rp->first_page;
        !           402:                ASSERT((int)rp->num_pages >= 0);
        !           403:                vm_page_free_count += rp->num_pages;
        !           404: 
        !           405:                m = rp->vm_page_array;
        !           406:                pa = rp->first_phys_addr;
        !           407: 
        !           408:                for (i = 0; i < rp->num_pages; i += 1) {
        !           409:                        m->phys_addr = pa;
        !           410:                        queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
        !           411:                        m->free = TRUE;
        !           412:                        m++;
        !           413:                        pa += page_size;
        !           414:                }
        !           415:        }
        !           416: 
        !           417:        /*
        !           418:         *      Initialize vm_pages_needed lock here - don't wait for pageout
        !           419:         *      daemon  XXX
        !           420:         */
        !           421:        simple_lock_init(&vm_pages_needed_lock);
        !           422: 
        !           423:        return(virtual_avail);
        !           424: }
        !           425: 
        !           426: /*
        !           427:  *     vm_page_hash:
        !           428:  *
        !           429:  *     Distributes the object/offset key pair among hash buckets.
        !           430:  *
        !           431:  *     NOTE:   To get a good hash function, the bucket count should
        !           432:  *             be a power of two.
        !           433:  */
        !           434: #define vm_page_hash(object, offset) \
        !           435:        (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \
        !           436:                & vm_page_hash_mask)
        !           437: 
        !           438: /*
        !           439:  *     vm_page_insert:         [ internal use only ]
        !           440:  *
        !           441:  *     Inserts the given mem entry into the object/object-page
        !           442:  *     table and object list.
        !           443:  *
        !           444:  *     The object and page must be locked.
        !           445:  */
        !           446: 
        !           447: void vm_page_insert(
        !           448:        register vm_page_t      mem,
        !           449:        register vm_object_t    object,
        !           450:        register vm_offset_t    offset)
        !           451: {
        !           452:        register vm_page_bucket_t *bucket;
        !           453: 
        !           454:        VM_PAGE_CHECK(mem);
        !           455: 
        !           456:        if (mem->tabled)
        !           457:                panic("vm_page_insert");
        !           458: 
        !           459:        /*
        !           460:         *      Record the object/offset pair in this page
        !           461:         */
        !           462: 
        !           463:        mem->object = object;
        !           464:        mem->offset = offset;
        !           465: 
        !           466:        /*
        !           467:         *      Insert it into the object_object/offset hash table
        !           468:         */
        !           469: 
        !           470:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
        !           471: {
        !           472:        int spl = splimp();
        !           473: 
        !           474:        simple_lock(&bucket->lock);
        !           475:        mem->next = bucket->pages;
        !           476:        bucket->pages = mem;
        !           477:        simple_unlock(&bucket->lock);
        !           478:        (void) splx(spl);
        !           479: }
        !           480: 
        !           481:        /*
        !           482:         *      Now link into the object's list of backed pages.
        !           483:         */
        !           484: 
        !           485:        queue_enter(&object->memq, mem, vm_page_t, listq);
        !           486:        mem->tabled = TRUE;
        !           487: 
        !           488:        /*
        !           489:         *      Show that the object has one more resident page.
        !           490:         */
        !           491: 
        !           492:        object->resident_page_count++;
        !           493: }
        !           494: 
        !           495: /*
        !           496:  *     vm_page_remove:         [ internal use only ]
        !           497:  *
        !           498:  *     Removes the given mem entry from the object/offset-page
        !           499:  *     table and the object page list.
        !           500:  *
        !           501:  *     The object and page must be locked.
        !           502:  */
        !           503: 
        !           504: void vm_page_remove(
        !           505:        register vm_page_t      mem)
        !           506: {
        !           507:        register vm_page_bucket_t       *bucket;
        !           508:        register vm_page_t      this;
        !           509: 
        !           510:        assert(mem->tabled);
        !           511:        VM_PAGE_CHECK(mem);
        !           512: 
        !           513:        if (!mem->tabled)
        !           514:                return;
        !           515: 
        !           516:        /*
        !           517:         *      Remove from the object_object/offset hash table
        !           518:         */
        !           519: 
        !           520:        bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
        !           521: {
        !           522:        int spl = splimp();
        !           523: 
        !           524:        simple_lock(&bucket->lock);
        !           525:        if ((this = bucket->pages) == mem) {
        !           526:                /* optimize for common case */
        !           527: 
        !           528:                bucket->pages = mem->next;
        !           529:        } else {
        !           530:                register vm_page_t      *prev;
        !           531: 
        !           532:                for (prev = &this->next;
        !           533:                     (this = *prev) != mem;
        !           534:                     prev = &this->next)
        !           535:                        continue;
        !           536:                *prev = this->next;
        !           537:        }
        !           538:        simple_unlock(&bucket->lock);
        !           539:        splx(spl);
        !           540: }
        !           541: 
        !           542:        /*
        !           543:         *      Now remove from the object's list of backed pages.
        !           544:         */
        !           545: 
        !           546:        queue_remove(&mem->object->memq, mem, vm_page_t, listq);
        !           547: 
        !           548:        /*
        !           549:         *      And show that the object has one fewer resident
        !           550:         *      page.
        !           551:         */
        !           552: 
        !           553:        mem->object->resident_page_count--;
        !           554: 
        !           555:        mem->tabled = FALSE;
        !           556: }
        !           557: 
        !           558: /*
        !           559:  *     vm_page_lookup:
        !           560:  *
        !           561:  *     Returns the page associated with the object/offset
        !           562:  *     pair specified; if none is found, VM_PAGE_NULL is returned.
        !           563:  *
        !           564:  *     The object must be locked.  No side effects.
        !           565:  */
        !           566: 
        !           567: vm_page_t vm_page_lookup(
        !           568:        register vm_object_t    object,
        !           569:        register vm_offset_t    offset)
        !           570: {
        !           571:        register vm_page_t      mem;
        !           572:        register vm_page_bucket_t *bucket;
        !           573: 
        !           574:        /*
        !           575:         *      Search the hash table for this object/offset pair
        !           576:         */
        !           577: 
        !           578:        bucket = &vm_page_buckets[vm_page_hash(object, offset)];
        !           579: 
        !           580: {
        !           581:        int spl = splimp();
        !           582: 
        !           583:        simple_lock(&bucket->lock);
        !           584:        for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
        !           585:                VM_PAGE_CHECK(mem);
        !           586:                if ((mem->object == object) && (mem->offset == offset))
        !           587:                        break;
        !           588:        }
        !           589:        simple_unlock(&bucket->lock);
        !           590:        splx(spl);
        !           591: }
        !           592:        return mem;
        !           593: }
        !           594: 
        !           595: /*
        !           596:  *     vm_page_rename:
        !           597:  *
        !           598:  *     Move the given memory entry from its
        !           599:  *     current object to the specified target object/offset.
        !           600:  *
        !           601:  *     The object must be locked.
        !           602:  */
        !           603: void vm_page_rename(
        !           604:        register vm_page_t      mem,
        !           605:        register vm_object_t    new_object,
        !           606:        vm_offset_t             new_offset)
        !           607: {
        !           608:        /*
        !           609:         *      Changes to mem->object require the page lock because
        !           610:         *      the pageout daemon uses that lock to get the object.
        !           611:         */
        !           612: 
        !           613:        vm_page_lock_queues();
        !           614:        vm_page_remove(mem);
        !           615:        vm_page_insert(mem, new_object, new_offset);
        !           616:        vm_page_unlock_queues();
        !           617: }
        !           618: 
        !           619: /*
        !           620:  *     vm_page_init:
        !           621:  *
        !           622:  *     Initialize the given vm_page, entering it into
        !           623:  *     the VP table at the given (object, offset),
        !           624:  *     and noting its physical address.
        !           625:  *
        !           626:  *     Implemented using a template set up in vm_page_startup.
        !           627:  *     All fields except those passed as arguments are static.
        !           628:  */
        !           629: void           vm_page_init(mem, object, offset, phys_addr)
        !           630:        vm_page_t       mem;
        !           631:        vm_object_t     object;
        !           632:        vm_offset_t     offset;
        !           633:        vm_offset_t     phys_addr;
        !           634: {
        !           635: #define        vm_page_init(page, object, offset, pa)  { \
        !           636:                register \
        !           637:                vm_offset_t     a = (pa); \
        !           638:                *(page) = vm_page_template; \
        !           639:                (page)->phys_addr = a; \
        !           640:                vm_page_insert((page), (object), (offset)); \
        !           641:        }
        !           642: 
        !           643:        vm_page_init(mem, object, offset, phys_addr);
        !           644: }
        !           645: 
        !           646: /*
        !           647:  *     vm_page_alloc_sequential:
        !           648:  *
        !           649:  *     vm_page_alloc: is a macro  calling
        !           650:  *             vm_page_alloc_sequential(object,offset,TRUE)
        !           651:  *
        !           652:  *     Allocate and return a memory cell associated
        !           653:  *     with this VM object/offset pair. Don't perform sequential 
        !           654:  *     access checks if called from ICS.
        !           655:  *
        !           656:  *     Object must be locked.
        !           657:  */
        !           658: vm_page_t vm_page_alloc_sequential(object, offset, sequential_unmap)
        !           659:        vm_object_t     object;
        !           660:        vm_offset_t     offset;
        !           661:        boolean_t       sequential_unmap;
        !           662: {
        !           663:        register vm_page_t      mem;
        !           664:        int             spl;
        !           665: 
        !           666:        spl = splimp();
        !           667:        simple_lock(&vm_page_queue_free_lock);
        !           668: 
        !           669:        if (queue_empty(&vm_page_queue_free)) {
        !           670:                simple_unlock(&vm_page_queue_free_lock);
        !           671:                splx(spl);
        !           672:                return(VM_PAGE_NULL);
        !           673:        }
        !           674: 
        !           675:        if ((vm_page_free_count < vm_page_free_reserved) &&
        !           676:                        !current_thread()->vm_privilege) {
        !           677:                simple_unlock(&vm_page_queue_free_lock);
        !           678:                splx(spl);
        !           679:                return(VM_PAGE_NULL);
        !           680:        }
        !           681: 
        !           682:        queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq);
        !           683:        mem->free = FALSE;
        !           684: 
        !           685:        vm_page_free_count--;
        !           686:        simple_unlock(&vm_page_queue_free_lock);
        !           687:        splx(spl);
        !           688: 
        !           689:        vm_page_remove(mem);    /* in case it is still in hash table */
        !           690: 
        !           691:        vm_page_init(mem, object, offset, mem->phys_addr);
        !           692: 
        !           693:        /*
        !           694:         *      Decide if we should poke the pageout daemon.
        !           695:         *      We do this if the free count is less than the low
        !           696:         *      water mark, or if the free count is less than the high
        !           697:         *      water mark (but above the low water mark) and the inactive
        !           698:         *      count is less than its target.
        !           699:         *
        !           700:         *      We don't have the counts locked ... if they change a little,
        !           701:         *      it doesn't really matter.
        !           702:         */
        !           703: 
        !           704:        if ((vm_page_free_count < vm_page_free_min) ||
        !           705:                        ((vm_page_free_count < vm_page_free_target) &&
        !           706:                        (vm_page_inactive_count < vm_page_inactive_target))){
        !           707:                thread_wakeup(&vm_pages_needed);
        !           708:        }
        !           709: 
        !           710:        /*
        !           711:         *      Detect sequential access and inactivate previous page
        !           712:         */
        !           713:        if (object->policy & VM_POLICY_SEQUENTIAL && sequential_unmap &&
        !           714:            (abs(offset - object->last_alloc) == PAGE_SIZE)) {
        !           715:                vm_page_t       last_mem;
        !           716: 
        !           717:                last_mem = vm_page_lookup(object, object->last_alloc);
        !           718:                if (last_mem != VM_PAGE_NULL) {
        !           719:                        int     when;
        !           720:                        
        !           721:                        switch (object->policy) {
        !           722:                                case VM_POLICY_SEQ_DEACTIVATE:
        !           723:                                        when = VM_DEACTIVATE_SOON;
        !           724:                                        break;
        !           725:                                case VM_POLICY_SEQ_FREE:
        !           726:                                default:
        !           727:                                        when = VM_DEACTIVATE_NOW;
        !           728:                                        break;
        !           729:                        }
        !           730:                        vm_policy_apply(object, last_mem, when);
        !           731:                }
        !           732:        }
        !           733: //     else if (object->policy & VM_SEQUENTIAL && sequential_unmap)
        !           734: //             object->policy = VM_RANDOM;
        !           735: 
        !           736:        object->last_alloc = offset;
        !           737:        return(mem);
        !           738: }
        !           739: 
        !           740: /*
        !           741:  *     vm_page_free:
        !           742:  *
        !           743:  *     Returns the given page to the free list,
        !           744:  *     disassociating it with any VM object.
        !           745:  *
        !           746:  *     Object and page must be locked prior to entry.
        !           747:  */
        !           748: void vm_page_free(mem)
        !           749:        register vm_page_t      mem;
        !           750: {
        !           751:        vm_page_remove(mem);
        !           752:        if (!mem->free) {
        !           753:                vm_page_addfree(mem);
        !           754:        }
        !           755: }
        !           756: 
        !           757: void vm_page_addfree(mem)
        !           758:        register vm_page_t      mem;
        !           759: {
        !           760:        if (mem->active) {
        !           761:                queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
        !           762:                mem->active = FALSE;
        !           763:                vm_page_active_count--;
        !           764:        }
        !           765: 
        !           766:        if (mem->inactive) {
        !           767:                queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq);
        !           768:                mem->inactive = FALSE;
        !           769:                vm_page_inactive_count--;
        !           770:        }
        !           771: 
        !           772:        if (!mem->fictitious) {
        !           773:                int     spl;
        !           774: 
        !           775:                spl = splimp();
        !           776:                simple_lock(&vm_page_queue_free_lock);
        !           777:                queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq);
        !           778:                mem->free = TRUE;
        !           779:                vm_page_free_count++;
        !           780:                simple_unlock(&vm_page_queue_free_lock);
        !           781:                splx(spl);
        !           782:        }
        !           783: }
        !           784: 
        !           785: /*
        !           786:  *     vm_page_wire:
        !           787:  *
        !           788:  *     Mark this page as wired down by yet
        !           789:  *     another map, removing it from paging queues
        !           790:  *     as necessary.
        !           791:  *
        !           792:  *     The page queues must be locked.
        !           793:  */
        !           794: void vm_page_wire(mem)
        !           795:        register vm_page_t      mem;
        !           796: {
        !           797:        VM_PAGE_CHECK(mem);
        !           798: 
        !           799:        if (mem->wire_count == 0) {
        !           800:                if (mem->active) {
        !           801:                        queue_remove(&vm_page_queue_active, mem, vm_page_t,
        !           802:                                                pageq);
        !           803:                        vm_page_active_count--;
        !           804:                        mem->active = FALSE;
        !           805:                }
        !           806:                if (mem->inactive) {
        !           807:                        queue_remove(&vm_page_queue_inactive, mem, vm_page_t,
        !           808:                                                pageq);
        !           809:                        vm_page_inactive_count--;
        !           810:                        mem->inactive = FALSE;
        !           811:                }
        !           812:                if (mem->free) {
        !           813:                        queue_remove(&vm_page_queue_free, mem, vm_page_t,
        !           814:                                                        pageq);
        !           815:                        vm_page_free_count--;
        !           816:                        mem->free = FALSE;
        !           817:                }
        !           818:                vm_page_wire_count++;
        !           819:        }
        !           820:        mem->wire_count++;
        !           821: }
        !           822: 
        !           823: /*
        !           824:  *     vm_page_unwire:
        !           825:  *
        !           826:  *     Release one wiring of this page, potentially
        !           827:  *     enabling it to be paged again.
        !           828:  *
        !           829:  *     The page queues must be locked.
        !           830:  */
        !           831: void vm_page_unwire(mem)
        !           832:        register vm_page_t      mem;
        !           833: {
        !           834:        VM_PAGE_CHECK(mem);
        !           835: 
        !           836:        if (--mem->wire_count == 0) {
        !           837:                queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
        !           838:                vm_page_active_count++;
        !           839:                mem->active = TRUE;
        !           840:                vm_page_wire_count--;
        !           841:        }
        !           842: }
        !           843: 
        !           844: /*
        !           845:  *     _vm_page_deactivate:
        !           846:  *
        !           847:  *     Internal routine to Returns the given page to the inactive list,
        !           848:  *     Page is put at the head of the inactive list if age is TRUE.
        !           849:  *     indicating that no physical maps have access
        !           850:  *     to this page.  [Used by the physical mapping system.]
        !           851:  *
        !           852:  *     The page queues must be locked.
        !           853:  */
        !           854: static void _vm_page_deactivate(m, age)
        !           855:        register vm_page_t      m;
        !           856:        register boolean_t age;
        !           857: {
        !           858:        VM_PAGE_CHECK(m);
        !           859: 
        !           860:        /*
        !           861:         *      Only move active pages -- ignore locked or already
        !           862:         *      inactive ones.
        !           863:         */
        !           864: 
        !           865:        if (m->active) {
        !           866:                pmap_clear_reference(VM_PAGE_TO_PHYS(m));
        !           867:                queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
        !           868:                if (age)
        !           869:                        queue_enter_first(&vm_page_queue_inactive, m, vm_page_t, pageq);
        !           870:                else
        !           871:                        queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
        !           872:                m->active = FALSE;
        !           873:                m->inactive = TRUE;
        !           874:                vm_page_active_count--;
        !           875:                vm_page_inactive_count++;
        !           876:                if (m->clean && pmap_is_modified(VM_PAGE_TO_PHYS(m)))
        !           877:                        m->clean = FALSE;
        !           878:                m->laundry = !m->clean;
        !           879:        }
        !           880: }
        !           881: 
        !           882: /*
        !           883:  *     vm_page_deactivate:
        !           884:  *
        !           885:  *     Returns the given page to the inactive list,
        !           886:  *     indicating that no physical maps have access
        !           887:  *     to this page.  [Used by the physical mapping system.]
        !           888:  *
        !           889:  *     The page queues must be locked.
        !           890:  */
        !           891: void vm_page_deactivate(m)
        !           892:        register vm_page_t      m;
        !           893: {
        !           894:        _vm_page_deactivate(m, FALSE);
        !           895: }
        !           896: 
        !           897: /*
        !           898:  *     vm_page_deactivate_first:
        !           899:  *
        !           900:  *     Returns the given page to the head of inactive list,
        !           901:  *     indicating that no physical maps have access
        !           902:  *     to this page.  [Used by the physical mapping system.]
        !           903:  *
        !           904:  *     The page queues must be locked.
        !           905:  */
        !           906: void vm_page_deactivate_first(m)
        !           907:        register vm_page_t      m;
        !           908: {
        !           909:        _vm_page_deactivate(m, FALSE);
        !           910: }
        !           911: 
        !           912: /*
        !           913:  *     vm_page_activate:
        !           914:  *
        !           915:  *     Put the specified page on the active list (if appropriate).
        !           916:  *
        !           917:  *     The page queues must be locked.
        !           918:  */
        !           919: 
        !           920: void vm_page_activate(m)
        !           921:        register vm_page_t      m;
        !           922: {
        !           923:        VM_PAGE_CHECK(m);
        !           924: 
        !           925: 
        !           926:        if (m->inactive) {
        !           927:                queue_remove(&vm_page_queue_inactive, m, vm_page_t,
        !           928:                                                pageq);
        !           929:                vm_page_inactive_count--;
        !           930:                m->inactive = FALSE;
        !           931:        }
        !           932:        if (m->free) {
        !           933:                queue_remove(&vm_page_queue_free, m, vm_page_t,
        !           934:                                                pageq);
        !           935:                vm_page_free_count--;
        !           936:                m->free = FALSE;
        !           937:        }
        !           938:        if (m->wire_count == 0) {
        !           939:                if (m->active)
        !           940:                        panic("vm_page_activate: already active");
        !           941: 
        !           942:                queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
        !           943:                m->active = TRUE;
        !           944:                vm_page_active_count++;
        !           945:        }
        !           946: }
        !           947: 
        !           948: /*
        !           949:  *     vm_page_zero_fill:
        !           950:  *
        !           951:  *     Zero-fill the specified page.
        !           952:  *     Written as a standard pagein routine, to
        !           953:  *     be used by the zero-fill object.
        !           954:  */
        !           955: 
        !           956: boolean_t vm_page_zero_fill(m)
        !           957:        vm_page_t       m;
        !           958: {
        !           959:        VM_PAGE_CHECK(m);
        !           960: 
        !           961:        pmap_zero_page(VM_PAGE_TO_PHYS(m));
        !           962:        return(TRUE);
        !           963: }
        !           964: 
        !           965: /*
        !           966:  *     vm_page_copy:
        !           967:  *
        !           968:  *     Copy one page to another
        !           969:  */
        !           970: 
        !           971: void vm_page_copy(src_m, dest_m)
        !           972:        vm_page_t       src_m;
        !           973:        vm_page_t       dest_m;
        !           974: {
        !           975:        VM_PAGE_CHECK(src_m);
        !           976:        VM_PAGE_CHECK(dest_m);
        !           977: 
        !           978:        pmap_copy_page(VM_PAGE_TO_PHYS(src_m), VM_PAGE_TO_PHYS(dest_m));
        !           979: }
        !           980: 
        !           981: 
        !           982: /*
        !           983:  *     vm_page_to_phys:
        !           984:  *
        !           985:  *     return the physical page, this routine is here so that
        !           986:  *     loadable drivers like macfs do not have to deref vm_page_t 
        !           987:  *     directly.
        !           988:  */
        !           989: 
        !           990: vm_offset_t
        !           991: vm_page_to_phys(m)
        !           992:        vm_page_t       m;
        !           993: {
        !           994:        return(VM_PAGE_TO_PHYS(m));
        !           995: }

unix.superglobalmegacorp.com

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