Annotation of kernel/vm/vm_object.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_object.c
        !            52:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            53:  *
        !            54:  *     Virtual memory object module.
        !            55:  */
        !            56: 
        !            57: #include <norma_vm.h>
        !            58: #include <mach_pagemap.h>
        !            59: 
        !            60: #if    NORMA_VM
        !            61: #include <norma/xmm_server_rename.h>
        !            62: #endif /* NORMA_VM */
        !            63: 
        !            64: #include <mach/memory_object.h>
        !            65: #include <mach/memory_object_default.h>
        !            66: #include <mach/memory_object_user.h>
        !            67: #include <mach/vm_param.h>
        !            68: #include <ipc/ipc_port.h>
        !            69: #include <ipc/ipc_space.h>
        !            70: #include <kern/assert.h>
        !            71: #include <kern/lock.h>
        !            72: #include <kern/queue.h>
        !            73: #include <kern/xpr.h>
        !            74: #include <kern/zalloc.h>
        !            75: #include <vm/memory_object.h>
        !            76: #include <vm/vm_fault.h>
        !            77: #include <vm/vm_map.h>
        !            78: #include <vm/vm_object.h>
        !            79: #include <vm/vm_page.h>
        !            80: #include <vm/vm_pageout.h>
        !            81: 
        !            82: #include <mach/vm_policy.h>
        !            83: 
        !            84: 
        !            85: void memory_object_release(
        !            86:        ipc_port_t      pager,
        !            87:        pager_request_t pager_request,
        !            88:        ipc_port_t      pager_name); /* forward */
        !            89: 
        !            90: void vm_object_deactivate_pages(vm_object_t);
        !            91: 
        !            92: /*
        !            93:  *     Virtual memory objects maintain the actual data
        !            94:  *     associated with allocated virtual memory.  A given
        !            95:  *     page of memory exists within exactly one object.
        !            96:  *
        !            97:  *     An object is only deallocated when all "references"
        !            98:  *     are given up.  Only one "reference" to a given
        !            99:  *     region of an object should be writeable.
        !           100:  *
        !           101:  *     Associated with each object is a list of all resident
        !           102:  *     memory pages belonging to that object; this list is
        !           103:  *     maintained by the "vm_page" module, but locked by the object's
        !           104:  *     lock.
        !           105:  *
        !           106:  *     Each object also records a "pager" routine which is
        !           107:  *     used to retrieve (and store) pages to the proper backing
        !           108:  *     storage.  In addition, objects may be backed by other
        !           109:  *     objects from which they were virtual-copied.
        !           110:  *
        !           111:  *     The only items within the object structure which are
        !           112:  *     modified after time of creation are:
        !           113:  *             reference count         locked by object's lock
        !           114:  *             pager routine           locked by object's lock
        !           115:  *
        !           116:  */
        !           117: 
        !           118: struct zone    *vm_object_zone;        /* vm backing store zone */
        !           119: 
        !           120: struct vm_object       kernel_object_store, vm_submap_object_store;
        !           121: #define        VM_OBJECT_HASH_COUNT            1024
        !           122: #define        VM_OBJECT_MEMORY_UNIT           (1024 * 1024)
        !           123: #define        VM_OBJECTS_PER_MEMORY_UNIT      50
        !           124: int            vm_cache_max;           /* set in vm_object_init */
        !           125: 
        !           126: queue_head_t   vm_object_hashtable[VM_OBJECT_HASH_COUNT];
        !           127: struct zone    *object_hash_zone;
        !           128: 
        !           129: struct vm_object_hash_entry {
        !           130:        queue_chain_t           hash_links;     /* hash chain links */
        !           131:        vm_object_t             object;         /* object we represent */
        !           132: };
        !           133: 
        !           134: typedef struct vm_object_hash_entry    *vm_object_hash_entry_t;
        !           135: 
        !           136: queue_head_t   vm_object_cached_list;  /* list of objects persisting */
        !           137: int            vm_object_cached;       /* size of cached list */
        !           138: simple_lock_data_t     vm_cache_lock;  /* lock for object cache */
        !           139: 
        !           140: queue_head_t   vm_object_list;         /* list of allocated objects */
        !           141: long           vm_object_count;        /* count of all objects */
        !           142: simple_lock_data_t     vm_object_list_lock;
        !           143:                                        /* lock for object list and count */
        !           144: 
        !           145: vm_object_t    kernel_object;          /* the single kernel object */
        !           146: 
        !           147: #define        vm_object_cache_lock()          simple_lock(&vm_cache_lock)
        !           148: #define        vm_object_cache_unlock()        simple_unlock(&vm_cache_lock)
        !           149: 
        !           150: struct vm_object       vm_object_template;
        !           151: 
        !           152: long   object_collapses = 0;
        !           153: long   object_bypasses  = 0;
        !           154: 
        !           155: /*
        !           156:  *     vm_object_init:
        !           157:  *
        !           158:  *     Initialize the VM objects module.
        !           159:  */
        !           160: void vm_object_init()
        !           161: {
        !           162:        register int    i;
        !           163: 
        !           164:        vm_object_zone = zinit((vm_size_t) sizeof(struct vm_object),
        !           165:                                round_page(512*1024),
        !           166:                                0, FALSE, "objects");
        !           167: 
        !           168:        object_hash_zone = zinit(
        !           169:                                (vm_size_t)sizeof(struct vm_object_hash_entry),
        !           170:                                100*1024, 0, FALSE,
        !           171:                                "object hash zone");
        !           172: 
        !           173:        queue_init(&vm_object_cached_list);
        !           174:        queue_init(&vm_object_list);
        !           175:        vm_object_count = 0;
        !           176:        simple_lock_init(&vm_cache_lock);
        !           177:        simple_lock_init(&vm_object_list_lock);
        !           178: 
        !           179:        for (i = 0; i < VM_OBJECT_HASH_COUNT; i++)
        !           180:                queue_init(&vm_object_hashtable[i]);
        !           181: 
        !           182:        /*
        !           183:         *  Parameterize the size of the cache based on the amount of
        !           184:         *  physical memory available.
        !           185:         */
        !           186:        vm_cache_max = mem_size / VM_OBJECT_MEMORY_UNIT;
        !           187:        vm_cache_max *= VM_OBJECTS_PER_MEMORY_UNIT;
        !           188:                
        !           189:        if (vm_cache_max > 2500)
        !           190:                vm_cache_max = 2500;
        !           191: 
        !           192:        /*
        !           193:         *      Fill in a template object, for quick initialization
        !           194:         */
        !           195: 
        !           196:        vm_object_template.ref_count = 1;
        !           197:        vm_object_template.resident_page_count = 0;
        !           198:        vm_object_template.size = 0;
        !           199:        vm_object_template.can_persist = FALSE;
        !           200:        vm_object_template.paging_in_progress = 0;
        !           201:        vm_object_template.copy = VM_OBJECT_NULL;
        !           202: 
        !           203:        vm_object_template.pager = vm_pager_null;
        !           204:        vm_object_template.pager_request = PORT_NULL;
        !           205:        vm_object_template.pager_name = PORT_NULL;
        !           206:        vm_object_template.pager_ready = FALSE;
        !           207:        vm_object_template.pager_creating = FALSE;
        !           208:        vm_object_template.internal = TRUE;
        !           209:        vm_object_template.paging_offset = 0;
        !           210:        vm_object_template.shadow = VM_OBJECT_NULL;
        !           211:        vm_object_template.shadow_offset = (vm_offset_t) 0;
        !           212:        vm_object_template.last_alloc = (vm_offset_t) 0;
        !           213:        vm_object_template.policy = (vm_offset_t) VM_POLICY_SEQ_DEACTIVATE;
        !           214: 
        !           215:        /*
        !           216:         *      Initialize the "kernel object"
        !           217:         */
        !           218: 
        !           219:        kernel_object = &kernel_object_store;
        !           220:        _vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
        !           221:                        kernel_object);
        !           222: 
        !           223:        /*
        !           224:         *      Initialize the "submap object".  Make it as large as the
        !           225:         *      kernel object so that no limit is imposed on submap sizes.
        !           226:         */
        !           227: 
        !           228:        vm_submap_object = &vm_submap_object_store;
        !           229:        _vm_object_allocate(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
        !           230:                        vm_submap_object);
        !           231: }
        !           232: 
        !           233: /*
        !           234:  *     vm_object_allocate:
        !           235:  *
        !           236:  *     Returns a new object with the given size.
        !           237:  */
        !           238: 
        !           239: vm_object_t vm_object_allocate(size)
        !           240:        vm_size_t       size;
        !           241: {
        !           242:        register vm_object_t    result;
        !           243: 
        !           244:        result = (vm_object_t) zalloc(vm_object_zone);
        !           245: 
        !           246:        _vm_object_allocate(size, result);
        !           247: 
        !           248:        return(result);
        !           249: }
        !           250: 
        !           251: _vm_object_allocate(size, object)
        !           252:        vm_size_t               size;
        !           253:        register vm_object_t    object;
        !           254: {
        !           255:        (*object) = vm_object_template;
        !           256:        queue_init(&object->memq);
        !           257:        vm_object_lock_init(object);
        !           258:        object->size = size;
        !           259:        simple_lock(&vm_object_list_lock);
        !           260:        queue_enter(&vm_object_list, object, vm_object_t, object_list);
        !           261:        vm_object_count++;
        !           262:        simple_unlock(&vm_object_list_lock);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  *     vm_object_reference:
        !           267:  *
        !           268:  *     Gets another reference to the given object.
        !           269:  */
        !           270: void vm_object_reference(object)
        !           271:        register vm_object_t    object;
        !           272: {
        !           273:        if (object == VM_OBJECT_NULL)
        !           274:                return;
        !           275: 
        !           276:        vm_object_lock(object);
        !           277:        object->ref_count++;
        !           278:        vm_object_unlock(object);
        !           279: }
        !           280: 
        !           281: /*
        !           282:  *     vm_object_deallocate:
        !           283:  *
        !           284:  *     Release a reference to the specified object,
        !           285:  *     gained either through a vm_object_allocate
        !           286:  *     or a vm_object_reference call.  When all references
        !           287:  *     are gone, storage associated with this object
        !           288:  *     may be relinquished.
        !           289:  *
        !           290:  *     No object may be locked.
        !           291:  */
        !           292: void vm_object_deallocate(object)
        !           293:        register vm_object_t    object;
        !           294: {
        !           295:        vm_object_t     temp;
        !           296: 
        !           297:        while (object != VM_OBJECT_NULL) {
        !           298: 
        !           299:                /*
        !           300:                 *      The cache holds a reference (uncounted) to
        !           301:                 *      the object; we must lock it before removing
        !           302:                 *      the object.
        !           303:                 */
        !           304: 
        !           305:                vm_object_cache_lock();
        !           306: 
        !           307:                /*
        !           308:                 *      Lose the reference
        !           309:                 */
        !           310:                vm_object_lock(object);
        !           311:                if (--(object->ref_count) != 0) {
        !           312: 
        !           313:                        /*
        !           314:                         *      If there are still references, then
        !           315:                         *      we are done.
        !           316:                         */
        !           317:                        vm_object_unlock(object);
        !           318:                        vm_object_cache_unlock();
        !           319:                        return;
        !           320:                }
        !           321: 
        !           322:                /*
        !           323:                 *      See if this object can persist.  If so, enter
        !           324:                 *      it in the cache, then deactivate all of its
        !           325:                 *      pages.
        !           326:                 */
        !           327: 
        !           328:                if (object->can_persist) {
        !           329:                        
        !           330:                        if (object->resident_page_count > 0) {
        !           331:                                queue_enter(&vm_object_cached_list, object,
        !           332:                                        vm_object_t, cached_list);
        !           333:                                vm_object_cached++;
        !           334:                                vm_object_cache_unlock();
        !           335:        
        !           336:                                vm_object_deactivate_pages(object);
        !           337:                                vm_object_unlock(object);
        !           338:        
        !           339:                                vm_object_cache_trim();
        !           340:                                return;
        !           341:                        }
        !           342:                        else {
        !           343:                                object->can_persist = FALSE;
        !           344:                        }
        !           345:                }
        !           346: 
        !           347:                /*
        !           348:                 *      Make sure no one can look us up now.
        !           349:                 */
        !           350:                vm_object_remove(object->pager);
        !           351:                vm_object_cache_unlock();
        !           352: 
        !           353:                temp = object->shadow;
        !           354:                vm_object_terminate(object);
        !           355:                        /* unlocks and deallocates object */
        !           356:                object = temp;
        !           357:        }
        !           358: }
        !           359: 
        !           360: 
        !           361: #define                vm_object_pager_terminate(object) {                     \
        !           362:        if ((object)->pager != vm_pager_null) {                         \
        !           363:                port_release((object)->pager);                          \
        !           364:                (object)->pager = vm_pager_null;                        \
        !           365:        }                                                               \
        !           366:        if ((object)->pager_request != PORT_NULL) {                     \
        !           367:                port_deallocate(kernel_task, (object)->pager_request);  \
        !           368:                (object)->pager_request = PORT_NULL;                    \
        !           369:        }                                                               \
        !           370:        if ((object)->pager_name != PORT_NULL) {                        \
        !           371:                port_deallocate(kernel_task, (object)->pager_name);     \
        !           372:                (object)->pager_name = PORT_NULL;                       \
        !           373:        }                                                               \
        !           374: }
        !           375: 
        !           376: /*
        !           377:  *     vm_object_terminate actually destroys the specified object, freeing
        !           378:  *     up all previously used resources.
        !           379:  *
        !           380:  *     The object must be locked.
        !           381:  */
        !           382: void vm_object_terminate(object)
        !           383:        register vm_object_t    object;
        !           384: {
        !           385:        register vm_page_t      p;
        !           386:        vm_page_t               next_p;
        !           387:        vm_object_t             shadow_object;
        !           388: 
        !           389:        /*
        !           390:         *      Detach the object from its shadow if we are the shadow's
        !           391:         *      copy.
        !           392:         */
        !           393:        if ((shadow_object = object->shadow) != VM_OBJECT_NULL) {
        !           394:                vm_object_lock(shadow_object);
        !           395:                if (shadow_object->copy == object)
        !           396:                        shadow_object->copy = VM_OBJECT_NULL;
        !           397:                else if (shadow_object->copy != VM_OBJECT_NULL)
        !           398:                        panic("vm_object_terminate: copy/shadow inconsistency");
        !           399:                vm_object_unlock(shadow_object);
        !           400:        }
        !           401: 
        !           402:        /*
        !           403:         *      Wait until the pageout daemon is through
        !           404:         *      with the object.
        !           405:         */
        !           406: 
        !           407:        while (object->paging_in_progress != 0) {
        !           408:                vm_object_sleep(object, object, FALSE);
        !           409:                vm_object_lock(object);
        !           410:        }
        !           411: 
        !           412: 
        !           413:        /*
        !           414:         *      While the paging system is locked,
        !           415:         *      pull the object's pages off the active
        !           416:         *      and inactive queues.  This keeps the
        !           417:         *      pageout daemon from playing with them
        !           418:         *      during vm_pager_deallocate.
        !           419:         *
        !           420:         *      We can't free the pages yet, because the
        !           421:         *      object's pager may have to write them out
        !           422:         *      before deallocating the paging space.
        !           423:         */
        !           424: 
        !           425:        p = (vm_page_t) queue_first(&object->memq);
        !           426:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !           427:                VM_PAGE_CHECK(p);
        !           428: 
        !           429:                vm_page_lock_queues();
        !           430:                if (p->active) {
        !           431:                        queue_remove(&vm_page_queue_active, p, vm_page_t,
        !           432:                                                pageq);
        !           433:                        p->active = FALSE;
        !           434:                        vm_page_active_count--;
        !           435:                }
        !           436: 
        !           437:                if (p->inactive) {
        !           438:                        queue_remove(&vm_page_queue_inactive, p, vm_page_t,
        !           439:                                                pageq);
        !           440:                        p->inactive = FALSE;
        !           441:                        vm_page_inactive_count--;
        !           442:                }
        !           443:                /*
        !           444:                 *      If we are on the free list just free ourselves now to make sure
        !           445:                 *      noone else finds out about this page.
        !           446:                 */
        !           447:                next_p = (vm_page_t) queue_next(&p->listq);
        !           448:                if (p->free) {
        !           449:                        vm_page_free(p);
        !           450:                }
        !           451:                vm_page_unlock_queues();
        !           452:                p = next_p;
        !           453:        }
        !           454:                                
        !           455:        vm_object_unlock(object);
        !           456: 
        !           457:        /*
        !           458:         *      Let the pager know object is dead.
        !           459:         */
        !           460: 
        !           461:        if (object->pager != vm_pager_null)
        !           462:                vm_pager_deallocate(object->pager);
        !           463: 
        !           464:        if (object->paging_in_progress != 0)
        !           465:                panic("vm_object_deallocate: pageout in progress");
        !           466: 
        !           467:        /*
        !           468:         *      Free physical page resources.  All references to the object
        !           469:         *      are gone, so we don't need to lock it.
        !           470:         */
        !           471: 
        !           472:                while (!queue_empty(&object->memq)) {
        !           473:                        p = (vm_page_t) queue_first(&object->memq);
        !           474: 
        !           475:                        VM_PAGE_CHECK(p);
        !           476: 
        !           477:                        vm_page_lock_queues();
        !           478:                        vm_page_free(p);
        !           479:                        vm_page_unlock_queues();
        !           480:                }
        !           481: 
        !           482:        simple_lock(&vm_object_list_lock);
        !           483:        queue_remove(&vm_object_list, object, vm_object_t, object_list);
        !           484:        vm_object_count--;
        !           485:        simple_unlock(&vm_object_list_lock);
        !           486: 
        !           487:        /*
        !           488:         *      Free the space for the object.
        !           489:         */
        !           490: 
        !           491:        zfree(vm_object_zone, (vm_offset_t) object);
        !           492: }
        !           493: 
        !           494: void vm_object_destroy(pager)
        !           495:        port_t          pager;
        !           496: {
        !           497:        register
        !           498:        vm_object_t     object = vm_object_lookup(pager);
        !           499: 
        !           500:        if (object == VM_OBJECT_NULL)
        !           501:                return;
        !           502: 
        !           503:        vm_object_deallocate(object);
        !           504: }
        !           505: 
        !           506: /*
        !           507:  *     _vm_object_deactivate_pages
        !           508:  *
        !           509:  *     Internal routine to deactivate pages in the specified object.
        !           510:  *     (Keep its pages in memory even though it is no longer referenced.)
        !           511:  *
        !           512:  *     The object must be locked.
        !           513:  */
        !           514: static void _vm_object_deactivate_pages(object, age)
        !           515:        register vm_object_t    object;
        !           516:        register boolean_t      age;
        !           517: {
        !           518:        register vm_page_t      p, next;
        !           519: 
        !           520:        vm_page_lock_queues();
        !           521:        p = (vm_page_t) queue_first(&object->memq);
        !           522:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !           523:                next = (vm_page_t) queue_next(&p->listq);
        !           524:                if (!p->inactive) {
        !           525:                        if (age)
        !           526:                                vm_page_deactivate_first(p);
        !           527:                        else
        !           528:                                vm_page_deactivate(p);
        !           529:                }
        !           530:                p = next;
        !           531:        }
        !           532:        vm_page_unlock_queues();
        !           533: }
        !           534: 
        !           535: /*
        !           536:  *     vm_object_deactivate_pages
        !           537:  *
        !           538:  *     Deactivate pages in the specified object.
        !           539:  *     (Keep its pages in memory even though it is no longer referenced.)
        !           540:  *
        !           541:  *     The object must be locked.
        !           542:  */
        !           543: void vm_object_deactivate_pages(object)
        !           544:        register vm_object_t    object;
        !           545: {
        !           546:        _vm_object_deactivate_pages(object, FALSE);
        !           547: }
        !           548: 
        !           549: /*
        !           550:  *     vm_object_deactivate_pages_first
        !           551:  *
        !           552:  *     Deactivate pages in the specified object. Age them.
        !           553:  *     (Keep its pages in memory even though it is no longer referenced.)
        !           554:  *
        !           555:  *     The object must be locked.
        !           556:  */
        !           557: void vm_object_deactivate_pages_first(object)
        !           558:        register vm_object_t    object;
        !           559: {
        !           560:        _vm_object_deactivate_pages(object, TRUE);
        !           561: }
        !           562: 
        !           563: /*
        !           564:  *     Trim the object cache to size.
        !           565:  */
        !           566: vm_object_cache_trim()
        !           567: {
        !           568:        register vm_object_t    object;
        !           569: 
        !           570:        vm_object_cache_lock();
        !           571:        while (vm_object_cached > vm_cache_max) {
        !           572:                object = (vm_object_t) queue_first(&vm_object_cached_list);
        !           573:                vm_object_cache_unlock();
        !           574: 
        !           575:                if (object != vm_object_lookup(object->pager))
        !           576:                        panic("vm_object_cache_trim: I'm sooo confused.");
        !           577:                vm_object_cache_object(object, FALSE);
        !           578: 
        !           579:                vm_object_cache_lock();
        !           580:        }
        !           581:        vm_object_cache_unlock();
        !           582: }
        !           583: 
        !           584: /*
        !           585: * 
        !           586: */
        !           587: kern_return_t
        !           588: adjust_vm_object_cache(vm_size_t oldval, vm_size_t newval)
        !           589: {
        !           590:        vm_cache_max = newval;
        !           591:        vm_object_cache_trim();
        !           592:        return(KERN_SUCCESS);   
        !           593: }
        !           594: 
        !           595: kern_return_t vm_object_cache_object(object, should_cache)
        !           596:        vm_object_t     object;
        !           597:        boolean_t       should_cache;
        !           598: {
        !           599:        if (object == VM_OBJECT_NULL)
        !           600:                return(KERN_INVALID_ARGUMENT);
        !           601: 
        !           602:        vm_object_cache_lock();
        !           603:        vm_object_lock(object);
        !           604:        object->can_persist = should_cache;
        !           605:        vm_object_unlock(object);
        !           606:        vm_object_cache_unlock();
        !           607: 
        !           608:        vm_object_deallocate(object);
        !           609: 
        !           610:        return(KERN_SUCCESS);
        !           611: }
        !           612: 
        !           613: 
        !           614: /*
        !           615:  *     vm_object_shutdown()
        !           616:  *
        !           617:  *     Shut down the object system.  Unfortunately, while we
        !           618:  *     may be trying to do this, init is happily waiting for
        !           619:  *     processes to exit, and therefore will be causing some objects
        !           620:  *     to be deallocated.  To handle this, we gain a fake reference
        !           621:  *     to all objects we release paging areas for.  This will prevent
        !           622:  *     a duplicate deallocation.  This routine is probably full of
        !           623:  *     race conditions!
        !           624:  */
        !           625: 
        !           626: void vm_object_shutdown()
        !           627: {
        !           628:        /*
        !           629:         *      Clean up the object cache *before* we screw up the reference
        !           630:         *      counts on all of the objects.
        !           631:         */
        !           632: 
        !           633:        vm_object_cache_clear();
        !           634: }
        !           635: 
        !           636: /*
        !           637:  *     vm_object_pmap_copy:
        !           638:  *
        !           639:  *     Makes all physical pages in the specified
        !           640:  *     object range copy-on-write.  No writeable
        !           641:  *     references to these pages should remain.
        !           642:  *
        !           643:  *     The object must *not* be locked.
        !           644:  */
        !           645: void vm_object_pmap_copy(object, start, end)
        !           646:        register vm_object_t    object;
        !           647:        register vm_offset_t    start;
        !           648:        register vm_offset_t    end;
        !           649: {
        !           650:        register vm_page_t      p;
        !           651: 
        !           652:        if (object == VM_OBJECT_NULL)
        !           653:                return;
        !           654: 
        !           655:        vm_object_lock(object);
        !           656:        p = (vm_page_t) queue_first(&object->memq);
        !           657:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !           658:                if ((start <= p->offset) && (p->offset < end)) {
        !           659:                        if (!p->copy_on_write) {
        !           660:                                pmap_copy_on_write(VM_PAGE_TO_PHYS(p));
        !           661:                                p->copy_on_write = TRUE;
        !           662:                        }
        !           663:                }
        !           664:                p = (vm_page_t) queue_next(&p->listq);
        !           665:        }
        !           666:        vm_object_unlock(object);
        !           667: }
        !           668: 
        !           669: /*
        !           670:  *     vm_object_pmap_remove:
        !           671:  *
        !           672:  *     Removes all physical pages in the specified
        !           673:  *     object range from all physical maps.
        !           674:  *
        !           675:  *     The object must *not* be locked.
        !           676:  */
        !           677: void vm_object_pmap_remove(object, start, end)
        !           678:        register vm_object_t    object;
        !           679:        register vm_offset_t    start;
        !           680:        register vm_offset_t    end;
        !           681: {
        !           682:        register vm_page_t      p;
        !           683: 
        !           684:        if (object == VM_OBJECT_NULL)
        !           685:                return;
        !           686: 
        !           687:        vm_object_lock(object);
        !           688:        p = (vm_page_t) queue_first(&object->memq);
        !           689:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !           690:                if ((start <= p->offset) && (p->offset < end)) {
        !           691:                        pmap_remove_all(VM_PAGE_TO_PHYS(p));
        !           692:                }
        !           693:                p = (vm_page_t) queue_next(&p->listq);
        !           694:        }
        !           695:        vm_object_unlock(object);
        !           696: }
        !           697: 
        !           698: /*
        !           699:  *     vm_object_copy:
        !           700:  *
        !           701:  *     Create a new object which is a copy of an existing
        !           702:  *     object, and mark all of the pages in the existing
        !           703:  *     object 'copy-on-write'.  The new object has one reference.
        !           704:  *     Returns the new object.
        !           705:  *
        !           706:  *     May defer the copy until later if the object is not backed
        !           707:  *     up by a non-default pager.
        !           708:  */
        !           709: void vm_object_copy(src_object, src_offset, size,
        !           710:                    dst_object, dst_offset, src_needs_copy)
        !           711:        register vm_object_t    src_object;
        !           712:        vm_offset_t             src_offset;
        !           713:        vm_size_t               size;
        !           714:        vm_object_t             *dst_object;    /* OUT */
        !           715:        vm_offset_t             *dst_offset;    /* OUT */
        !           716:        boolean_t               *src_needs_copy;        /* OUT */
        !           717: {
        !           718:        register vm_object_t    new_copy;
        !           719:        register vm_object_t    old_copy;
        !           720:        vm_offset_t             new_start, new_end;
        !           721: 
        !           722:        register vm_page_t      p;
        !           723: 
        !           724:        if (src_object == VM_OBJECT_NULL) {
        !           725:                /*
        !           726:                 *      Nothing to copy
        !           727:                 */
        !           728:                *dst_object = VM_OBJECT_NULL;
        !           729:                *dst_offset = 0;
        !           730:                *src_needs_copy = FALSE;
        !           731:                return;
        !           732:        }
        !           733: 
        !           734:        /*
        !           735:         *      If the object's pager is null_pager or the
        !           736:         *      default pager, we don't have to make a copy
        !           737:         *      of it.  Instead, we set the needs copy flag and
        !           738:         *      make a shadow later.
        !           739:         */
        !           740: 
        !           741:        vm_object_lock(src_object);
        !           742:        if (src_object->pager == vm_pager_null ||
        !           743:            src_object->internal) {
        !           744: 
        !           745:                /*
        !           746:                 *      Make another reference to the object
        !           747:                 */
        !           748:                src_object->ref_count++;
        !           749: 
        !           750:                /*
        !           751:                 *      Mark all of the pages copy-on-write.
        !           752:                 */
        !           753:                for (p = (vm_page_t) queue_first(&src_object->memq);
        !           754:                     !queue_end(&src_object->memq, (queue_entry_t)p);
        !           755:                     p = (vm_page_t) queue_next(&p->listq)) {
        !           756:                        if (src_offset <= p->offset &&
        !           757:                            p->offset < src_offset + size)
        !           758:                                p->copy_on_write = TRUE;
        !           759:                }
        !           760:                vm_object_unlock(src_object);
        !           761: 
        !           762:                *dst_object = src_object;
        !           763:                *dst_offset = src_offset;
        !           764:                
        !           765:                /*
        !           766:                 *      Must make a shadow when write is desired
        !           767:                 */
        !           768:                *src_needs_copy = TRUE;
        !           769:                return;
        !           770:        }
        !           771: 
        !           772:        /*
        !           773:         *      Try to collapse the object before copying it.
        !           774:         */
        !           775:        vm_object_collapse(src_object);
        !           776: 
        !           777:        /*
        !           778:         *      If the object has a pager, the pager wants to
        !           779:         *      see all of the changes.  We need a copy-object
        !           780:         *      for the changed pages.
        !           781:         *
        !           782:         *      If there is a copy-object, and it is empty,
        !           783:         *      no changes have been made to the object since the
        !           784:         *      copy-object was made.  We can use the same copy-
        !           785:         *      object.
        !           786:         */
        !           787: 
        !           788:     Retry1:
        !           789:        old_copy = src_object->copy;
        !           790:        if (old_copy != VM_OBJECT_NULL) {
        !           791:                /*
        !           792:                 *      Try to get the locks (out of order)
        !           793:                 */
        !           794:                if (!vm_object_lock_try(old_copy)) {
        !           795:                        vm_object_unlock(src_object);
        !           796: 
        !           797:                        /* should spin a bit here... */
        !           798:                        vm_object_lock(src_object);
        !           799:                        goto Retry1;
        !           800:                }
        !           801: 
        !           802:                if (old_copy->resident_page_count == 0 &&
        !           803:                    old_copy->pager == vm_pager_null) {
        !           804:                        /*
        !           805:                         *      Return another reference to
        !           806:                         *      the existing copy-object.
        !           807:                         */
        !           808:                        old_copy->ref_count++;
        !           809:                        vm_object_unlock(old_copy);
        !           810:                        vm_object_unlock(src_object);
        !           811:                        *dst_object = old_copy;
        !           812:                        *dst_offset = src_offset;
        !           813:                        *src_needs_copy = FALSE;
        !           814:                        return;
        !           815:                }
        !           816:                vm_object_unlock(old_copy);
        !           817:        }
        !           818:        vm_object_unlock(src_object);
        !           819: 
        !           820:        /*
        !           821:         *      If the object has a pager, the pager wants
        !           822:         *      to see all of the changes.  We must make
        !           823:         *      a copy-object and put the changed pages there.
        !           824:         *
        !           825:         *      The copy-object is always made large enough to
        !           826:         *      completely shadow the original object, since
        !           827:         *      it may have several users who want to shadow
        !           828:         *      the original object at different points.
        !           829:         */
        !           830: 
        !           831:        new_copy = vm_object_allocate(src_object->size);
        !           832: 
        !           833:     Retry2:
        !           834:        vm_object_lock(src_object);
        !           835:        /*
        !           836:         *      Copy object may have changed while we were unlocked
        !           837:         */
        !           838:        old_copy = src_object->copy;
        !           839:        if (old_copy != VM_OBJECT_NULL) {
        !           840:                /*
        !           841:                 *      Try to get the locks (out of order)
        !           842:                 */
        !           843:                if (!vm_object_lock_try(old_copy)) {
        !           844:                        vm_object_unlock(src_object);
        !           845:                        goto Retry2;
        !           846:                }
        !           847: 
        !           848:                /*
        !           849:                 *      Consistency check
        !           850:                 */
        !           851:                if (old_copy->shadow != src_object ||
        !           852:                    old_copy->shadow_offset != (vm_offset_t) 0)
        !           853:                        panic("vm_object_copy: copy/shadow inconsistency");
        !           854: 
        !           855:                /*
        !           856:                 *      Make the old copy-object shadow the new one.
        !           857:                 *      It will receive no more pages from the original
        !           858:                 *      object.
        !           859:                 */
        !           860: 
        !           861:                src_object->ref_count--;        /* remove ref. from old_copy */
        !           862:                old_copy->shadow = new_copy;
        !           863:                new_copy->ref_count++;          /* locking not needed - we
        !           864:                                                   have the only pointer */
        !           865:                vm_object_unlock(old_copy);     /* done with old_copy */
        !           866:        }
        !           867: 
        !           868:        new_start = (vm_offset_t) 0;    /* always shadow original at 0 */
        !           869:        new_end   = (vm_offset_t) new_copy->size; /* for the whole object */
        !           870: 
        !           871:        /*
        !           872:         *      Point the new copy at the existing object.
        !           873:         */
        !           874: 
        !           875:        new_copy->shadow = src_object;
        !           876:        new_copy->shadow_offset = new_start;
        !           877:        src_object->ref_count++;
        !           878:        src_object->copy = new_copy;
        !           879: 
        !           880:        /*
        !           881:         *      Mark all the affected pages of the existing object
        !           882:         *      copy-on-write.
        !           883:         */
        !           884:        p = (vm_page_t) queue_first(&src_object->memq);
        !           885:        while (!queue_end(&src_object->memq, (queue_entry_t) p)) {
        !           886:                if ((new_start <= p->offset) && (p->offset < new_end)) {
        !           887:                        p->copy_on_write = TRUE;
        !           888:                }
        !           889:                p = (vm_page_t) queue_next(&p->listq);
        !           890:        }
        !           891: 
        !           892:        vm_object_unlock(src_object);
        !           893: 
        !           894:        *dst_object = new_copy;
        !           895:        *dst_offset = src_offset - new_start;
        !           896:        *src_needs_copy = FALSE;
        !           897: }
        !           898: 
        !           899: /*
        !           900:  *     vm_object_shadow:
        !           901:  *
        !           902:  *     Create a new object which is backed by the
        !           903:  *     specified existing object range.  The source
        !           904:  *     object reference is deallocated.
        !           905:  *
        !           906:  *     The new object and offset into that object
        !           907:  *     are returned in the source parameters.
        !           908:  */
        !           909: 
        !           910: void vm_object_shadow(object, offset, length)
        !           911:        vm_object_t     *object;        /* IN/OUT */
        !           912:        vm_offset_t     *offset;        /* IN/OUT */
        !           913:        vm_size_t       length;
        !           914: {
        !           915:        register vm_object_t    source;
        !           916:        register vm_object_t    result;
        !           917: 
        !           918:        source = *object;
        !           919: 
        !           920:        /*
        !           921:         *      Allocate a new object with the given length
        !           922:         */
        !           923: 
        !           924:        if ((result = vm_object_allocate(length)) == VM_OBJECT_NULL)
        !           925:                panic("vm_object_shadow: no object for shadowing");
        !           926: 
        !           927:        /*
        !           928:         *      The new object shadows the source object, adding
        !           929:         *      a reference to it.  Our caller changes his reference
        !           930:         *      to point to the new object, removing a reference to
        !           931:         *      the source object.  Net result: no change of reference
        !           932:         *      count.
        !           933:         */
        !           934:        result->shadow = source;
        !           935:        
        !           936:        /*
        !           937:         *      Store the offset into the source object,
        !           938:         *      and fix up the offset into the new object.
        !           939:         */
        !           940: 
        !           941:        result->shadow_offset = *offset;
        !           942: 
        !           943:        /*
        !           944:         *      Return the new things
        !           945:         */
        !           946: 
        !           947:        *offset = 0;
        !           948:        *object = result;
        !           949: }
        !           950: 
        !           951: /*
        !           952:  *     Set the specified object's pager to the specified pager.
        !           953:  */
        !           954: 
        !           955: void vm_object_setpager(object, pager, paging_offset,
        !           956:                        read_only)
        !           957:        vm_object_t     object;
        !           958:        vm_pager_t      pager;
        !           959:        vm_offset_t     paging_offset;
        !           960:        boolean_t       read_only;
        !           961: {
        !           962: #ifdef lint
        !           963:        read_only++;    /* No longer used */
        !           964: #endif lint
        !           965: 
        !           966:        vm_object_lock(object);                 /* XXX ? */
        !           967:        object->pager = pager;
        !           968:        object->paging_offset = paging_offset;
        !           969:        vm_object_unlock(object);                       /* XXX ? */
        !           970: }
        !           971: 
        !           972: /*
        !           973:  *     vm_object_hash hashes the pager/id pair.
        !           974:  */
        !           975: /* Shift for sizeof(struct vm_object_hash_entry) */
        !           976: #define VM_OBJECT_HASH_SHIFT   8
        !           977: #define vm_object_hash(pager) \
        !           978:        ((((unsigned)pager) >> VM_OBJECT_HASH_SHIFT) % VM_OBJECT_HASH_COUNT)
        !           979: 
        !           980: /*
        !           981:  *     vm_object_lookup looks in the object cache for an object with the
        !           982:  *     specified pager and paging id.
        !           983:  */
        !           984: 
        !           985: vm_object_t vm_object_lookup(pager)
        !           986:        vm_pager_t      pager;
        !           987: {
        !           988:        register queue_t                bucket;
        !           989:        register vm_object_hash_entry_t entry;
        !           990:        vm_object_t                     object;
        !           991: 
        !           992:        bucket = &vm_object_hashtable[vm_object_hash(pager)];
        !           993: 
        !           994:        vm_object_cache_lock();
        !           995: 
        !           996:        entry = (vm_object_hash_entry_t) queue_first(bucket);
        !           997:        while (!queue_end(bucket, (queue_entry_t) entry)) {
        !           998:                object = entry->object;
        !           999:                if (object->pager == pager) {
        !          1000:                        vm_object_lock(object);
        !          1001:                        if (object->ref_count == 0) {
        !          1002:                                queue_remove(&vm_object_cached_list, object,
        !          1003:                                                vm_object_t, cached_list);
        !          1004:                                vm_object_cached--;
        !          1005:                        }
        !          1006:                        object->ref_count++;
        !          1007:                        vm_object_unlock(object);
        !          1008:                        vm_object_cache_unlock();
        !          1009:                        return(object);
        !          1010:                }
        !          1011:                entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
        !          1012:        }
        !          1013: 
        !          1014:        vm_object_cache_unlock();
        !          1015:        return(VM_OBJECT_NULL);
        !          1016: }
        !          1017: 
        !          1018: /*
        !          1019:  *     vm_object_enter enters the specified object/pager/id into
        !          1020:  *     the hash table.
        !          1021:  */
        !          1022: 
        !          1023: void vm_object_enter(object, pager)
        !          1024:        vm_object_t     object;
        !          1025:        vm_pager_t      pager;
        !          1026: {
        !          1027:        register queue_t                bucket;
        !          1028:        register vm_object_hash_entry_t entry;
        !          1029: 
        !          1030:        /*
        !          1031:         *      We don't cache null objects, and we can't cache
        !          1032:         *      objects with the null pager.
        !          1033:         */
        !          1034: 
        !          1035:        if (object == VM_OBJECT_NULL)
        !          1036:                return;
        !          1037:        if (pager == vm_pager_null)
        !          1038:                return;
        !          1039: 
        !          1040:        bucket = &vm_object_hashtable[vm_object_hash(pager)];
        !          1041:        entry = (vm_object_hash_entry_t) zalloc(object_hash_zone);
        !          1042:        entry->object = object;
        !          1043:        object->can_persist = TRUE;
        !          1044: 
        !          1045:        vm_object_cache_lock();
        !          1046:        queue_enter(bucket, entry, vm_object_hash_entry_t, hash_links);
        !          1047:        vm_object_cache_unlock();
        !          1048: }
        !          1049: 
        !          1050: /*
        !          1051:  *     vm_object_remove:
        !          1052:  *
        !          1053:  *     Remove the pager from the hash table.
        !          1054:  *     Note:  This assumes that the object cache
        !          1055:  *     is locked.  XXX this should be fixed
        !          1056:  *     by reorganizing vm_object_deallocate.
        !          1057:  */
        !          1058: vm_object_remove(pager)
        !          1059:        register vm_pager_t     pager;
        !          1060: {
        !          1061:        register queue_t                bucket;
        !          1062:        register vm_object_hash_entry_t entry;
        !          1063:        register vm_object_t            object;
        !          1064: 
        !          1065:        bucket = &vm_object_hashtable[vm_object_hash(pager)];
        !          1066: 
        !          1067:        entry = (vm_object_hash_entry_t) queue_first(bucket);
        !          1068:        while (!queue_end(bucket, (queue_entry_t) entry)) {
        !          1069:                object = entry->object;
        !          1070:                if (object->pager == pager) {
        !          1071:                        queue_remove(bucket, entry, vm_object_hash_entry_t,
        !          1072:                                        hash_links);
        !          1073:                        zfree(object_hash_zone, (vm_offset_t) entry);
        !          1074:                        break;
        !          1075:                }
        !          1076:                entry = (vm_object_hash_entry_t) queue_next(&entry->hash_links);
        !          1077:        }
        !          1078: }
        !          1079: 
        !          1080: /*
        !          1081:  *     vm_object_cache_clear removes all objects from the cache.
        !          1082:  *
        !          1083:  */
        !          1084: 
        !          1085: void vm_object_cache_clear()
        !          1086: {
        !          1087:        register vm_object_t    object;
        !          1088: 
        !          1089:        /*
        !          1090:         *      Remove each object in the cache by scanning down the
        !          1091:         *      list of cached objects.
        !          1092:         */
        !          1093:        vm_object_cache_lock();
        !          1094:        while (!queue_empty(&vm_object_cached_list)) {
        !          1095:                object = (vm_object_t) queue_first(&vm_object_cached_list);
        !          1096:                vm_object_cache_unlock();
        !          1097: 
        !          1098:                /* 
        !          1099:                 * Note: it is important that we use vm_object_lookup
        !          1100:                 * to gain a reference, and not vm_object_reference, because
        !          1101:                 * the logic for removing an object from the cache lies in 
        !          1102:                 * lookup.
        !          1103:                 */
        !          1104:                if (object != vm_object_lookup(object->pager))
        !          1105:                        panic("vm_object_cache_clear: I'm sooo confused.");
        !          1106:                vm_object_cache_object(object, FALSE);
        !          1107: 
        !          1108:                vm_object_cache_lock();
        !          1109:        }
        !          1110:        vm_object_cache_unlock();
        !          1111: }
        !          1112: 
        !          1113: /*
        !          1114:  *     Remove some number of entries from the object cache.
        !          1115:  */
        !          1116: int
        !          1117: vm_object_cache_steal(num)
        !          1118:        register int num;
        !          1119: {
        !          1120:        register vm_object_t    object;
        !          1121:        register int            num_removed = 0;
        !          1122: 
        !          1123:        vm_object_cache_lock();
        !          1124:        while (num_removed < num && !queue_empty(&vm_object_cached_list)) {
        !          1125:                object = (vm_object_t) queue_first(&vm_object_cached_list);
        !          1126:                vm_object_cache_unlock();
        !          1127: 
        !          1128:                if (object != vm_object_lookup(object->pager))
        !          1129:                        panic("vm_object_cache_steal: I'm sooo confused.");
        !          1130:                vm_object_cache_object(object, FALSE);
        !          1131:                num_removed++;
        !          1132: 
        !          1133:                vm_object_cache_lock();
        !          1134:        }
        !          1135:        vm_object_cache_unlock();
        !          1136: 
        !          1137:        return(num_removed);
        !          1138: }
        !          1139: 
        !          1140: boolean_t      vm_object_collapse_allowed = TRUE;
        !          1141: /*
        !          1142:  *     vm_object_collapse:
        !          1143:  *
        !          1144:  *     Collapse an object with the object backing it.
        !          1145:  *     Pages in the backing object are moved into the
        !          1146:  *     parent, and the backing object is deallocated.
        !          1147:  *
        !          1148:  *     Requires that the object be locked and the page
        !          1149:  *     queues be unlocked.
        !          1150:  *
        !          1151:  */
        !          1152: void vm_object_collapse(object)
        !          1153:        register vm_object_t    object;
        !          1154: 
        !          1155: {
        !          1156:        register vm_object_t    backing_object;
        !          1157:        register vm_offset_t    backing_offset;
        !          1158:        register vm_size_t      size;
        !          1159:        register vm_offset_t    new_offset;
        !          1160:        register vm_page_t      p, pp;
        !          1161: 
        !          1162:        if (!vm_object_collapse_allowed)
        !          1163:                return;
        !          1164: 
        !          1165:        while (TRUE) {
        !          1166:                /*
        !          1167:                 *      Verify that the conditions are right for collapse:
        !          1168:                 *
        !          1169:                 *      The object exists and no pages in it are currently
        !          1170:                 *      being paged out (or have ever been paged out).
        !          1171:                 */
        !          1172:                if (object == VM_OBJECT_NULL ||
        !          1173:                    object->paging_in_progress != 0 ||
        !          1174:                    object->pager != vm_pager_null)
        !          1175:                        return;
        !          1176: 
        !          1177:                /*
        !          1178:                 *              There is a backing object, and
        !          1179:                 */
        !          1180:        
        !          1181:                if ((backing_object = object->shadow) == VM_OBJECT_NULL)
        !          1182:                        return;
        !          1183:        
        !          1184:                vm_object_lock(backing_object);
        !          1185:                /*
        !          1186:                 *      ...
        !          1187:                 *              The backing object is not read_only,
        !          1188:                 *              and no pages in the backing object are
        !          1189:                 *              currently being paged out.
        !          1190:                 *              The backing object is internal.
        !          1191:                 */
        !          1192:        
        !          1193:                if (!backing_object->internal ||
        !          1194:                    backing_object->paging_in_progress != 0) {
        !          1195:                        vm_object_unlock(backing_object);
        !          1196:                        return;
        !          1197:                }
        !          1198:        
        !          1199:                /*
        !          1200:                 *      The backing object can't be a copy-object:
        !          1201:                 *      the shadow_offset for the copy-object must stay
        !          1202:                 *      as 0.  Furthermore (for the 'we have all the
        !          1203:                 *      pages' case), if we bypass backing_object and
        !          1204:                 *      just shadow the next object in the chain, old
        !          1205:                 *      pages from that object would then have to be copied
        !          1206:                 *      BOTH into the (former) backing_object and into the
        !          1207:                 *      parent object.
        !          1208:                 */
        !          1209:                if (backing_object->shadow != VM_OBJECT_NULL &&
        !          1210:                    backing_object->shadow->copy != VM_OBJECT_NULL) {
        !          1211:                        vm_object_unlock(backing_object);
        !          1212:                        return;
        !          1213:                }
        !          1214: 
        !          1215:                /*
        !          1216:                 *      We know that we can either collapse the backing
        !          1217:                 *      object (if the parent is the only reference to
        !          1218:                 *      it) or (perhaps) remove the parent's reference
        !          1219:                 *      to it.
        !          1220:                 */
        !          1221: 
        !          1222:                backing_offset = object->shadow_offset;
        !          1223:                size = object->size;
        !          1224: 
        !          1225:                /*
        !          1226:                 *      If there is exactly one reference to the backing
        !          1227:                 *      object, we can collapse it into the parent.
        !          1228:                 */
        !          1229:        
        !          1230:                if (backing_object->ref_count == 1) {
        !          1231: 
        !          1232:                        /*
        !          1233:                         *      We can collapse the backing object.
        !          1234:                         *
        !          1235:                         *      Move all in-memory pages from backing_object
        !          1236:                         *      to the parent.  Pages that have been paged out
        !          1237:                         *      will be overwritten by any of the parent's
        !          1238:                         *      pages that shadow them.
        !          1239:                         */
        !          1240: 
        !          1241:                        while (!queue_empty(&backing_object->memq)) {
        !          1242: 
        !          1243:                                p = (vm_page_t)
        !          1244:                                        queue_first(&backing_object->memq);
        !          1245: 
        !          1246:                                new_offset = (p->offset - backing_offset);
        !          1247: 
        !          1248:                                /*
        !          1249:                                 *      If the parent has a page here, or if
        !          1250:                                 *      this page falls outside the parent,
        !          1251:                                 *      dispose of it.
        !          1252:                                 *
        !          1253:                                 *      Otherwise, move it as planned.
        !          1254:                                 */
        !          1255: 
        !          1256:                                if (p->offset < backing_offset ||
        !          1257:                                    new_offset >= size) {
        !          1258:                                        vm_page_lock_queues();
        !          1259:                                        vm_page_free(p);
        !          1260:                                        vm_page_unlock_queues();
        !          1261:                                } else {
        !          1262:                                    pp = vm_page_lookup(object, new_offset);
        !          1263:                                    if (pp != VM_PAGE_NULL) {
        !          1264:                                        vm_page_lock_queues();
        !          1265:                                        vm_page_free(p);
        !          1266:                                        vm_page_unlock_queues();
        !          1267:                                    }
        !          1268:                                    else {
        !          1269:                                        vm_page_rename(p, object, new_offset);
        !          1270:                                    }
        !          1271:                                }
        !          1272:                        }
        !          1273: 
        !          1274:                        /*
        !          1275:                         *      Move the pager from backing_object to object.
        !          1276:                         *
        !          1277:                         *      XXX We're only using part of the paging space
        !          1278:                         *      for keeps now... we ought to discard the
        !          1279:                         *      unused portion.
        !          1280:                         */
        !          1281: 
        !          1282:                        object->pager = backing_object->pager;
        !          1283:                        object->paging_offset =
        !          1284:                                backing_object->paging_offset + backing_offset;
        !          1285: 
        !          1286:                        backing_object->pager = vm_pager_null;
        !          1287:                        backing_object->pager_request = PORT_NULL;
        !          1288:                        backing_object->pager_name = PORT_NULL;
        !          1289: 
        !          1290:                        /*
        !          1291:                         *      Object now shadows whatever backing_object did.
        !          1292:                         *      Note that the reference to backing_object->shadow
        !          1293:                         *      moves from within backing_object to within object.
        !          1294:                         */
        !          1295: 
        !          1296:                        object->shadow = backing_object->shadow;
        !          1297:                        object->shadow_offset += backing_object->shadow_offset;
        !          1298:                        if (object->shadow != VM_OBJECT_NULL &&
        !          1299:                            object->shadow->copy != VM_OBJECT_NULL) {
        !          1300:                                panic("vm_object_collapse: we collapsed a copy-object!");
        !          1301:                        }
        !          1302:                        /*
        !          1303:                         *      Discard backing_object.
        !          1304:                         *
        !          1305:                         *      Since the backing object has no pages, no
        !          1306:                         *      pager left, and no object references within it,
        !          1307:                         *      all that is necessary is to dispose of it.
        !          1308:                         */
        !          1309: 
        !          1310:                        vm_object_unlock(backing_object);
        !          1311: 
        !          1312:                        simple_lock(&vm_object_list_lock);
        !          1313:                        queue_remove(&vm_object_list, backing_object,
        !          1314:                                                vm_object_t, object_list);
        !          1315:                        vm_object_count--;
        !          1316:                        simple_unlock(&vm_object_list_lock);
        !          1317: 
        !          1318:                        zfree(vm_object_zone, (vm_offset_t) backing_object);
        !          1319: 
        !          1320:                        object_collapses++;
        !          1321:                }
        !          1322:                else {
        !          1323:                        /*
        !          1324:                         *      If all of the pages in the backing object are
        !          1325:                         *      shadowed by the parent object, the parent
        !          1326:                         *      object no longer has to shadow the backing
        !          1327:                         *      object; it can shadow the next one in the
        !          1328:                         *      chain.
        !          1329:                         *
        !          1330:                         *      The backing object must not be paged out - we'd
        !          1331:                         *      have to check all of the paged-out pages, as
        !          1332:                         *      well.
        !          1333:                         */
        !          1334: 
        !          1335:                        if (backing_object->pager != vm_pager_null) {
        !          1336:                                vm_object_unlock(backing_object);
        !          1337:                                return;
        !          1338:                        }
        !          1339: 
        !          1340:                        /*
        !          1341:                         *      Should have a check for a 'small' number
        !          1342:                         *      of pages here.
        !          1343:                         */
        !          1344: 
        !          1345:                        p = (vm_page_t) queue_first(&backing_object->memq);
        !          1346:                        while (!queue_end(&backing_object->memq,
        !          1347:                                          (queue_entry_t) p)) {
        !          1348: 
        !          1349:                                new_offset = (p->offset - backing_offset);
        !          1350: 
        !          1351:                                /*
        !          1352:                                 *      If the parent has a page here, or if
        !          1353:                                 *      this page falls outside the parent,
        !          1354:                                 *      keep going.
        !          1355:                                 *
        !          1356:                                 *      Otherwise, the backing_object must be
        !          1357:                                 *      left in the chain.
        !          1358:                                 */
        !          1359: 
        !          1360:                                if (p->offset >= backing_offset &&
        !          1361:                                    new_offset <= size &&
        !          1362:                                    (pp = vm_page_lookup(object, new_offset))
        !          1363:                                      == VM_PAGE_NULL) {
        !          1364:                                        /*
        !          1365:                                         *      Page still needed.
        !          1366:                                         *      Can't go any further.
        !          1367:                                         */
        !          1368:                                        vm_object_unlock(backing_object);
        !          1369:                                        return;
        !          1370:                                }
        !          1371:                                p = (vm_page_t) queue_next(&p->listq);
        !          1372:                        }
        !          1373: 
        !          1374:                        /*
        !          1375:                         *      Make the parent shadow the next object
        !          1376:                         *      in the chain.  Deallocating backing_object
        !          1377:                         *      will not remove it, since its reference
        !          1378:                         *      count is at least 2.
        !          1379:                         */
        !          1380: 
        !          1381:                        vm_object_reference(object->shadow = backing_object->shadow);
        !          1382:                        object->shadow_offset += backing_object->shadow_offset;
        !          1383: 
        !          1384:                        /*      Drop the reference count on backing_object.
        !          1385:                         *      Since its ref_count was at least 2, it
        !          1386:                         *      will not vanish; so we don't need to call
        !          1387:                         *      vm_object_deallocate.
        !          1388:                         */
        !          1389:                        backing_object->ref_count--;
        !          1390:                        vm_object_unlock(backing_object);
        !          1391: 
        !          1392:                        object_bypasses ++;
        !          1393: 
        !          1394:                }
        !          1395: 
        !          1396:                /*
        !          1397:                 *      Try again with this object's new backing object.
        !          1398:                 */
        !          1399:        }
        !          1400: }
        !          1401: 
        !          1402: /*
        !          1403:  *     vm_object_page_remove: [internal]
        !          1404:  *
        !          1405:  *     Removes all physical pages in the specified
        !          1406:  *     object range from the object's list of pages.
        !          1407:  *
        !          1408:  *     The object must be locked.
        !          1409:  */
        !          1410: void vm_object_page_remove(object, start, end)
        !          1411:        register vm_object_t    object;
        !          1412:        register vm_offset_t    start;
        !          1413:        register vm_offset_t    end;
        !          1414: {
        !          1415:        register vm_page_t      p, next;
        !          1416: 
        !          1417:        if (object == VM_OBJECT_NULL)
        !          1418:                return;
        !          1419: 
        !          1420:        p = (vm_page_t) queue_first(&object->memq);
        !          1421:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !          1422:                next = (vm_page_t) queue_next(&p->listq);
        !          1423:                if ((start <= p->offset) && (p->offset < end)) {
        !          1424:                        pmap_remove_all(VM_PAGE_TO_PHYS(p));
        !          1425:                        vm_page_lock_queues();
        !          1426:                        vm_page_free(p);
        !          1427:                        vm_page_unlock_queues();
        !          1428:                }
        !          1429:                p = next;
        !          1430:        }
        !          1431: }
        !          1432: 
        !          1433: /*
        !          1434:  *     Routine:        vm_object_coalesce
        !          1435:  *     Function:       Coalesces two objects backing up adjoining
        !          1436:  *                     regions of memory into a single object.
        !          1437:  *
        !          1438:  *     returns TRUE if objects were combined.
        !          1439:  *
        !          1440:  *     NOTE:   Only works at the moment if the second object is NULL -
        !          1441:  *             if it's not, which object do we lock first?
        !          1442:  *
        !          1443:  *     Parameters:
        !          1444:  *             prev_object     First object to coalesce
        !          1445:  *             prev_offset     Offset into prev_object
        !          1446:  *             next_object     Second object into coalesce
        !          1447:  *             next_offset     Offset into next_object
        !          1448:  *
        !          1449:  *             prev_size       Size of reference to prev_object
        !          1450:  *             next_size       Size of reference to next_object
        !          1451:  *
        !          1452:  *     Conditions:
        !          1453:  *     The object must *not* be locked.
        !          1454:  */
        !          1455: boolean_t vm_object_coalesce(prev_object, next_object,
        !          1456:                        prev_offset, next_offset,
        !          1457:                        prev_size, next_size)
        !          1458: 
        !          1459:        register vm_object_t    prev_object;
        !          1460:        vm_object_t     next_object;
        !          1461:        vm_offset_t     prev_offset, next_offset;
        !          1462:        vm_size_t       prev_size, next_size;
        !          1463: {
        !          1464:        vm_size_t       newsize;
        !          1465: 
        !          1466: #ifdef lint
        !          1467:        next_offset++;
        !          1468: #endif lint
        !          1469: 
        !          1470:        if (next_object != VM_OBJECT_NULL) {
        !          1471:                return(FALSE);
        !          1472:        }
        !          1473: 
        !          1474:        if (prev_object == VM_OBJECT_NULL) {
        !          1475:                return(TRUE);
        !          1476:        }
        !          1477: 
        !          1478:        vm_object_lock(prev_object);
        !          1479: 
        !          1480:        /*
        !          1481:         *      Try to collapse the object first
        !          1482:         */
        !          1483:        vm_object_collapse(prev_object);
        !          1484: 
        !          1485:        /*
        !          1486:         *      Can't coalesce if:
        !          1487:         *      . more than one reference
        !          1488:         *      . paged out
        !          1489:         *      . shadows another object
        !          1490:         *      . has a copy elsewhere
        !          1491:         *      (any of which mean that the pages not mapped to
        !          1492:         *      prev_entry may be in use anyway)
        !          1493:         */
        !          1494: 
        !          1495:        if (prev_object->ref_count > 1 ||
        !          1496:                prev_object->pager != vm_pager_null ||
        !          1497:                prev_object->shadow != VM_OBJECT_NULL ||
        !          1498:                prev_object->copy != VM_OBJECT_NULL) {
        !          1499:                vm_object_unlock(prev_object);
        !          1500:                return(FALSE);
        !          1501:        }
        !          1502: 
        !          1503:        /*
        !          1504:         *      Remove any pages that may still be in the object from
        !          1505:         *      a previous deallocation.
        !          1506:         */
        !          1507: 
        !          1508:        vm_object_page_remove(prev_object,
        !          1509:                        prev_offset + prev_size,
        !          1510:                        prev_offset + prev_size + next_size);
        !          1511: 
        !          1512:        /*
        !          1513:         *      Extend the object if necessary.
        !          1514:         */
        !          1515:        newsize = prev_offset + prev_size + next_size;
        !          1516:        if (newsize > prev_object->size)
        !          1517:                prev_object->size = newsize;
        !          1518: 
        !          1519:        vm_object_unlock(prev_object);
        !          1520:        return(TRUE);
        !          1521: }
        !          1522: 
        !          1523: vm_object_t    vm_object_request_object(p)
        !          1524:        port_t          p;
        !          1525: {
        !          1526: #ifdef lint
        !          1527:        p++;
        !          1528: #endif lint
        !          1529:        printf("vm_object_request_object: called\n");
        !          1530:        return(VM_OBJECT_NULL);
        !          1531: }
        !          1532: 
        !          1533: /*
        !          1534:  *     Routine:        vm_object_name
        !          1535:  *     Purpose:
        !          1536:  *             Returns a reference to the "name" port associated
        !          1537:  *             with this object.
        !          1538:  */
        !          1539: port_t         vm_object_name(object)
        !          1540:        vm_object_t     object;
        !          1541: {
        !          1542:        return ((port_t)object);
        !          1543: }
        !          1544: 
        !          1545: #if    DEBUG
        !          1546: /*
        !          1547:  *     vm_object_print:        [ debug ]
        !          1548:  */
        !          1549: void vm_object_print(object)
        !          1550:        vm_object_t     object;
        !          1551: {
        !          1552:        register vm_page_t      p;
        !          1553:        extern indent;
        !          1554: 
        !          1555:        register int count;
        !          1556: 
        !          1557:        if (object == VM_OBJECT_NULL)
        !          1558:                return;
        !          1559: 
        !          1560:        iprintf("Object 0x%x: size=0x%x, ref=%d, pager=0x%x+0x%x, shadow=(0x%x)+0x%x\n",
        !          1561:                (int) object, (int) object->size, object->ref_count, (int) object->pager,
        !          1562:                (int) object->paging_offset,
        !          1563:                (int) object->shadow, (int) object->shadow_offset);
        !          1564: 
        !          1565:        indent += 2;
        !          1566: 
        !          1567:        count = 0;
        !          1568:        p = (vm_page_t) queue_first(&object->memq);
        !          1569:        while (!queue_end(&object->memq, (queue_entry_t) p)) {
        !          1570:                if (count == 0) iprintf("memory:=");
        !          1571:                else if (count == 6) {printf("\n"); iprintf(" ..."); count = 0;}
        !          1572:                else printf(",");
        !          1573:                count++;
        !          1574: 
        !          1575:                printf("(off=0x%x,page=0x%x)", p->offset, VM_PAGE_TO_PHYS(p));
        !          1576:                p = (vm_page_t) queue_next(&p->listq);
        !          1577:        }
        !          1578:        if (count != 0)
        !          1579:                printf("\n");
        !          1580:        indent -= 2;
        !          1581: }
        !          1582: #endif DEBUG
        !          1583: 
        !          1584: 

unix.superglobalmegacorp.com

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