|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988,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: */ ! 52: /* ! 53: * File: vm/vm_object.c ! 54: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 55: * ! 56: * Virtual memory object module. ! 57: */ ! 58: ! 59: #ifdef MACH_BSD ! 60: /* remove as part of compoenent support merge */ ! 61: extern int vnode_pager_workaround; ! 62: #endif ! 63: ! 64: #include <mach_pagemap.h> ! 65: #include <task_swapper.h> ! 66: ! 67: #include <mach/memory_object.h> ! 68: #include <mach/memory_object_default.h> ! 69: #include <mach/memory_object_control_server.h> ! 70: #include <mach/vm_param.h> ! 71: #include <ipc/ipc_port.h> ! 72: #include <ipc/ipc_space.h> ! 73: #include <kern/assert.h> ! 74: #include <kern/lock.h> ! 75: #include <kern/queue.h> ! 76: #include <kern/xpr.h> ! 77: #include <kern/zalloc.h> ! 78: #include <kern/host.h> ! 79: #include <kern/host_statistics.h> ! 80: #include <vm/memory_object.h> ! 81: #include <vm/vm_fault.h> ! 82: #include <vm/vm_map.h> ! 83: #include <vm/vm_object.h> ! 84: #include <vm/vm_page.h> ! 85: #include <vm/vm_pageout.h> ! 86: #include <kern/misc_protos.h> ! 87: ! 88: /* ! 89: * Virtual memory objects maintain the actual data ! 90: * associated with allocated virtual memory. A given ! 91: * page of memory exists within exactly one object. ! 92: * ! 93: * An object is only deallocated when all "references" ! 94: * are given up. Only one "reference" to a given ! 95: * region of an object should be writeable. ! 96: * ! 97: * Associated with each object is a list of all resident ! 98: * memory pages belonging to that object; this list is ! 99: * maintained by the "vm_page" module, but locked by the object's ! 100: * lock. ! 101: * ! 102: * Each object also records the memory object port ! 103: * that is used by the kernel to request and write ! 104: * back data (the memory object port, field "pager"), ! 105: * and the ports provided to the memory manager, the server that ! 106: * manages that data, to return data and control its ! 107: * use (the memory object control port, field "pager_request") ! 108: * and for naming (the memory object name port, field "pager_name"). ! 109: * ! 110: * Virtual memory objects are allocated to provide ! 111: * zero-filled memory (vm_allocate) or map a user-defined ! 112: * memory object into a virtual address space (vm_map). ! 113: * ! 114: * Virtual memory objects that refer to a user-defined ! 115: * memory object are called "permanent", because all changes ! 116: * made in virtual memory are reflected back to the ! 117: * memory manager, which may then store it permanently. ! 118: * Other virtual memory objects are called "temporary", ! 119: * meaning that changes need be written back only when ! 120: * necessary to reclaim pages, and that storage associated ! 121: * with the object can be discarded once it is no longer ! 122: * mapped. ! 123: * ! 124: * A permanent memory object may be mapped into more ! 125: * than one virtual address space. Moreover, two threads ! 126: * may attempt to make the first mapping of a memory ! 127: * object concurrently. Only one thread is allowed to ! 128: * complete this mapping; all others wait for the ! 129: * "pager_initialized" field is asserted, indicating ! 130: * that the first thread has initialized all of the ! 131: * necessary fields in the virtual memory object structure. ! 132: * ! 133: * The kernel relies on a *default memory manager* to ! 134: * provide backing storage for the zero-filled virtual ! 135: * memory objects. The memory object ports associated ! 136: * with these temporary virtual memory objects are only ! 137: * generated and passed to the default memory manager ! 138: * when it becomes necessary. Virtual memory objects ! 139: * that depend on the default memory manager are called ! 140: * "internal". The "pager_created" field is provided to ! 141: * indicate whether these ports have ever been allocated. ! 142: * ! 143: * The kernel may also create virtual memory objects to ! 144: * hold changed pages after a copy-on-write operation. ! 145: * In this case, the virtual memory object (and its ! 146: * backing storage -- its memory object) only contain ! 147: * those pages that have been changed. The "shadow" ! 148: * field refers to the virtual memory object that contains ! 149: * the remainder of the contents. The "shadow_offset" ! 150: * field indicates where in the "shadow" these contents begin. ! 151: * The "copy" field refers to a virtual memory object ! 152: * to which changed pages must be copied before changing ! 153: * this object, in order to implement another form ! 154: * of copy-on-write optimization. ! 155: * ! 156: * The virtual memory object structure also records ! 157: * the attributes associated with its memory object. ! 158: * The "pager_ready", "can_persist" and "copy_strategy" ! 159: * fields represent those attributes. The "cached_list" ! 160: * field is used in the implementation of the persistence ! 161: * attribute. ! 162: * ! 163: * ZZZ Continue this comment. ! 164: */ ! 165: ! 166: /* Forward declarations for internal functions. */ ! 167: extern void _vm_object_allocate( ! 168: vm_size_t size, ! 169: vm_object_t object); ! 170: ! 171: extern void vm_object_terminate( ! 172: vm_object_t object); ! 173: ! 174: extern void vm_object_remove( ! 175: vm_object_t object); ! 176: ! 177: extern vm_object_t vm_object_cache_trim( ! 178: boolean_t called_from_vm_object_deallocate); ! 179: ! 180: extern void vm_object_deactivate_pages( ! 181: vm_object_t object); ! 182: ! 183: extern void vm_object_abort_activity( ! 184: vm_object_t object); ! 185: ! 186: extern kern_return_t vm_object_copy_call( ! 187: vm_object_t src_object, ! 188: vm_offset_t src_offset, ! 189: vm_size_t size, ! 190: vm_object_t *_result_object); ! 191: ! 192: extern void vm_object_do_collapse( ! 193: vm_object_t object, ! 194: vm_object_t backing_object); ! 195: ! 196: extern void vm_object_do_bypass( ! 197: vm_object_t object, ! 198: vm_object_t backing_object); ! 199: ! 200: extern void memory_object_release( ! 201: ipc_port_t pager, ! 202: pager_request_t pager_request); ! 203: ! 204: zone_t vm_object_zone; /* vm backing store zone */ ! 205: ! 206: /* ! 207: * All wired-down kernel memory belongs to a single virtual ! 208: * memory object (kernel_object) to avoid wasting data structures. ! 209: */ ! 210: struct vm_object kernel_object_store; ! 211: vm_object_t kernel_object = &kernel_object_store; ! 212: ! 213: /* ! 214: * The submap object is used as a placeholder for vm_map_submap ! 215: * operations. The object is declared in vm_map.c because it ! 216: * is exported by the vm_map module. The storage is declared ! 217: * here because it must be initialized here. ! 218: */ ! 219: struct vm_object vm_submap_object_store; ! 220: ! 221: /* ! 222: * Virtual memory objects are initialized from ! 223: * a template (see vm_object_allocate). ! 224: * ! 225: * When adding a new field to the virtual memory ! 226: * object structure, be sure to add initialization ! 227: * (see vm_object_init). ! 228: */ ! 229: struct vm_object vm_object_template; ! 230: ! 231: /* ! 232: * Virtual memory objects that are not referenced by ! 233: * any address maps, but that are allowed to persist ! 234: * (an attribute specified by the associated memory manager), ! 235: * are kept in a queue (vm_object_cached_list). ! 236: * ! 237: * When an object from this queue is referenced again, ! 238: * for example to make another address space mapping, ! 239: * it must be removed from the queue. That is, the ! 240: * queue contains *only* objects with zero references. ! 241: * ! 242: * The kernel may choose to terminate objects from this ! 243: * queue in order to reclaim storage. The current policy ! 244: * is to permit a fixed maximum number of unreferenced ! 245: * objects (vm_object_cached_max). ! 246: * ! 247: * A spin lock (accessed by routines ! 248: * vm_object_cache_{lock,lock_try,unlock}) governs the ! 249: * object cache. It must be held when objects are ! 250: * added to or removed from the cache (in vm_object_terminate). ! 251: * The routines that acquire a reference to a virtual ! 252: * memory object based on one of the memory object ports ! 253: * must also lock the cache. ! 254: * ! 255: * Ideally, the object cache should be more isolated ! 256: * from the reference mechanism, so that the lock need ! 257: * not be held to make simple references. ! 258: */ ! 259: queue_head_t vm_object_cached_list; ! 260: int vm_object_cached_count; ! 261: int vm_object_cached_high; /* highest # of cached objects */ ! 262: int vm_object_cached_max = 500; /* may be patched*/ ! 263: ! 264: decl_mutex_data(,vm_object_cached_lock_data) ! 265: ! 266: #define vm_object_cache_lock() \ ! 267: mutex_lock(&vm_object_cached_lock_data) ! 268: #define vm_object_cache_lock_try() \ ! 269: mutex_try(&vm_object_cached_lock_data) ! 270: #define vm_object_cache_unlock() \ ! 271: mutex_unlock(&vm_object_cached_lock_data) ! 272: ! 273: #define VM_OBJECT_HASH_COUNT 1024 ! 274: queue_head_t vm_object_hashtable[VM_OBJECT_HASH_COUNT]; ! 275: struct zone *vm_object_hash_zone; ! 276: ! 277: struct vm_object_hash_entry { ! 278: queue_chain_t hash_link; /* hash chain link */ ! 279: ipc_port_t pager; /* pager we represent */ ! 280: vm_object_t object; /* corresponding object */ ! 281: boolean_t waiting; /* someone waiting for ! 282: * termination */ ! 283: }; ! 284: ! 285: typedef struct vm_object_hash_entry *vm_object_hash_entry_t; ! 286: #define VM_OBJECT_HASH_ENTRY_NULL ((vm_object_hash_entry_t) 0) ! 287: ! 288: #define VM_OBJECT_HASH_SHIFT 8 ! 289: #define vm_object_hash(pager) \ ! 290: ((((unsigned)pager) >> VM_OBJECT_HASH_SHIFT) % VM_OBJECT_HASH_COUNT) ! 291: ! 292: /* ! 293: * vm_object_hash_lookup looks up a pager in the hashtable ! 294: * and returns the corresponding entry, with optional removal. ! 295: */ ! 296: ! 297: vm_object_hash_entry_t ! 298: vm_object_hash_lookup( ! 299: ipc_port_t pager, ! 300: boolean_t remove_entry) ! 301: { ! 302: register queue_t bucket; ! 303: register vm_object_hash_entry_t entry; ! 304: ! 305: bucket = &vm_object_hashtable[vm_object_hash(pager)]; ! 306: ! 307: entry = (vm_object_hash_entry_t)queue_first(bucket); ! 308: while (!queue_end(bucket, (queue_entry_t)entry)) { ! 309: if (entry->pager == pager && !remove_entry) ! 310: return(entry); ! 311: else if (entry->pager == pager) { ! 312: queue_remove(bucket, entry, ! 313: vm_object_hash_entry_t, hash_link); ! 314: return(entry); ! 315: } ! 316: ! 317: entry = (vm_object_hash_entry_t)queue_next(&entry->hash_link); ! 318: } ! 319: ! 320: return(VM_OBJECT_HASH_ENTRY_NULL); ! 321: } ! 322: ! 323: /* ! 324: * vm_object_hash_enter enters the specified ! 325: * pager / cache object association in the hashtable. ! 326: */ ! 327: ! 328: void ! 329: vm_object_hash_insert( ! 330: vm_object_hash_entry_t entry) ! 331: { ! 332: register queue_t bucket; ! 333: ! 334: bucket = &vm_object_hashtable[vm_object_hash(entry->pager)]; ! 335: ! 336: queue_enter(bucket, entry, vm_object_hash_entry_t, hash_link); ! 337: } ! 338: ! 339: vm_object_hash_entry_t ! 340: vm_object_hash_entry_alloc( ! 341: ipc_port_t pager) ! 342: { ! 343: vm_object_hash_entry_t entry; ! 344: ! 345: entry = (vm_object_hash_entry_t)zalloc(vm_object_hash_zone); ! 346: entry->pager = pager; ! 347: entry->object = VM_OBJECT_NULL; ! 348: entry->waiting = FALSE; ! 349: ! 350: return(entry); ! 351: } ! 352: ! 353: void ! 354: vm_object_hash_entry_free( ! 355: vm_object_hash_entry_t entry) ! 356: { ! 357: zfree(vm_object_hash_zone, (vm_offset_t)entry); ! 358: } ! 359: ! 360: /* ! 361: * vm_object_allocate: ! 362: * ! 363: * Returns a new object with the given size. ! 364: */ ! 365: ! 366: void ! 367: _vm_object_allocate( ! 368: vm_size_t size, ! 369: vm_object_t object) ! 370: { ! 371: XPR(XPR_VM_OBJECT, ! 372: "vm_object_allocate, object 0x%X size 0x%X\n", ! 373: (integer_t)object, size, 0,0,0); ! 374: ! 375: *object = vm_object_template; ! 376: queue_init(&object->memq); ! 377: queue_init(&object->msr_q); ! 378: vm_object_lock_init(object); ! 379: object->size = size; ! 380: } ! 381: ! 382: vm_object_t ! 383: vm_object_allocate( ! 384: vm_size_t size) ! 385: { ! 386: register vm_object_t object; ! 387: register ipc_port_t port; ! 388: ! 389: object = (vm_object_t) zalloc(vm_object_zone); ! 390: ! 391: // dbgLog(object, size, 0, 2); /* (TEST/DEBUG) */ ! 392: ! 393: _vm_object_allocate(size, object); ! 394: ! 395: return object; ! 396: } ! 397: ! 398: /* ! 399: * vm_object_bootstrap: ! 400: * ! 401: * Initialize the VM objects module. ! 402: */ ! 403: void ! 404: vm_object_bootstrap(void) ! 405: { ! 406: register i; ! 407: ! 408: vm_object_zone = zinit((vm_size_t) sizeof(struct vm_object), ! 409: round_page(512*1024), ! 410: round_page(12*1024), ! 411: "vm objects"); ! 412: ! 413: queue_init(&vm_object_cached_list); ! 414: mutex_init(&vm_object_cached_lock_data, ETAP_VM_OBJ_CACHE); ! 415: ! 416: vm_object_hash_zone = ! 417: zinit((vm_size_t) sizeof (struct vm_object_hash_entry), ! 418: round_page(512*1024), ! 419: round_page(12*1024), ! 420: "vm object hash entries"); ! 421: ! 422: for (i = 0; i < VM_OBJECT_HASH_COUNT; i++) ! 423: queue_init(&vm_object_hashtable[i]); ! 424: ! 425: /* ! 426: * Fill in a template object, for quick initialization ! 427: */ ! 428: ! 429: /* memq; Lock; init after allocation */ ! 430: vm_object_template.size = 0; ! 431: vm_object_template.frozen_size = 0; ! 432: vm_object_template.ref_count = 1; ! 433: #if TASK_SWAPPER ! 434: vm_object_template.res_count = 1; ! 435: #endif /* TASK_SWAPPER */ ! 436: vm_object_template.resident_page_count = 0; ! 437: vm_object_template.copy = VM_OBJECT_NULL; ! 438: vm_object_template.shadow = VM_OBJECT_NULL; ! 439: vm_object_template.shadow_offset = (vm_offset_t) 0; ! 440: vm_object_template.true_share = FALSE; ! 441: ! 442: vm_object_template.pager = IP_NULL; ! 443: vm_object_template.paging_offset = 0; ! 444: vm_object_template.pager_request = PAGER_REQUEST_NULL; ! 445: /* msr_q; init after allocation */ ! 446: ! 447: vm_object_template.copy_strategy = MEMORY_OBJECT_COPY_SYMMETRIC; ! 448: vm_object_template.absent_count = 0; ! 449: vm_object_template.paging_in_progress = 0; ! 450: ! 451: /* Begin bitfields */ ! 452: vm_object_template.all_wanted = 0; /* all bits FALSE */ ! 453: vm_object_template.pager_created = FALSE; ! 454: vm_object_template.pager_initialized = FALSE; ! 455: vm_object_template.pager_ready = FALSE; ! 456: vm_object_template.pager_trusted = FALSE; ! 457: vm_object_template.can_persist = FALSE; ! 458: vm_object_template.internal = TRUE; ! 459: vm_object_template.temporary = TRUE; ! 460: vm_object_template.private = FALSE; ! 461: vm_object_template.pageout = FALSE; ! 462: vm_object_template.alive = TRUE; ! 463: vm_object_template.lock_in_progress = FALSE; ! 464: vm_object_template.lock_restart = FALSE; ! 465: vm_object_template.silent_overwrite = FALSE; ! 466: vm_object_template.advisory_pageout = FALSE; ! 467: vm_object_template.shadowed = FALSE; ! 468: /* End bitfields */ ! 469: ! 470: /* cached_list; init after allocation */ ! 471: vm_object_template.last_alloc = (vm_offset_t) 0; ! 472: vm_object_template.cluster_size = 0; ! 473: #if MACH_PAGEMAP ! 474: vm_object_template.existence_map = VM_EXTERNAL_NULL; ! 475: #endif /* MACH_PAGEMAP */ ! 476: #if MACH_ASSERT ! 477: vm_object_template.paging_object = VM_OBJECT_NULL; ! 478: #endif /* MACH_ASSERT */ ! 479: ! 480: /* ! 481: * Initialize the "kernel object" ! 482: */ ! 483: ! 484: kernel_object = &kernel_object_store; ! 485: ! 486: /* ! 487: * Note that in the following size specifications, we need to add 1 because ! 488: * VM_MAX_KERNEL_ADDRESS is a maximum address, not a size. ! 489: */ ! 490: _vm_object_allocate((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) + 1, ! 491: kernel_object); ! 492: ! 493: /* ! 494: * Initialize the "submap object". Make it as large as the ! 495: * kernel object so that no limit is imposed on submap sizes. ! 496: */ ! 497: ! 498: vm_submap_object = &vm_submap_object_store; ! 499: _vm_object_allocate((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) + 1, ! 500: vm_submap_object); ! 501: /* ! 502: * Create an "extra" reference to this object so that we never ! 503: * try to deallocate it; zfree doesn't like to be called with ! 504: * non-zone memory. ! 505: */ ! 506: vm_object_reference(vm_submap_object); ! 507: ! 508: #if MACH_PAGEMAP ! 509: vm_external_module_initialize(); ! 510: #endif /* MACH_PAGEMAP */ ! 511: } ! 512: ! 513: void ! 514: vm_object_init(void) ! 515: { ! 516: /* ! 517: * Finish initializing the kernel object. ! 518: */ ! 519: } ! 520: ! 521: #if TASK_SWAPPER ! 522: /* ! 523: * vm_object_res_deallocate ! 524: * ! 525: * (recursively) decrement residence counts on vm objects and their shadows. ! 526: * Called from vm_object_deallocate and when swapping out an object. ! 527: * ! 528: * The object is locked, and remains locked throughout the function, ! 529: * even as we iterate down the shadow chain. Locks on intermediate objects ! 530: * will be dropped, but not the original object. ! 531: * ! 532: * NOTE: this function used to use recursion, rather than iteration. ! 533: */ ! 534: ! 535: void ! 536: vm_object_res_deallocate( ! 537: vm_object_t object) ! 538: { ! 539: vm_object_t orig_object = object; ! 540: /* ! 541: * Object is locked so it can be called directly ! 542: * from vm_object_deallocate. Original object is never ! 543: * unlocked. ! 544: */ ! 545: assert(object->res_count > 0); ! 546: while (--object->res_count == 0) { ! 547: assert(object->ref_count >= object->res_count); ! 548: vm_object_deactivate_pages(object); ! 549: /* iterate on shadow, if present */ ! 550: if (object->shadow != VM_OBJECT_NULL) { ! 551: vm_object_t tmp_object = object->shadow; ! 552: vm_object_lock(tmp_object); ! 553: if (object != orig_object) ! 554: vm_object_unlock(object); ! 555: object = tmp_object; ! 556: assert(object->res_count > 0); ! 557: } else ! 558: break; ! 559: } ! 560: if (object != orig_object) ! 561: vm_object_unlock(object); ! 562: } ! 563: ! 564: /* ! 565: * vm_object_res_reference ! 566: * ! 567: * Internal function to increment residence count on a vm object ! 568: * and its shadows. It is called only from vm_object_reference, and ! 569: * when swapping in a vm object, via vm_map_swap. ! 570: * ! 571: * The object is locked, and remains locked throughout the function, ! 572: * even as we iterate down the shadow chain. Locks on intermediate objects ! 573: * will be dropped, but not the original object. ! 574: * ! 575: * NOTE: this function used to use recursion, rather than iteration. ! 576: */ ! 577: ! 578: void ! 579: vm_object_res_reference( ! 580: vm_object_t object) ! 581: { ! 582: vm_object_t orig_object = object; ! 583: /* ! 584: * Object is locked, so this can be called directly ! 585: * from vm_object_reference. This lock is never released. ! 586: */ ! 587: while ((++object->res_count == 1) && ! 588: (object->shadow != VM_OBJECT_NULL)) { ! 589: vm_object_t tmp_object = object->shadow; ! 590: ! 591: assert(object->ref_count >= object->res_count); ! 592: vm_object_lock(tmp_object); ! 593: if (object != orig_object) ! 594: vm_object_unlock(object); ! 595: object = tmp_object; ! 596: } ! 597: if (object != orig_object) ! 598: vm_object_unlock(object); ! 599: assert(orig_object->ref_count >= orig_object->res_count); ! 600: } ! 601: #endif /* TASK_SWAPPER */ ! 602: ! 603: #if MACH_ASSERT ! 604: /* ! 605: * vm_object_reference: ! 606: * ! 607: * Gets another reference to the given object. ! 608: */ ! 609: void ! 610: vm_object_reference( ! 611: register vm_object_t object) ! 612: { ! 613: if (object == VM_OBJECT_NULL) ! 614: return; ! 615: ! 616: vm_object_lock(object); ! 617: assert(object->ref_count > 0); ! 618: object->ref_count++; ! 619: vm_object_res_reference(object); ! 620: vm_object_unlock(object); ! 621: } ! 622: #endif /* MACH_ASSERT */ ! 623: ! 624: #define MIGHT_NOT_CACHE_SHADOWS 1 ! 625: #if MIGHT_NOT_CACHE_SHADOWS ! 626: int cache_shadows = TRUE; ! 627: #endif /* MIGHT_NOT_CACHE_SHADOWS */ ! 628: ! 629: /* ! 630: * vm_object_deallocate: ! 631: * ! 632: * Release a reference to the specified object, ! 633: * gained either through a vm_object_allocate ! 634: * or a vm_object_reference call. When all references ! 635: * are gone, storage associated with this object ! 636: * may be relinquished. ! 637: * ! 638: * No object may be locked. ! 639: */ ! 640: void ! 641: vm_object_deallocate( ! 642: register vm_object_t object) ! 643: { ! 644: boolean_t retry_cache_trim = FALSE; ! 645: vm_object_t shadow; ! 646: ! 647: // if(object)dbgLog(object, object->ref_count, object->can_persist, 3); /* (TEST/DEBUG) */ ! 648: // else dbgLog(object, 0, 0, 3); /* (TEST/DEBUG) */ ! 649: ! 650: ! 651: while (object != VM_OBJECT_NULL) { ! 652: ! 653: /* ! 654: * The cache holds a reference (uncounted) to ! 655: * the object; we must lock it before removing ! 656: * the object. ! 657: */ ! 658: ! 659: vm_object_cache_lock(); ! 660: vm_object_lock(object); ! 661: assert(object->alive); ! 662: ! 663: /* ! 664: * Lose the reference. If other references ! 665: * remain, then we are done, unless we need ! 666: * to retry a cache trim. ! 667: * If it is the last reference, then keep it ! 668: * until any pending initialization is completed. ! 669: */ ! 670: ! 671: assert(object->ref_count > 0); ! 672: if (object->ref_count > 1) { ! 673: object->ref_count--; ! 674: vm_object_res_deallocate(object); ! 675: vm_object_unlock(object); ! 676: vm_object_cache_unlock(); ! 677: if (retry_cache_trim && ! 678: ((object = vm_object_cache_trim(TRUE)) != ! 679: VM_OBJECT_NULL)) { ! 680: continue; ! 681: } ! 682: return; ! 683: } ! 684: ! 685: /* ! 686: * We have to wait for initialization ! 687: * before destroying or caching the object. ! 688: */ ! 689: ! 690: if (object->pager_created && ! object->pager_initialized) { ! 691: assert(! object->can_persist); ! 692: vm_object_assert_wait(object, ! 693: VM_OBJECT_EVENT_INITIALIZED, ! 694: THREAD_UNINT); ! 695: vm_object_unlock(object); ! 696: vm_object_cache_unlock(); ! 697: thread_block((void (*)(void))0); ! 698: continue; ! 699: } ! 700: ! 701: /* ! 702: * If this object can persist, then enter it in ! 703: * the cache. Otherwise, terminate it. ! 704: * ! 705: * NOTE: Only permanent objects are cached, and ! 706: * permanent objects cannot have shadows. This ! 707: * affects the residence counting logic in a minor ! 708: * way (can do it in-line, mostly). ! 709: */ ! 710: ! 711: if (object->can_persist) { ! 712: /* ! 713: * Now it is safe to decrement reference count, ! 714: * and to return if reference count is > 0. ! 715: */ ! 716: if (--object->ref_count > 0) { ! 717: vm_object_res_deallocate(object); ! 718: vm_object_unlock(object); ! 719: vm_object_cache_unlock(); ! 720: if (retry_cache_trim && ! 721: ((object = vm_object_cache_trim(TRUE)) != ! 722: VM_OBJECT_NULL)) { ! 723: continue; ! 724: } ! 725: return; ! 726: } ! 727: ! 728: #if MIGHT_NOT_CACHE_SHADOWS ! 729: /* ! 730: * Remove shadow now if we don't ! 731: * want to cache shadows. ! 732: */ ! 733: if (! cache_shadows) { ! 734: shadow = object->shadow; ! 735: object->shadow = VM_OBJECT_NULL; ! 736: } ! 737: #endif /* MIGHT_NOT_CACHE_SHADOWS */ ! 738: ! 739: /* ! 740: * Enter the object onto the queue of ! 741: * cached objects, and deactivate ! 742: * all of its pages. ! 743: */ ! 744: assert(object->shadow == VM_OBJECT_NULL); ! 745: VM_OBJ_RES_DECR(object); ! 746: XPR(XPR_VM_OBJECT, ! 747: "vm_o_deallocate: adding %x to cache, queue = (%x, %x)\n", ! 748: (integer_t)object, ! 749: (integer_t)vm_object_cached_list.next, ! 750: (integer_t)vm_object_cached_list.prev,0,0); ! 751: ! 752: vm_object_cached_count++; ! 753: if (vm_object_cached_count > vm_object_cached_high) ! 754: vm_object_cached_high = vm_object_cached_count; ! 755: queue_enter(&vm_object_cached_list, object, ! 756: vm_object_t, cached_list); ! 757: vm_object_cache_unlock(); ! 758: vm_object_deactivate_pages(object); ! 759: vm_object_unlock(object); ! 760: ! 761: #if MIGHT_NOT_CACHE_SHADOWS ! 762: /* ! 763: * If we have a shadow that we need ! 764: * to deallocate, do so now, remembering ! 765: * to trim the cache later. ! 766: */ ! 767: if (! cache_shadows && shadow != VM_OBJECT_NULL) { ! 768: object = shadow; ! 769: retry_cache_trim = TRUE; ! 770: continue; ! 771: } ! 772: #endif /* MIGHT_NOT_CACHE_SHADOWS */ ! 773: ! 774: /* ! 775: * Trim the cache. If the cache trim ! 776: * returns with a shadow for us to deallocate, ! 777: * then remember to retry the cache trim ! 778: * when we are done deallocating the shadow. ! 779: * Otherwise, we are done. ! 780: */ ! 781: ! 782: object = vm_object_cache_trim(TRUE); ! 783: if (object == VM_OBJECT_NULL) { ! 784: return; ! 785: } ! 786: retry_cache_trim = TRUE; ! 787: ! 788: } else { ! 789: /* ! 790: * This object is not cachable; terminate it. ! 791: */ ! 792: XPR(XPR_VM_OBJECT, ! 793: "vm_o_deallocate: !cacheable 0x%X res %d paging_ops %d thread 0x%lX ref %d\n", ! 794: (integer_t)object, object->resident_page_count, ! 795: object->paging_in_progress, ! 796: (natural_t)current_thread(),object->ref_count); ! 797: ! 798: VM_OBJ_RES_DECR(object); /* XXX ? */ ! 799: /* ! 800: * Terminate this object. If it had a shadow, ! 801: * then deallocate it; otherwise, if we need ! 802: * to retry a cache trim, do so now; otherwise, ! 803: * we are done. "pageout" objects have a shadow, ! 804: * but maintain a "paging reference" rather than ! 805: * a normal reference. ! 806: */ ! 807: shadow = object->pageout?VM_OBJECT_NULL:object->shadow; ! 808: vm_object_terminate(object); ! 809: if (shadow != VM_OBJECT_NULL) { ! 810: object = shadow; ! 811: continue; ! 812: } ! 813: if (retry_cache_trim && ! 814: ((object = vm_object_cache_trim(TRUE)) != ! 815: VM_OBJECT_NULL)) { ! 816: continue; ! 817: } ! 818: return; ! 819: } ! 820: } ! 821: assert(! retry_cache_trim); ! 822: } ! 823: ! 824: /* ! 825: * Check to see whether we really need to trim ! 826: * down the cache. If so, remove an object from ! 827: * the cache, terminate it, and repeat. ! 828: * ! 829: * Called with, and returns with, cache lock unlocked. ! 830: */ ! 831: vm_object_t ! 832: vm_object_cache_trim( ! 833: boolean_t called_from_vm_object_deallocate) ! 834: { ! 835: register vm_object_t object = VM_OBJECT_NULL; ! 836: vm_object_t shadow; ! 837: ! 838: for (;;) { ! 839: ! 840: /* ! 841: * If we no longer need to trim the cache, ! 842: * then we are done. ! 843: */ ! 844: ! 845: vm_object_cache_lock(); ! 846: if (vm_object_cached_count <= vm_object_cached_max) { ! 847: vm_object_cache_unlock(); ! 848: return VM_OBJECT_NULL; ! 849: } ! 850: ! 851: /* ! 852: * We must trim down the cache, so remove ! 853: * the first object in the cache. ! 854: */ ! 855: XPR(XPR_VM_OBJECT, ! 856: "vm_object_cache_trim: removing from front of cache (%x, %x)\n", ! 857: (integer_t)vm_object_cached_list.next, ! 858: (integer_t)vm_object_cached_list.prev, 0, 0, 0); ! 859: ! 860: object = (vm_object_t) queue_first(&vm_object_cached_list); ! 861: vm_object_lock(object); ! 862: queue_remove(&vm_object_cached_list, object, vm_object_t, ! 863: cached_list); ! 864: vm_object_cached_count--; ! 865: ! 866: /* ! 867: * Since this object is in the cache, we know ! 868: * that it is initialized and has no references. ! 869: * Take a reference to avoid recursive deallocations. ! 870: */ ! 871: ! 872: assert(object->pager_initialized); ! 873: assert(object->ref_count == 0); ! 874: object->ref_count++; ! 875: ! 876: /* ! 877: * Terminate the object. ! 878: * If the object had a shadow, we let vm_object_deallocate ! 879: * deallocate it. "pageout" objects have a shadow, but ! 880: * maintain a "paging reference" rather than a normal ! 881: * reference. ! 882: * (We are careful here to limit recursion.) ! 883: */ ! 884: shadow = object->pageout?VM_OBJECT_NULL:object->shadow; ! 885: vm_object_terminate(object); ! 886: if (shadow != VM_OBJECT_NULL) { ! 887: if (called_from_vm_object_deallocate) { ! 888: return shadow; ! 889: } else { ! 890: vm_object_deallocate(shadow); ! 891: } ! 892: } ! 893: } ! 894: } ! 895: ! 896: boolean_t vm_object_terminate_remove_all = FALSE; ! 897: ! 898: /* ! 899: * Routine: vm_object_terminate ! 900: * Purpose: ! 901: * Free all resources associated with a vm_object. ! 902: * In/out conditions: ! 903: * Upon entry, the object and the cache must be locked, ! 904: * and the object must have exactly one reference. ! 905: * ! 906: * The shadow object reference is left alone. ! 907: * ! 908: * Upon exit, the cache will be unlocked, and the ! 909: * object will cease to exist. ! 910: */ ! 911: void ! 912: vm_object_terminate( ! 913: register vm_object_t object) ! 914: { ! 915: register vm_page_t p; ! 916: vm_object_t shadow_object; ! 917: ! 918: XPR(XPR_VM_OBJECT, "vm_object_terminate, object 0x%X ref %d\n", ! 919: (integer_t)object, object->ref_count, 0, 0, 0); ! 920: ! 921: /* ! 922: * Make sure the object isn't already being terminated ! 923: */ ! 924: ! 925: assert(object->alive); ! 926: object->alive = FALSE; ! 927: ! 928: /* ! 929: * Make sure no one can look us up now. ! 930: */ ! 931: ! 932: if(object->pager != IP_NULL) { ! 933: vm_object_hash_entry_t entry; ! 934: ! 935: entry = vm_object_hash_lookup(object->pager, FALSE); ! 936: if (entry != VM_OBJECT_HASH_ENTRY_NULL) ! 937: entry->object = VM_OBJECT_NULL; ! 938: } ! 939: ! 940: vm_object_cache_unlock(); ! 941: ! 942: /* ! 943: * Detach the object from its shadow if we are the shadow's ! 944: * copy. ! 945: */ ! 946: if (((shadow_object = object->shadow) != VM_OBJECT_NULL) && ! 947: !(object->pageout)) { ! 948: vm_object_lock(shadow_object); ! 949: assert((shadow_object->copy == object) || ! 950: (shadow_object->copy == VM_OBJECT_NULL)); ! 951: shadow_object->copy = VM_OBJECT_NULL; ! 952: vm_object_unlock(shadow_object); ! 953: } ! 954: ! 955: /* ! 956: * The pageout daemon might be playing with our pages. ! 957: * Now that the object is dead, it won't touch any more ! 958: * pages, but some pages might already be on their way out. ! 959: * Hence, we wait until the active paging activities have ceased. ! 960: */ ! 961: vm_object_paging_wait(object, THREAD_UNINT); ! 962: object->ref_count--; ! 963: #if TASK_SWAPPER ! 964: assert(object->res_count == 0); ! 965: #endif /* TASK_SWAPPER */ ! 966: ! 967: Restart: ! 968: assert (object->ref_count == 0); ! 969: ! 970: /* ! 971: * Clean or free the pages, as appropriate. ! 972: * It is possible for us to find busy/absent pages, ! 973: * if some faults on this object were aborted. ! 974: */ ! 975: if (object->pageout) { ! 976: assert(shadow_object != VM_OBJECT_NULL); ! 977: assert(shadow_object == object->shadow); ! 978: ! 979: vm_pageout_object_terminate(object); ! 980: ! 981: } else if (object->temporary && ! object->can_persist || ! 982: object->pager == IP_NULL) { ! 983: while (!queue_empty(&object->memq)) { ! 984: p = (vm_page_t) queue_first(&object->memq); ! 985: ! 986: VM_PAGE_CHECK(p); ! 987: ! 988: if (p->busy && !p->absent) ! 989: panic("vm_object_terminate.2 0x%x 0x%x", ! 990: object, p); ! 991: ! 992: VM_PAGE_FREE(p); ! 993: } ! 994: } else while (!queue_empty(&object->memq)) { ! 995: /* ! 996: * Clear pager_trusted bit so that the pages get yanked ! 997: * out of the object instead of cleaned in place. This ! 998: * prevents a deadlock in XMM and makes more sense anyway. ! 999: */ ! 1000: object->pager_trusted = FALSE; ! 1001: ! 1002: p = (vm_page_t) queue_first(&object->memq); ! 1003: ! 1004: VM_PAGE_CHECK(p); ! 1005: ! 1006: if (p->busy && !p->absent) ! 1007: panic("vm_object_terminate.3 0x%x 0x%x", object, p); ! 1008: ! 1009: vm_page_lock_queues(); ! 1010: VM_PAGE_QUEUES_REMOVE(p); ! 1011: vm_page_unlock_queues(); ! 1012: ! 1013: if (p->absent || p->private) { ! 1014: ! 1015: /* ! 1016: * For private pages, VM_PAGE_FREE just ! 1017: * leaves the page structure around for ! 1018: * its owner to clean up. For absent ! 1019: * pages, the structure is returned to ! 1020: * the appropriate pool. ! 1021: */ ! 1022: ! 1023: goto free_page; ! 1024: } ! 1025: ! 1026: if (p->fictitious) ! 1027: panic("vm_object_terminate.4 0x%x 0x%x", object, p); ! 1028: ! 1029: if (!p->dirty) ! 1030: p->dirty = pmap_is_modified(p->phys_addr); ! 1031: ! 1032: if (p->dirty || p->precious) { ! 1033: p->busy = TRUE; ! 1034: vm_object_paging_begin(object); ! 1035: vm_object_unlock(object); ! 1036: vm_pageout_cluster(p); /* flush page */ ! 1037: vm_object_lock(object); ! 1038: vm_object_paging_wait(object, THREAD_UNINT); ! 1039: ! 1040: XPR(XPR_VM_OBJECT, ! 1041: "vm_object_terminate restart, object 0x%X ref %d\n", ! 1042: (integer_t)object, object->ref_count, 0, 0, 0); ! 1043: ! 1044: goto Restart; ! 1045: } else { ! 1046: free_page: ! 1047: VM_PAGE_FREE(p); ! 1048: } ! 1049: } ! 1050: ! 1051: assert(object->paging_in_progress == 0); ! 1052: assert(object->ref_count == 0); ! 1053: ! 1054: vm_object_remove(object); ! 1055: ! 1056: /* ! 1057: * Throw away port rights... note that they may ! 1058: * already have been thrown away (by vm_object_destroy ! 1059: * or memory_object_destroy). ! 1060: * ! 1061: * Instead of destroying the control port, ! 1062: * we send all rights off to the memory manager, ! 1063: * using memory_object_terminate. ! 1064: */ ! 1065: ! 1066: vm_object_unlock(object); ! 1067: if (object->pager != IP_NULL) { ! 1068: /* consumes our rights for pager, pager_request */ ! 1069: memory_object_release(object->pager, object->pager_request); ! 1070: } ! 1071: ! 1072: #if MACH_PAGEMAP ! 1073: vm_external_destroy(object->existence_map, object->size); ! 1074: #endif /* MACH_PAGEMAP */ ! 1075: ! 1076: /* ! 1077: * Free the space for the object. ! 1078: */ ! 1079: ! 1080: zfree(vm_object_zone, (vm_offset_t) object); ! 1081: } ! 1082: ! 1083: /* ! 1084: * Routine: vm_object_pager_wakeup ! 1085: * Purpose: Wake up anyone waiting for termination of a pager. ! 1086: */ ! 1087: ! 1088: void ! 1089: vm_object_pager_wakeup( ! 1090: ipc_port_t pager) ! 1091: { ! 1092: vm_object_hash_entry_t entry; ! 1093: boolean_t waiting = FALSE; ! 1094: ! 1095: /* ! 1096: * If anyone was waiting for the memory_object_terminate ! 1097: * to be queued, wake them up now. ! 1098: */ ! 1099: vm_object_cache_lock(); ! 1100: entry = vm_object_hash_lookup(pager, TRUE); ! 1101: if (entry != VM_OBJECT_HASH_ENTRY_NULL) ! 1102: waiting = entry->waiting; ! 1103: vm_object_cache_unlock(); ! 1104: if (entry != VM_OBJECT_HASH_ENTRY_NULL) { ! 1105: if (waiting) ! 1106: thread_wakeup((event_t) pager); ! 1107: vm_object_hash_entry_free(entry); ! 1108: } ! 1109: } ! 1110: ! 1111: /* ! 1112: * Routine: memory_object_release ! 1113: * Purpose: Terminate the pager and release port rights, ! 1114: * just like memory_object_terminate, except ! 1115: * that we wake up anyone blocked in vm_object_enter ! 1116: * waiting for termination message to be queued ! 1117: * before calling memory_object_init. ! 1118: */ ! 1119: void ! 1120: memory_object_release( ! 1121: ipc_port_t pager, ! 1122: pager_request_t pager_request) ! 1123: { ! 1124: #ifdef MACH_BSD ! 1125: kern_return_t vnode_pager_terminate(ipc_port_t, ipc_port_t); ! 1126: #endif ! 1127: ! 1128: /* ! 1129: * Keep a reference to pager port; ! 1130: * the terminate might otherwise release all references. ! 1131: */ ! 1132: ipc_port_copy_send(pager); ! 1133: ! 1134: /* ! 1135: * Terminate the pager. ! 1136: */ ! 1137: ! 1138: #ifdef MACH_BSD ! 1139: if(((rpc_subsystem_t)pager_mux_hash_lookup(pager)) == ! 1140: ((rpc_subsystem_t) &vnode_pager_workaround)) { ! 1141: (void) vnode_pager_terminate(pager, pager_request); ! 1142: } else { ! 1143: (void) memory_object_terminate(pager, pager_request); ! 1144: } ! 1145: #else ! 1146: (void) memory_object_terminate(pager, pager_request); ! 1147: #endif ! 1148: ! 1149: /* ! 1150: * Wakeup anyone waiting for this terminate ! 1151: */ ! 1152: vm_object_pager_wakeup(pager); ! 1153: ! 1154: /* ! 1155: * Release reference to pager port. ! 1156: */ ! 1157: ipc_port_release_send(pager); ! 1158: } ! 1159: ! 1160: /* ! 1161: * Routine: vm_object_abort_activity [internal use only] ! 1162: * Purpose: ! 1163: * Abort paging requests pending on this object. ! 1164: * In/out conditions: ! 1165: * The object is locked on entry and exit. ! 1166: */ ! 1167: void ! 1168: vm_object_abort_activity( ! 1169: vm_object_t object) ! 1170: { ! 1171: register ! 1172: vm_page_t p; ! 1173: vm_page_t next; ! 1174: ! 1175: XPR(XPR_VM_OBJECT, "vm_object_abort_activity, object 0x%X\n", ! 1176: (integer_t)object, 0, 0, 0, 0); ! 1177: ! 1178: /* ! 1179: * Abort all activity that would be waiting ! 1180: * for a result on this memory object. ! 1181: * ! 1182: * We could also choose to destroy all pages ! 1183: * that we have in memory for this object, but ! 1184: * we don't. ! 1185: */ ! 1186: ! 1187: p = (vm_page_t) queue_first(&object->memq); ! 1188: while (!queue_end(&object->memq, (queue_entry_t) p)) { ! 1189: next = (vm_page_t) queue_next(&p->listq); ! 1190: ! 1191: /* ! 1192: * If it's being paged in, destroy it. ! 1193: * If an unlock has been requested, start it again. ! 1194: */ ! 1195: ! 1196: if (p->busy && p->absent) { ! 1197: VM_PAGE_FREE(p); ! 1198: } ! 1199: else { ! 1200: if (p->unlock_request != VM_PROT_NONE) ! 1201: p->unlock_request = VM_PROT_NONE; ! 1202: PAGE_WAKEUP(p); ! 1203: } ! 1204: ! 1205: p = next; ! 1206: } ! 1207: ! 1208: /* ! 1209: * Wake up threads waiting for the memory object to ! 1210: * become ready. ! 1211: */ ! 1212: ! 1213: object->pager_ready = TRUE; ! 1214: vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY); ! 1215: } ! 1216: ! 1217: /* ! 1218: * Routine: memory_object_destroy [user interface] ! 1219: * Purpose: ! 1220: * Shut down a memory object, despite the ! 1221: * presence of address map (or other) references ! 1222: * to the vm_object. ! 1223: */ ! 1224: kern_return_t ! 1225: memory_object_destroy( ! 1226: register vm_object_t object, ! 1227: kern_return_t reason) ! 1228: { ! 1229: ipc_port_t old_object; ! 1230: pager_request_t old_pager_request; ! 1231: ! 1232: #ifdef lint ! 1233: reason++; ! 1234: #endif /* lint */ ! 1235: ! 1236: if (object == VM_OBJECT_NULL) ! 1237: return(KERN_SUCCESS); ! 1238: ! 1239: /* ! 1240: * Remove the port associations immediately. ! 1241: * ! 1242: * This will prevent the memory manager from further ! 1243: * meddling. [If it wanted to flush data or make ! 1244: * other changes, it should have done so before performing ! 1245: * the destroy call.] ! 1246: */ ! 1247: ! 1248: vm_object_cache_lock(); ! 1249: vm_object_lock(object); ! 1250: vm_object_remove(object); ! 1251: object->can_persist = FALSE; ! 1252: vm_object_cache_unlock(); ! 1253: ! 1254: /* ! 1255: * Rip out the ports from the vm_object now... this ! 1256: * will prevent new memory_object calls from succeeding. ! 1257: */ ! 1258: ! 1259: old_object = object->pager; ! 1260: old_pager_request = object->pager_request; ! 1261: ! 1262: object->pager = IP_NULL; ! 1263: object->pager_request = PAGER_REQUEST_NULL; ! 1264: ! 1265: /* ! 1266: * Wait for existing paging activity (that might ! 1267: * have the old ports) to subside. ! 1268: */ ! 1269: ! 1270: vm_object_paging_wait(object, THREAD_UNINT); ! 1271: vm_object_unlock(object); ! 1272: ! 1273: /* ! 1274: * Shut down the ports now. ! 1275: * ! 1276: * [Paging operations may be proceeding concurrently -- ! 1277: * they'll get the null values established above.] ! 1278: */ ! 1279: ! 1280: if (old_object != IP_NULL) { ! 1281: /* consumes our rights for object, control */ ! 1282: memory_object_release(old_object, old_pager_request); ! 1283: } ! 1284: ! 1285: /* ! 1286: * Lose the reference that was donated for this routine ! 1287: */ ! 1288: ! 1289: vm_object_deallocate(object); ! 1290: ! 1291: return(KERN_SUCCESS); ! 1292: } ! 1293: ! 1294: /* ! 1295: * vm_object_deactivate_pages ! 1296: * ! 1297: * Deactivate all pages in the specified object. (Keep its pages ! 1298: * in memory even though it is no longer referenced.) ! 1299: * ! 1300: * The object must be locked. ! 1301: */ ! 1302: void ! 1303: vm_object_deactivate_pages( ! 1304: register vm_object_t object) ! 1305: { ! 1306: register vm_page_t p; ! 1307: ! 1308: queue_iterate(&object->memq, p, vm_page_t, listq) { ! 1309: vm_page_lock_queues(); ! 1310: if (!p->busy) ! 1311: vm_page_deactivate(p); ! 1312: vm_page_unlock_queues(); ! 1313: } ! 1314: } ! 1315: ! 1316: ! 1317: /* ! 1318: * Routine: vm_object_pmap_protect ! 1319: * ! 1320: * Purpose: ! 1321: * Reduces the permission for all physical ! 1322: * pages in the specified object range. ! 1323: * ! 1324: * If removing write permission only, it is ! 1325: * sufficient to protect only the pages in ! 1326: * the top-level object; only those pages may ! 1327: * have write permission. ! 1328: * ! 1329: * If removing all access, we must follow the ! 1330: * shadow chain from the top-level object to ! 1331: * remove access to all pages in shadowed objects. ! 1332: * ! 1333: * The object must *not* be locked. The object must ! 1334: * be temporary/internal. ! 1335: * ! 1336: * If pmap is not NULL, this routine assumes that ! 1337: * the only mappings for the pages are in that ! 1338: * pmap. ! 1339: */ ! 1340: ! 1341: void ! 1342: vm_object_pmap_protect( ! 1343: register vm_object_t object, ! 1344: register vm_offset_t offset, ! 1345: vm_offset_t size, ! 1346: pmap_t pmap, ! 1347: vm_offset_t pmap_start, ! 1348: vm_prot_t prot) ! 1349: { ! 1350: if (object == VM_OBJECT_NULL) ! 1351: return; ! 1352: ! 1353: vm_object_lock(object); ! 1354: ! 1355: assert(object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC); ! 1356: ! 1357: while (TRUE) { ! 1358: if (object->resident_page_count > atop(size) / 2 && ! 1359: pmap != PMAP_NULL) { ! 1360: vm_object_unlock(object); ! 1361: pmap_protect(pmap, pmap_start, pmap_start + size, prot); ! 1362: return; ! 1363: } ! 1364: ! 1365: { ! 1366: register vm_page_t p; ! 1367: register vm_offset_t end; ! 1368: ! 1369: end = offset + size; ! 1370: ! 1371: if (pmap != PMAP_NULL) { ! 1372: queue_iterate(&object->memq, p, vm_page_t, listq) { ! 1373: if (!p->fictitious && ! 1374: (offset <= p->offset) && (p->offset < end)) { ! 1375: ! 1376: vm_offset_t start = pmap_start + (p->offset - offset); ! 1377: ! 1378: pmap_protect(pmap, start, start + PAGE_SIZE, prot); ! 1379: } ! 1380: } ! 1381: } else { ! 1382: queue_iterate(&object->memq, p, vm_page_t, listq) { ! 1383: if (!p->fictitious && ! 1384: (offset <= p->offset) && (p->offset < end)) { ! 1385: ! 1386: pmap_page_protect(p->phys_addr, ! 1387: prot & ~p->page_lock); ! 1388: } ! 1389: } ! 1390: } ! 1391: } ! 1392: ! 1393: if (prot == VM_PROT_NONE) { ! 1394: /* ! 1395: * Must follow shadow chain to remove access ! 1396: * to pages in shadowed objects. ! 1397: */ ! 1398: register vm_object_t next_object; ! 1399: ! 1400: next_object = object->shadow; ! 1401: if (next_object != VM_OBJECT_NULL) { ! 1402: offset += object->shadow_offset; ! 1403: vm_object_lock(next_object); ! 1404: vm_object_unlock(object); ! 1405: object = next_object; ! 1406: } ! 1407: else { ! 1408: /* ! 1409: * End of chain - we are done. ! 1410: */ ! 1411: break; ! 1412: } ! 1413: } ! 1414: else { ! 1415: /* ! 1416: * Pages in shadowed objects may never have ! 1417: * write permission - we may stop here. ! 1418: */ ! 1419: break; ! 1420: } ! 1421: } ! 1422: ! 1423: vm_object_unlock(object); ! 1424: } ! 1425: ! 1426: /* ! 1427: * Routine: vm_object_copy_slowly ! 1428: * ! 1429: * Description: ! 1430: * Copy the specified range of the source ! 1431: * virtual memory object without using ! 1432: * protection-based optimizations (such ! 1433: * as copy-on-write). The pages in the ! 1434: * region are actually copied. ! 1435: * ! 1436: * In/out conditions: ! 1437: * The caller must hold a reference and a lock ! 1438: * for the source virtual memory object. The source ! 1439: * object will be returned *unlocked*. ! 1440: * ! 1441: * Results: ! 1442: * If the copy is completed successfully, KERN_SUCCESS is ! 1443: * returned. If the caller asserted the interruptible ! 1444: * argument, and an interruption occurred while waiting ! 1445: * for a user-generated event, MACH_SEND_INTERRUPTED is ! 1446: * returned. Other values may be returned to indicate ! 1447: * hard errors during the copy operation. ! 1448: * ! 1449: * A new virtual memory object is returned in a ! 1450: * parameter (_result_object). The contents of this ! 1451: * new object, starting at a zero offset, are a copy ! 1452: * of the source memory region. In the event of ! 1453: * an error, this parameter will contain the value ! 1454: * VM_OBJECT_NULL. ! 1455: */ ! 1456: kern_return_t ! 1457: vm_object_copy_slowly( ! 1458: register vm_object_t src_object, ! 1459: vm_offset_t src_offset, ! 1460: vm_size_t size, ! 1461: boolean_t interruptible, ! 1462: vm_object_t *_result_object) /* OUT */ ! 1463: { ! 1464: vm_object_t new_object; ! 1465: vm_offset_t new_offset; ! 1466: ! 1467: vm_offset_t src_lo_offset = src_offset; ! 1468: vm_offset_t src_hi_offset = src_offset + size; ! 1469: ! 1470: XPR(XPR_VM_OBJECT, "v_o_c_slowly obj 0x%x off 0x%x size 0x%x\n", ! 1471: src_object, src_offset, size, 0, 0); ! 1472: ! 1473: if (size == 0) { ! 1474: vm_object_unlock(src_object); ! 1475: *_result_object = VM_OBJECT_NULL; ! 1476: return(KERN_INVALID_ARGUMENT); ! 1477: } ! 1478: ! 1479: /* ! 1480: * Prevent destruction of the source object while we copy. ! 1481: */ ! 1482: ! 1483: assert(src_object->ref_count > 0); ! 1484: src_object->ref_count++; ! 1485: VM_OBJ_RES_INCR(src_object); ! 1486: vm_object_unlock(src_object); ! 1487: ! 1488: /* ! 1489: * Create a new object to hold the copied pages. ! 1490: * A few notes: ! 1491: * We fill the new object starting at offset 0, ! 1492: * regardless of the input offset. ! 1493: * We don't bother to lock the new object within ! 1494: * this routine, since we have the only reference. ! 1495: */ ! 1496: ! 1497: new_object = vm_object_allocate(size); ! 1498: new_offset = 0; ! 1499: ! 1500: assert(size == trunc_page(size)); /* Will the loop terminate? */ ! 1501: ! 1502: for ( ; ! 1503: size != 0 ; ! 1504: src_offset += PAGE_SIZE, new_offset += PAGE_SIZE, size -= PAGE_SIZE ! 1505: ) { ! 1506: vm_page_t new_page; ! 1507: vm_fault_return_t result; ! 1508: ! 1509: while ((new_page = vm_page_alloc(new_object, new_offset)) ! 1510: == VM_PAGE_NULL) { ! 1511: VM_PAGE_WAIT(); ! 1512: } ! 1513: ! 1514: do { ! 1515: vm_prot_t prot = VM_PROT_READ; ! 1516: vm_page_t _result_page; ! 1517: vm_page_t top_page; ! 1518: register ! 1519: vm_page_t result_page; ! 1520: kern_return_t error_code; ! 1521: ! 1522: vm_object_lock(src_object); ! 1523: vm_object_paging_begin(src_object); ! 1524: ! 1525: XPR(XPR_VM_FAULT,"vm_object_copy_slowly -> vm_fault_page",0,0,0,0,0); ! 1526: result = vm_fault_page(src_object, src_offset, ! 1527: VM_PROT_READ, FALSE, interruptible, ! 1528: src_lo_offset, src_hi_offset, ! 1529: VM_BEHAVIOR_SEQUENTIAL, ! 1530: &prot, &_result_page, &top_page, ! 1531: (int *)0, ! 1532: &error_code, FALSE, FALSE); ! 1533: ! 1534: switch(result) { ! 1535: case VM_FAULT_SUCCESS: ! 1536: result_page = _result_page; ! 1537: ! 1538: /* ! 1539: * We don't need to hold the object ! 1540: * lock -- the busy page will be enough. ! 1541: * [We don't care about picking up any ! 1542: * new modifications.] ! 1543: * ! 1544: * Copy the page to the new object. ! 1545: * ! 1546: * POLICY DECISION: ! 1547: * If result_page is clean, ! 1548: * we could steal it instead ! 1549: * of copying. ! 1550: */ ! 1551: ! 1552: vm_object_unlock(result_page->object); ! 1553: vm_page_copy(result_page, new_page); ! 1554: ! 1555: /* ! 1556: * Let go of both pages (make them ! 1557: * not busy, perform wakeup, activate). ! 1558: */ ! 1559: ! 1560: new_page->busy = FALSE; ! 1561: new_page->dirty = TRUE; ! 1562: vm_object_lock(result_page->object); ! 1563: PAGE_WAKEUP_DONE(result_page); ! 1564: ! 1565: vm_page_lock_queues(); ! 1566: if (!result_page->active && ! 1567: !result_page->inactive) ! 1568: vm_page_activate(result_page); ! 1569: vm_page_activate(new_page); ! 1570: vm_page_unlock_queues(); ! 1571: ! 1572: /* ! 1573: * Release paging references and ! 1574: * top-level placeholder page, if any. ! 1575: */ ! 1576: ! 1577: vm_fault_cleanup(result_page->object, ! 1578: top_page); ! 1579: ! 1580: break; ! 1581: ! 1582: case VM_FAULT_RETRY: ! 1583: break; ! 1584: ! 1585: case VM_FAULT_MEMORY_SHORTAGE: ! 1586: VM_PAGE_WAIT(); ! 1587: break; ! 1588: ! 1589: case VM_FAULT_FICTITIOUS_SHORTAGE: ! 1590: vm_page_more_fictitious(); ! 1591: break; ! 1592: ! 1593: case VM_FAULT_INTERRUPTED: ! 1594: vm_page_free(new_page); ! 1595: vm_object_deallocate(new_object); ! 1596: vm_object_deallocate(src_object); ! 1597: *_result_object = VM_OBJECT_NULL; ! 1598: return(MACH_SEND_INTERRUPTED); ! 1599: ! 1600: case VM_FAULT_MEMORY_ERROR: ! 1601: /* ! 1602: * A policy choice: ! 1603: * (a) ignore pages that we can't ! 1604: * copy ! 1605: * (b) return the null object if ! 1606: * any page fails [chosen] ! 1607: */ ! 1608: ! 1609: vm_page_free(new_page); ! 1610: vm_object_deallocate(new_object); ! 1611: vm_object_deallocate(src_object); ! 1612: *_result_object = VM_OBJECT_NULL; ! 1613: return(error_code ? error_code: ! 1614: KERN_MEMORY_ERROR); ! 1615: } ! 1616: } while (result != VM_FAULT_SUCCESS); ! 1617: } ! 1618: ! 1619: /* ! 1620: * Lose the extra reference, and return our object. ! 1621: */ ! 1622: ! 1623: vm_object_deallocate(src_object); ! 1624: *_result_object = new_object; ! 1625: return(KERN_SUCCESS); ! 1626: } ! 1627: ! 1628: /* ! 1629: * Routine: vm_object_copy_quickly ! 1630: * ! 1631: * Purpose: ! 1632: * Copy the specified range of the source virtual ! 1633: * memory object, if it can be done without waiting ! 1634: * for user-generated events. ! 1635: * ! 1636: * Results: ! 1637: * If the copy is successful, the copy is returned in ! 1638: * the arguments; otherwise, the arguments are not ! 1639: * affected. ! 1640: * ! 1641: * In/out conditions: ! 1642: * The object should be unlocked on entry and exit. ! 1643: */ ! 1644: ! 1645: /*ARGSUSED*/ ! 1646: boolean_t ! 1647: vm_object_copy_quickly( ! 1648: vm_object_t *_object, /* INOUT */ ! 1649: vm_offset_t offset, /* IN */ ! 1650: vm_size_t size, /* IN */ ! 1651: boolean_t *_src_needs_copy, /* OUT */ ! 1652: boolean_t *_dst_needs_copy) /* OUT */ ! 1653: { ! 1654: vm_object_t object = *_object; ! 1655: memory_object_copy_strategy_t copy_strategy; ! 1656: ! 1657: XPR(XPR_VM_OBJECT, "v_o_c_quickly obj 0x%x off 0x%x size 0x%x\n", ! 1658: *_object, offset, size, 0, 0); ! 1659: if (object == VM_OBJECT_NULL) { ! 1660: *_src_needs_copy = FALSE; ! 1661: *_dst_needs_copy = FALSE; ! 1662: return(TRUE); ! 1663: } ! 1664: ! 1665: vm_object_lock(object); ! 1666: ! 1667: copy_strategy = object->copy_strategy; ! 1668: ! 1669: switch (copy_strategy) { ! 1670: case MEMORY_OBJECT_COPY_SYMMETRIC: ! 1671: ! 1672: /* ! 1673: * Symmetric copy strategy. ! 1674: * Make another reference to the object. ! 1675: * Leave object/offset unchanged. ! 1676: */ ! 1677: ! 1678: assert(object->ref_count > 0); ! 1679: object->ref_count++; ! 1680: vm_object_res_reference(object); ! 1681: object->shadowed = TRUE; ! 1682: vm_object_unlock(object); ! 1683: ! 1684: /* ! 1685: * Both source and destination must make ! 1686: * shadows, and the source must be made ! 1687: * read-only if not already. ! 1688: */ ! 1689: ! 1690: *_src_needs_copy = TRUE; ! 1691: *_dst_needs_copy = TRUE; ! 1692: ! 1693: break; ! 1694: ! 1695: case MEMORY_OBJECT_COPY_DELAY: ! 1696: vm_object_unlock(object); ! 1697: return(FALSE); ! 1698: ! 1699: default: ! 1700: vm_object_unlock(object); ! 1701: return(FALSE); ! 1702: } ! 1703: return(TRUE); ! 1704: } ! 1705: ! 1706: int copy_call_count = 0; ! 1707: int copy_call_sleep_count = 0; ! 1708: int copy_call_restart_count = 0; ! 1709: ! 1710: /* ! 1711: * Routine: vm_object_copy_call [internal] ! 1712: * ! 1713: * Description: ! 1714: * Copy the source object (src_object), using the ! 1715: * user-managed copy algorithm. ! 1716: * ! 1717: * In/out conditions: ! 1718: * The source object must be locked on entry. It ! 1719: * will be *unlocked* on exit. ! 1720: * ! 1721: * Results: ! 1722: * If the copy is successful, KERN_SUCCESS is returned. ! 1723: * A new object that represents the copied virtual ! 1724: * memory is returned in a parameter (*_result_object). ! 1725: * If the return value indicates an error, this parameter ! 1726: * is not valid. ! 1727: */ ! 1728: kern_return_t ! 1729: vm_object_copy_call( ! 1730: vm_object_t src_object, ! 1731: vm_offset_t src_offset, ! 1732: vm_size_t size, ! 1733: vm_object_t *_result_object) /* OUT */ ! 1734: { ! 1735: kern_return_t kr; ! 1736: vm_object_t copy; ! 1737: boolean_t check_ready = FALSE; ! 1738: ! 1739: /* ! 1740: * If a copy is already in progress, wait and retry. ! 1741: * ! 1742: * XXX ! 1743: * Consider making this call interruptable, as Mike ! 1744: * intended it to be. ! 1745: * ! 1746: * XXXO ! 1747: * Need a counter or version or something to allow ! 1748: * us to use the copy that the currently requesting ! 1749: * thread is obtaining -- is it worth adding to the ! 1750: * vm object structure? Depends how common this case it. ! 1751: */ ! 1752: copy_call_count++; ! 1753: while (vm_object_wanted(src_object, VM_OBJECT_EVENT_COPY_CALL)) { ! 1754: vm_object_wait(src_object, VM_OBJECT_EVENT_COPY_CALL, ! 1755: THREAD_UNINT); ! 1756: vm_object_lock(src_object); ! 1757: copy_call_restart_count++; ! 1758: } ! 1759: ! 1760: /* ! 1761: * Indicate (for the benefit of memory_object_create_copy) ! 1762: * that we want a copy for src_object. (Note that we cannot ! 1763: * do a real assert_wait before calling memory_object_copy, ! 1764: * so we simply set the flag.) ! 1765: */ ! 1766: ! 1767: vm_object_set_wanted(src_object, VM_OBJECT_EVENT_COPY_CALL); ! 1768: vm_object_unlock(src_object); ! 1769: ! 1770: /* ! 1771: * Ask the memory manager to give us a memory object ! 1772: * which represents a copy of the src object. ! 1773: * The memory manager may give us a memory object ! 1774: * which we already have, or it may give us a ! 1775: * new memory object. This memory object will arrive ! 1776: * via memory_object_create_copy. ! 1777: */ ! 1778: ! 1779: kr = KERN_FAILURE; /* XXX need to change memory_object.defs */ ! 1780: if (kr != KERN_SUCCESS) { ! 1781: return kr; ! 1782: } ! 1783: ! 1784: /* ! 1785: * Wait for the copy to arrive. ! 1786: */ ! 1787: vm_object_lock(src_object); ! 1788: while (vm_object_wanted(src_object, VM_OBJECT_EVENT_COPY_CALL)) { ! 1789: vm_object_wait(src_object, VM_OBJECT_EVENT_COPY_CALL, ! 1790: THREAD_UNINT); ! 1791: vm_object_lock(src_object); ! 1792: copy_call_sleep_count++; ! 1793: } ! 1794: Retry: ! 1795: assert(src_object->copy != VM_OBJECT_NULL); ! 1796: copy = src_object->copy; ! 1797: if (!vm_object_lock_try(copy)) { ! 1798: vm_object_unlock(src_object); ! 1799: mutex_pause(); /* wait a bit */ ! 1800: vm_object_lock(src_object); ! 1801: goto Retry; ! 1802: } ! 1803: if (copy->size < src_offset+size) ! 1804: copy->size = src_offset+size; ! 1805: ! 1806: if (!copy->pager_ready) ! 1807: check_ready = TRUE; ! 1808: ! 1809: /* ! 1810: * Return the copy. ! 1811: */ ! 1812: *_result_object = copy; ! 1813: vm_object_unlock(copy); ! 1814: vm_object_unlock(src_object); ! 1815: ! 1816: /* Wait for the copy to be ready. */ ! 1817: if (check_ready == TRUE) { ! 1818: vm_object_lock(copy); ! 1819: while (!copy->pager_ready) { ! 1820: vm_object_wait(copy, VM_OBJECT_EVENT_PAGER_READY, ! 1821: FALSE); ! 1822: vm_object_lock(copy); ! 1823: } ! 1824: vm_object_unlock(copy); ! 1825: } ! 1826: ! 1827: return KERN_SUCCESS; ! 1828: } ! 1829: ! 1830: int copy_delayed_lock_collisions = 0; ! 1831: int copy_delayed_max_collisions = 0; ! 1832: int copy_delayed_lock_contention = 0; ! 1833: int copy_delayed_protect_iterate = 0; ! 1834: int copy_delayed_protect_lookup = 0; ! 1835: int copy_delayed_protect_lookup_wait = 0; ! 1836: ! 1837: /* ! 1838: * Routine: vm_object_copy_delayed [internal] ! 1839: * ! 1840: * Description: ! 1841: * Copy the specified virtual memory object, using ! 1842: * the asymmetric copy-on-write algorithm. ! 1843: * ! 1844: * In/out conditions: ! 1845: * The object must be unlocked on entry. ! 1846: * ! 1847: * This routine will not block waiting for user-generated ! 1848: * events. It is not interruptible. ! 1849: */ ! 1850: vm_object_t ! 1851: vm_object_copy_delayed( ! 1852: vm_object_t src_object, ! 1853: vm_offset_t src_offset, ! 1854: vm_size_t size) ! 1855: { ! 1856: vm_object_t new_copy = VM_OBJECT_NULL; ! 1857: vm_object_t old_copy; ! 1858: vm_page_t p; ! 1859: vm_size_t copy_size; ! 1860: ! 1861: int collisions = 0; ! 1862: /* ! 1863: * The user-level memory manager wants to see all of the changes ! 1864: * to this object, but it has promised not to make any changes on ! 1865: * its own. ! 1866: * ! 1867: * Perform an asymmetric copy-on-write, as follows: ! 1868: * Create a new object, called a "copy object" to hold ! 1869: * pages modified by the new mapping (i.e., the copy, ! 1870: * not the original mapping). ! 1871: * Record the original object as the backing object for ! 1872: * the copy object. If the original mapping does not ! 1873: * change a page, it may be used read-only by the copy. ! 1874: * Record the copy object in the original object. ! 1875: * When the original mapping causes a page to be modified, ! 1876: * it must be copied to a new page that is "pushed" to ! 1877: * the copy object. ! 1878: * Mark the new mapping (the copy object) copy-on-write. ! 1879: * This makes the copy object itself read-only, allowing ! 1880: * it to be reused if the original mapping makes no ! 1881: * changes, and simplifying the synchronization required ! 1882: * in the "push" operation described above. ! 1883: * ! 1884: * The copy-on-write is said to be assymetric because the original ! 1885: * object is *not* marked copy-on-write. A copied page is pushed ! 1886: * to the copy object, regardless which party attempted to modify ! 1887: * the page. ! 1888: * ! 1889: * Repeated asymmetric copy operations may be done. If the ! 1890: * original object has not been changed since the last copy, its ! 1891: * copy object can be reused. Otherwise, a new copy object can be ! 1892: * inserted between the original object and its previous copy ! 1893: * object. Since any copy object is read-only, this cannot affect ! 1894: * affect the contents of the previous copy object. ! 1895: * ! 1896: * Note that a copy object is higher in the object tree than the ! 1897: * original object; therefore, use of the copy object recorded in ! 1898: * the original object must be done carefully, to avoid deadlock. ! 1899: */ ! 1900: ! 1901: Retry: ! 1902: vm_object_lock(src_object); ! 1903: ! 1904: /* ! 1905: * See whether we can reuse the result of a previous ! 1906: * copy operation. ! 1907: */ ! 1908: ! 1909: old_copy = src_object->copy; ! 1910: if (old_copy != VM_OBJECT_NULL) { ! 1911: /* ! 1912: * Try to get the locks (out of order) ! 1913: */ ! 1914: if (!vm_object_lock_try(old_copy)) { ! 1915: vm_object_unlock(src_object); ! 1916: mutex_pause(); ! 1917: ! 1918: /* Heisenberg Rules */ ! 1919: copy_delayed_lock_collisions++; ! 1920: if (collisions++ == 0) ! 1921: copy_delayed_lock_contention++; ! 1922: ! 1923: if (collisions > copy_delayed_max_collisions) ! 1924: copy_delayed_max_collisions = collisions; ! 1925: ! 1926: goto Retry; ! 1927: } ! 1928: ! 1929: /* ! 1930: * Determine whether the old copy object has ! 1931: * been modified. ! 1932: */ ! 1933: ! 1934: if (old_copy->resident_page_count == 0 && ! 1935: !old_copy->pager_created) { ! 1936: /* ! 1937: * It has not been modified. ! 1938: * ! 1939: * Return another reference to ! 1940: * the existing copy-object. ! 1941: */ ! 1942: assert(old_copy->ref_count > 0); ! 1943: old_copy->ref_count++; ! 1944: ! 1945: if (old_copy->size < src_offset+size) ! 1946: old_copy->size = src_offset+size; ! 1947: ! 1948: #if TASK_SWAPPER ! 1949: /* ! 1950: * We have to reproduce some of the code from ! 1951: * vm_object_res_reference because we've taken ! 1952: * the locks out of order here, and deadlock ! 1953: * would result if we simply called that function. ! 1954: */ ! 1955: if (++old_copy->res_count == 1) { ! 1956: assert(old_copy->shadow == src_object); ! 1957: vm_object_res_reference(src_object); ! 1958: } ! 1959: #endif /* TASK_SWAPPER */ ! 1960: ! 1961: vm_object_unlock(old_copy); ! 1962: vm_object_unlock(src_object); ! 1963: ! 1964: if (new_copy != VM_OBJECT_NULL) { ! 1965: vm_object_unlock(new_copy); ! 1966: vm_object_deallocate(new_copy); ! 1967: } ! 1968: ! 1969: return(old_copy); ! 1970: } ! 1971: if (new_copy == VM_OBJECT_NULL) { ! 1972: vm_object_unlock(old_copy); ! 1973: vm_object_unlock(src_object); ! 1974: new_copy = vm_object_allocate(src_offset + size); ! 1975: vm_object_lock(new_copy); ! 1976: goto Retry; ! 1977: } ! 1978: ! 1979: /* ! 1980: * Adjust the size argument so that the newly-created ! 1981: * copy object will be large enough to back either the ! 1982: * new old copy object or the new mapping. ! 1983: */ ! 1984: if (old_copy->size > src_offset+size) ! 1985: size = old_copy->size - src_offset; ! 1986: ! 1987: /* ! 1988: * The copy-object is always made large enough to ! 1989: * completely shadow the original object, since ! 1990: * it may have several users who want to shadow ! 1991: * the original object at different points. ! 1992: */ ! 1993: ! 1994: assert((old_copy->shadow == src_object) && ! 1995: (old_copy->shadow_offset == (vm_offset_t) 0)); ! 1996: ! 1997: /* ! 1998: * Make the old copy-object shadow the new one. ! 1999: * It will receive no more pages from the original ! 2000: * object. ! 2001: */ ! 2002: ! 2003: src_object->ref_count--; /* remove ref. from old_copy */ ! 2004: assert(src_object->ref_count > 0); ! 2005: old_copy->shadow = new_copy; ! 2006: assert(new_copy->ref_count > 0); ! 2007: new_copy->ref_count++; /* for old_copy->shadow ref. */ ! 2008: ! 2009: #if TASK_SWAPPER ! 2010: if (old_copy->res_count) { ! 2011: VM_OBJ_RES_INCR(new_copy); ! 2012: VM_OBJ_RES_DECR(src_object); ! 2013: } ! 2014: #endif ! 2015: ! 2016: vm_object_unlock(old_copy); /* done with old_copy */ ! 2017: } else if (new_copy == VM_OBJECT_NULL) { ! 2018: vm_object_unlock(src_object); ! 2019: new_copy = vm_object_allocate(src_offset + size); ! 2020: vm_object_lock(new_copy); ! 2021: goto Retry; ! 2022: } ! 2023: ! 2024: /* ! 2025: * Readjust the copy-object size if necessary. ! 2026: */ ! 2027: copy_size = new_copy->size; ! 2028: if (copy_size < src_offset+size) { ! 2029: copy_size = src_offset+size; ! 2030: new_copy->size = copy_size; ! 2031: } ! 2032: ! 2033: /* ! 2034: * Point the new copy at the existing object. ! 2035: */ ! 2036: ! 2037: new_copy->shadow = src_object; ! 2038: new_copy->shadow_offset = 0; ! 2039: new_copy->shadowed = TRUE; /* caller must set needs_copy */ ! 2040: assert(src_object->ref_count > 0); ! 2041: src_object->ref_count++; ! 2042: VM_OBJ_RES_INCR(src_object); ! 2043: src_object->copy = new_copy; ! 2044: vm_object_unlock(new_copy); ! 2045: ! 2046: /* ! 2047: * Mark all (current) pages of the existing object copy-on-write. ! 2048: * This object may have a shadow chain below it, but ! 2049: * those pages will already be marked copy-on-write. ! 2050: */ ! 2051: ! 2052: vm_object_paging_wait(src_object, THREAD_UNINT); ! 2053: copy_delayed_protect_iterate++; ! 2054: queue_iterate(&src_object->memq, p, vm_page_t, listq) { ! 2055: if (!p->fictitious) ! 2056: pmap_page_protect(p->phys_addr, ! 2057: (VM_PROT_ALL & ~VM_PROT_WRITE & ! 2058: ~p->page_lock)); ! 2059: } ! 2060: vm_object_unlock(src_object); ! 2061: XPR(XPR_VM_OBJECT, ! 2062: "vm_object_copy_delayed: used copy object %X for source %X\n", ! 2063: (integer_t)new_copy, (integer_t)src_object, 0, 0, 0); ! 2064: ! 2065: return(new_copy); ! 2066: } ! 2067: ! 2068: /* ! 2069: * Routine: vm_object_copy_strategically ! 2070: * ! 2071: * Purpose: ! 2072: * Perform a copy according to the source object's ! 2073: * declared strategy. This operation may block, ! 2074: * and may be interrupted. ! 2075: */ ! 2076: kern_return_t ! 2077: vm_object_copy_strategically( ! 2078: register vm_object_t src_object, ! 2079: vm_offset_t src_offset, ! 2080: vm_size_t size, ! 2081: vm_object_t *dst_object, /* OUT */ ! 2082: vm_offset_t *dst_offset, /* OUT */ ! 2083: boolean_t *dst_needs_copy) /* OUT */ ! 2084: { ! 2085: boolean_t result; ! 2086: boolean_t interruptible = THREAD_ABORTSAFE; /* XXX */ ! 2087: memory_object_copy_strategy_t copy_strategy; ! 2088: ! 2089: assert(src_object != VM_OBJECT_NULL); ! 2090: ! 2091: vm_object_lock(src_object); ! 2092: ! 2093: /* ! 2094: * The copy strategy is only valid if the memory manager ! 2095: * is "ready". Internal objects are always ready. ! 2096: */ ! 2097: ! 2098: while (!src_object->internal && !src_object->pager_ready) { ! 2099: ! 2100: vm_object_wait( src_object, ! 2101: VM_OBJECT_EVENT_PAGER_READY, ! 2102: interruptible); ! 2103: if (interruptible && ! 2104: (current_thread()->wait_result != THREAD_AWAKENED)) { ! 2105: *dst_object = VM_OBJECT_NULL; ! 2106: *dst_offset = 0; ! 2107: *dst_needs_copy = FALSE; ! 2108: return(MACH_SEND_INTERRUPTED); ! 2109: } ! 2110: vm_object_lock(src_object); ! 2111: } ! 2112: ! 2113: copy_strategy = src_object->copy_strategy; ! 2114: ! 2115: /* ! 2116: * Use the appropriate copy strategy. ! 2117: */ ! 2118: ! 2119: switch (copy_strategy) { ! 2120: case MEMORY_OBJECT_COPY_NONE: ! 2121: result = vm_object_copy_slowly(src_object, src_offset, size, ! 2122: interruptible, dst_object); ! 2123: if (result == KERN_SUCCESS) { ! 2124: *dst_offset = 0; ! 2125: *dst_needs_copy = FALSE; ! 2126: } ! 2127: break; ! 2128: ! 2129: case MEMORY_OBJECT_COPY_CALL: ! 2130: result = vm_object_copy_call(src_object, src_offset, size, ! 2131: dst_object); ! 2132: if (result == KERN_SUCCESS) { ! 2133: *dst_offset = src_offset; ! 2134: *dst_needs_copy = TRUE; ! 2135: } ! 2136: break; ! 2137: ! 2138: case MEMORY_OBJECT_COPY_DELAY: ! 2139: vm_object_unlock(src_object); ! 2140: *dst_object = vm_object_copy_delayed(src_object, ! 2141: src_offset, size); ! 2142: *dst_offset = src_offset; ! 2143: *dst_needs_copy = TRUE; ! 2144: result = KERN_SUCCESS; ! 2145: break; ! 2146: ! 2147: case MEMORY_OBJECT_COPY_SYMMETRIC: ! 2148: XPR(XPR_VM_OBJECT, "v_o_c_strategically obj 0x%x off 0x%x size 0x%x\n",(natural_t)src_object, src_offset, size, 0, 0); ! 2149: vm_object_unlock(src_object); ! 2150: result = KERN_MEMORY_RESTART_COPY; ! 2151: break; ! 2152: ! 2153: default: ! 2154: panic("copy_strategically: bad strategy"); ! 2155: result = KERN_INVALID_ARGUMENT; ! 2156: } ! 2157: return(result); ! 2158: } ! 2159: ! 2160: /* ! 2161: * vm_object_shadow: ! 2162: * ! 2163: * Create a new object which is backed by the ! 2164: * specified existing object range. The source ! 2165: * object reference is deallocated. ! 2166: * ! 2167: * The new object and offset into that object ! 2168: * are returned in the source parameters. ! 2169: */ ! 2170: boolean_t vm_object_shadow_check = FALSE; ! 2171: ! 2172: boolean_t ! 2173: vm_object_shadow( ! 2174: vm_object_t *object, /* IN/OUT */ ! 2175: vm_offset_t *offset, /* IN/OUT */ ! 2176: vm_size_t length) ! 2177: { ! 2178: register vm_object_t source; ! 2179: register vm_object_t result; ! 2180: ! 2181: source = *object; ! 2182: assert(source->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC); ! 2183: ! 2184: /* ! 2185: * Determine if we really need a shadow. ! 2186: */ ! 2187: ! 2188: if (vm_object_shadow_check && source->ref_count == 1 && ! 2189: (source->shadow == VM_OBJECT_NULL || ! 2190: source->shadow->copy == VM_OBJECT_NULL)) ! 2191: { ! 2192: source->shadowed = FALSE; ! 2193: return FALSE; ! 2194: } ! 2195: ! 2196: /* ! 2197: * Allocate a new object with the given length ! 2198: */ ! 2199: ! 2200: if ((result = vm_object_allocate(length)) == VM_OBJECT_NULL) ! 2201: panic("vm_object_shadow: no object for shadowing"); ! 2202: ! 2203: /* ! 2204: * The new object shadows the source object, adding ! 2205: * a reference to it. Our caller changes his reference ! 2206: * to point to the new object, removing a reference to ! 2207: * the source object. Net result: no change of reference ! 2208: * count. ! 2209: */ ! 2210: result->shadow = source; ! 2211: ! 2212: /* ! 2213: * Store the offset into the source object, ! 2214: * and fix up the offset into the new object. ! 2215: */ ! 2216: ! 2217: result->shadow_offset = *offset; ! 2218: ! 2219: /* ! 2220: * Return the new things ! 2221: */ ! 2222: ! 2223: *offset = 0; ! 2224: *object = result; ! 2225: return TRUE; ! 2226: } ! 2227: ! 2228: /* ! 2229: * The relationship between vm_object structures and ! 2230: * the memory_object ports requires careful synchronization. ! 2231: * ! 2232: * All associations are created by vm_object_enter. All three ! 2233: * port fields are filled in, as follows: ! 2234: * pager: the memory_object port itself, supplied by ! 2235: * the user requesting a mapping (or the kernel, ! 2236: * when initializing internal objects); the ! 2237: * kernel simulates holding send rights by keeping ! 2238: * a port reference; ! 2239: * pager_request: ! 2240: * the memory object control port, ! 2241: * created by the kernel; the kernel holds ! 2242: * receive (and ownership) rights to this ! 2243: * port, but no other references. ! 2244: * All of the ports are referenced by their global names. ! 2245: * ! 2246: * When initialization is complete, the "initialized" field ! 2247: * is asserted. Other mappings using a particular memory object, ! 2248: * and any references to the vm_object gained through the ! 2249: * port association must wait for this initialization to occur. ! 2250: * ! 2251: * In order to allow the memory manager to set attributes before ! 2252: * requests (notably virtual copy operations, but also data or ! 2253: * unlock requests) are made, a "ready" attribute is made available. ! 2254: * Only the memory manager may affect the value of this attribute. ! 2255: * Its value does not affect critical kernel functions, such as ! 2256: * internal object initialization or destruction. [Furthermore, ! 2257: * memory objects created by the kernel are assumed to be ready ! 2258: * immediately; the default memory manager need not explicitly ! 2259: * set the "ready" attribute.] ! 2260: * ! 2261: * [Both the "initialized" and "ready" attribute wait conditions ! 2262: * use the "pager" field as the wait event.] ! 2263: * ! 2264: * The port associations can be broken down by any of the ! 2265: * following routines: ! 2266: * vm_object_terminate: ! 2267: * No references to the vm_object remain, and ! 2268: * the object cannot (or will not) be cached. ! 2269: * This is the normal case, and is done even ! 2270: * though one of the other cases has already been ! 2271: * done. ! 2272: * vm_object_destroy: ! 2273: * The memory_object port has been destroyed, ! 2274: * meaning that the kernel cannot flush dirty ! 2275: * pages or request new data or unlock existing ! 2276: * data. ! 2277: * memory_object_destroy: ! 2278: * The memory manager has requested that the ! 2279: * kernel relinquish rights to the memory object ! 2280: * port. [The memory manager may not want to ! 2281: * destroy the port, but may wish to refuse or ! 2282: * tear down existing memory mappings.] ! 2283: * Each routine that breaks an association must break all of ! 2284: * them at once. At some later time, that routine must clear ! 2285: * the vm_object port fields and release the port rights. ! 2286: * [Furthermore, each routine must cope with the simultaneous ! 2287: * or previous operations of the others.] ! 2288: * ! 2289: * In addition to the lock on the object, the vm_object_cache_lock ! 2290: * governs the port associations. References gained through the ! 2291: * port association require use of the cache lock. ! 2292: * ! 2293: * Because the port fields may be cleared spontaneously, they ! 2294: * cannot be used to determine whether a memory object has ! 2295: * ever been associated with a particular vm_object. [This ! 2296: * knowledge is important to the shadow object mechanism.] ! 2297: * For this reason, an additional "created" attribute is ! 2298: * provided. ! 2299: * ! 2300: * During various paging operations, the port values found in the ! 2301: * vm_object must be valid. To prevent these port rights from being ! 2302: * released, and to prevent the port associations from changing ! 2303: * (other than being removed, i.e., made null), routines may use ! 2304: * the vm_object_paging_begin/end routines [actually, macros]. ! 2305: * The implementation uses the "paging_in_progress" and "wanted" fields. ! 2306: * [Operations that alter the validity of the port values include the ! 2307: * termination routines and vm_object_collapse.] ! 2308: */ ! 2309: ! 2310: #define IKOT_PAGER_LOOKUP_TYPE IKOT_PAGING_REQUEST ! 2311: ! 2312: vm_object_t ! 2313: vm_object_lookup( ! 2314: ipc_port_t port) ! 2315: { ! 2316: vm_object_t object; ! 2317: ! 2318: start_over: ! 2319: object = VM_OBJECT_NULL; ! 2320: ! 2321: if (IP_VALID(port)) { ! 2322: vm_object_cache_lock(); ! 2323: ip_lock(port); ! 2324: if (ip_active(port) && ! 2325: (ip_kotype(port) == IKOT_PAGER_LOOKUP_TYPE)) { ! 2326: object = (vm_object_t) port->ip_kobject; ! 2327: if (!vm_object_lock_try(object)) { ! 2328: /* ! 2329: * failed to acquire object lock. Drop the ! 2330: * other two locks and wait for it, then go ! 2331: * back and start over in case the port ! 2332: * associations changed in the interim. ! 2333: */ ! 2334: ip_unlock(port); ! 2335: vm_object_cache_unlock(); ! 2336: vm_object_lock(object); ! 2337: vm_object_unlock(object); ! 2338: goto start_over; ! 2339: } ! 2340: ! 2341: assert(object->alive); ! 2342: ! 2343: if (object->ref_count == 0) { ! 2344: queue_remove(&vm_object_cached_list, object, ! 2345: vm_object_t, cached_list); ! 2346: vm_object_cached_count--; ! 2347: XPR(XPR_VM_OBJECT_CACHE, ! 2348: "vm_object_lookup: removing %X, head (%X, %X)\n", ! 2349: (integer_t)object, ! 2350: (integer_t)vm_object_cached_list.next, ! 2351: (integer_t)vm_object_cached_list.prev, 0,0); ! 2352: } ! 2353: ! 2354: object->ref_count++; ! 2355: vm_object_res_reference(object); ! 2356: vm_object_unlock(object); ! 2357: } ! 2358: ip_unlock(port); ! 2359: vm_object_cache_unlock(); ! 2360: } ! 2361: ! 2362: return object; ! 2363: } ! 2364: ! 2365: ! 2366: ! 2367: void ! 2368: vm_object_destroy( ! 2369: ipc_port_t pager) ! 2370: { ! 2371: vm_object_t object; ! 2372: vm_object_hash_entry_t entry; ! 2373: pager_request_t old_pager_request; ! 2374: ! 2375: /* ! 2376: * Perform essentially the same operations as in vm_object_lookup, ! 2377: * except that this time we look up based on the memory_object ! 2378: * port, not the control port. ! 2379: */ ! 2380: vm_object_cache_lock(); ! 2381: entry = vm_object_hash_lookup(pager, FALSE); ! 2382: if (entry == VM_OBJECT_HASH_ENTRY_NULL || ! 2383: entry->object == VM_OBJECT_NULL) { ! 2384: vm_object_cache_unlock(); ! 2385: return; ! 2386: } ! 2387: ! 2388: object = entry->object; ! 2389: entry->object = VM_OBJECT_NULL; ! 2390: ! 2391: vm_object_lock(object); ! 2392: if (object->ref_count == 0) { ! 2393: XPR(XPR_VM_OBJECT_CACHE, ! 2394: "vm_object_destroy: removing %x from cache, head (%x, %x)\n", ! 2395: (integer_t)object, ! 2396: (integer_t)vm_object_cached_list.next, ! 2397: (integer_t)vm_object_cached_list.prev, 0,0); ! 2398: ! 2399: queue_remove(&vm_object_cached_list, object, ! 2400: vm_object_t, cached_list); ! 2401: vm_object_cached_count--; ! 2402: } ! 2403: object->ref_count++; ! 2404: vm_object_res_reference(object); ! 2405: ! 2406: object->can_persist = FALSE; ! 2407: ! 2408: assert(object->pager == pager); ! 2409: ! 2410: /* ! 2411: * Remove the port associations. ! 2412: * ! 2413: * Note that the memory_object itself is dead, so ! 2414: * we don't bother with it. ! 2415: */ ! 2416: ! 2417: object->pager = IP_NULL; ! 2418: vm_object_remove(object); ! 2419: ! 2420: old_pager_request = object->pager_request; ! 2421: ! 2422: object->pager_request = PAGER_REQUEST_NULL; ! 2423: ! 2424: vm_object_unlock(object); ! 2425: vm_object_cache_unlock(); ! 2426: ! 2427: vm_object_pager_wakeup(pager); ! 2428: ! 2429: /* ! 2430: * Clean up the port references. Note that there's no ! 2431: * point in trying the memory_object_terminate call ! 2432: * because the memory_object itself is dead. ! 2433: */ ! 2434: ! 2435: ipc_port_release_send(pager); ! 2436: ! 2437: if ((ipc_port_t)old_pager_request != IP_NULL) ! 2438: ipc_port_dealloc_kernel((ipc_port_t)old_pager_request); ! 2439: ! 2440: /* ! 2441: * Restart pending page requests ! 2442: */ ! 2443: vm_object_lock(object); ! 2444: ! 2445: vm_object_abort_activity(object); ! 2446: ! 2447: vm_object_unlock(object); ! 2448: ! 2449: /* ! 2450: * Lose the object reference. ! 2451: */ ! 2452: ! 2453: vm_object_deallocate(object); ! 2454: } ! 2455: ! 2456: /* ! 2457: * Routine: vm_object_enter ! 2458: * Purpose: ! 2459: * Find a VM object corresponding to the given ! 2460: * pager; if no such object exists, create one, ! 2461: * and initialize the pager. ! 2462: */ ! 2463: vm_object_t ! 2464: vm_object_enter( ! 2465: ipc_port_t pager, ! 2466: vm_size_t size, ! 2467: boolean_t internal, ! 2468: boolean_t init) ! 2469: { ! 2470: register vm_object_t object; ! 2471: vm_object_t new_object; ! 2472: boolean_t must_init; ! 2473: ipc_port_t pager_request; ! 2474: vm_object_hash_entry_t entry, new_entry; ! 2475: #ifdef MACH_BSD ! 2476: kern_return_t vnode_pager_init( ipc_port_t, ipc_port_t, vm_size_t); ! 2477: #endif ! 2478: ! 2479: if (!IP_VALID(pager)) ! 2480: return(vm_object_allocate(size)); ! 2481: ! 2482: new_object = VM_OBJECT_NULL; ! 2483: new_entry = VM_OBJECT_HASH_ENTRY_NULL; ! 2484: must_init = init; ! 2485: ! 2486: /* ! 2487: * Look for an object associated with this port. ! 2488: */ ! 2489: ! 2490: restart: ! 2491: vm_object_cache_lock(); ! 2492: for (;;) { ! 2493: entry = vm_object_hash_lookup(pager, FALSE); ! 2494: ! 2495: /* ! 2496: * If a previous object is being terminated, ! 2497: * we must wait for the termination message ! 2498: * to be queued. ! 2499: * ! 2500: * We set kobject to a non-null value to let the ! 2501: * terminator know that someone is waiting. ! 2502: * Among the possibilities is that the port ! 2503: * could die while we're waiting. Must restart ! 2504: * instead of continuing the loop. ! 2505: */ ! 2506: ! 2507: if (entry != VM_OBJECT_HASH_ENTRY_NULL) { ! 2508: if (entry->object != VM_OBJECT_NULL) ! 2509: break; ! 2510: ! 2511: entry->waiting = TRUE; ! 2512: assert_wait((event_t) pager, THREAD_UNINT); ! 2513: vm_object_cache_unlock(); ! 2514: thread_block((void (*)(void))0); ! 2515: goto restart; ! 2516: } ! 2517: ! 2518: /* ! 2519: * We must unlock to create a new object; ! 2520: * if we do so, we must try the lookup again. ! 2521: */ ! 2522: ! 2523: if (new_object == VM_OBJECT_NULL) { ! 2524: vm_object_cache_unlock(); ! 2525: assert(new_entry == VM_OBJECT_HASH_ENTRY_NULL); ! 2526: new_entry = vm_object_hash_entry_alloc(pager); ! 2527: new_object = vm_object_allocate(size); ! 2528: vm_object_cache_lock(); ! 2529: } else { ! 2530: /* ! 2531: * Lookup failed twice, and we have something ! 2532: * to insert; set the object. ! 2533: */ ! 2534: ! 2535: if (entry == VM_OBJECT_HASH_ENTRY_NULL) { ! 2536: vm_object_hash_insert(new_entry); ! 2537: entry = new_entry; ! 2538: new_entry = VM_OBJECT_HASH_ENTRY_NULL; ! 2539: } ! 2540: ! 2541: entry->object = new_object; ! 2542: new_object = VM_OBJECT_NULL; ! 2543: must_init = TRUE; ! 2544: } ! 2545: } ! 2546: ! 2547: object = entry->object; ! 2548: assert(object != VM_OBJECT_NULL); ! 2549: ! 2550: if (!must_init) { ! 2551: vm_object_lock(object); ! 2552: assert(object->pager_created); ! 2553: assert(!internal || object->internal); ! 2554: if (object->ref_count == 0) { ! 2555: XPR(XPR_VM_OBJECT_CACHE, ! 2556: "vm_object_enter: removing %x from cache, head (%x, %x)\n", ! 2557: (integer_t)object, ! 2558: (integer_t)vm_object_cached_list.next, ! 2559: (integer_t)vm_object_cached_list.prev, 0,0); ! 2560: queue_remove(&vm_object_cached_list, object, ! 2561: vm_object_t, cached_list); ! 2562: vm_object_cached_count--; ! 2563: } ! 2564: object->ref_count++; ! 2565: vm_object_res_reference(object); ! 2566: vm_object_unlock(object); ! 2567: ! 2568: VM_STAT(hits++); ! 2569: } ! 2570: assert(object->ref_count > 0); ! 2571: ! 2572: VM_STAT(lookups++); ! 2573: ! 2574: vm_object_cache_unlock(); ! 2575: ! 2576: XPR(XPR_VM_OBJECT, ! 2577: "vm_o_enter: pager 0x%x obj 0x%x must_init %d\n", ! 2578: (integer_t)pager, (integer_t)object, must_init, 0, 0); ! 2579: ! 2580: /* ! 2581: * If we raced to create a vm_object but lost, let's ! 2582: * throw away ours. ! 2583: */ ! 2584: ! 2585: if (new_object != VM_OBJECT_NULL) ! 2586: vm_object_deallocate(new_object); ! 2587: ! 2588: if (new_entry != VM_OBJECT_HASH_ENTRY_NULL) ! 2589: vm_object_hash_entry_free(new_entry); ! 2590: ! 2591: if (must_init) { ! 2592: ! 2593: /* ! 2594: * Allocate request port. ! 2595: */ ! 2596: ! 2597: pager_request = ipc_port_alloc_kernel(); ! 2598: assert (pager_request != IP_NULL); ! 2599: ipc_kobject_set(pager_request, (ipc_kobject_t) object, ! 2600: IKOT_PAGING_REQUEST); ! 2601: ! 2602: vm_object_lock(object); ! 2603: ! 2604: /* ! 2605: * Copy the naked send right we were given. ! 2606: */ ! 2607: ! 2608: pager = ipc_port_copy_send(pager); ! 2609: if (!IP_VALID(pager)) ! 2610: panic("vm_object_enter: port died"); /* XXX */ ! 2611: ! 2612: object->pager_created = TRUE; ! 2613: object->pager = pager; ! 2614: object->internal = internal; ! 2615: object->pager_trusted = internal; ! 2616: if (!internal) { ! 2617: /* copy strategy invalid until set by memory manager */ ! 2618: object->copy_strategy = MEMORY_OBJECT_COPY_INVALID; ! 2619: } ! 2620: object->pager_request = pager_request; ! 2621: object->pager_ready = FALSE; ! 2622: ! 2623: vm_object_unlock(object); ! 2624: ! 2625: /* ! 2626: * Let the pager know we're using it. ! 2627: */ ! 2628: ! 2629: #ifdef MACH_BSD ! 2630: if(((rpc_subsystem_t)pager_mux_hash_lookup(pager)) == ! 2631: ((rpc_subsystem_t) &vnode_pager_workaround)) { ! 2632: (void) vnode_pager_init(pager, ! 2633: object->pager_request, ! 2634: PAGE_SIZE); ! 2635: } else { ! 2636: (void) memory_object_init(pager, ! 2637: object->pager_request, ! 2638: PAGE_SIZE); ! 2639: } ! 2640: #else ! 2641: (void) memory_object_init(pager, ! 2642: object->pager_request, ! 2643: PAGE_SIZE); ! 2644: #endif ! 2645: ! 2646: vm_object_lock(object); ! 2647: if (internal) { ! 2648: object->pager_ready = TRUE; ! 2649: vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY); ! 2650: } ! 2651: ! 2652: object->pager_initialized = TRUE; ! 2653: vm_object_wakeup(object, VM_OBJECT_EVENT_INITIALIZED); ! 2654: } else { ! 2655: vm_object_lock(object); ! 2656: } ! 2657: ! 2658: /* ! 2659: * [At this point, the object must be locked] ! 2660: */ ! 2661: ! 2662: /* ! 2663: * Wait for the work above to be done by the first ! 2664: * thread to map this object. ! 2665: */ ! 2666: ! 2667: while (!object->pager_initialized) { ! 2668: vm_object_wait( object, ! 2669: VM_OBJECT_EVENT_INITIALIZED, ! 2670: THREAD_UNINT); ! 2671: vm_object_lock(object); ! 2672: } ! 2673: vm_object_unlock(object); ! 2674: ! 2675: XPR(XPR_VM_OBJECT, ! 2676: "vm_object_enter: vm_object %x, memory_object %x, internal %d\n", ! 2677: (integer_t)object, (integer_t)object->pager, internal, 0,0); ! 2678: return(object); ! 2679: } ! 2680: ! 2681: /* ! 2682: * Routine: vm_object_pager_create ! 2683: * Purpose: ! 2684: * Create a memory object for an internal object. ! 2685: * In/out conditions: ! 2686: * The object is locked on entry and exit; ! 2687: * it may be unlocked within this call. ! 2688: * Limitations: ! 2689: * Only one thread may be performing a ! 2690: * vm_object_pager_create on an object at ! 2691: * a time. Presumably, only the pageout ! 2692: * daemon will be using this routine. ! 2693: */ ! 2694: ! 2695: void ! 2696: vm_object_pager_create( ! 2697: register vm_object_t object) ! 2698: { ! 2699: ipc_port_t pager; ! 2700: vm_object_hash_entry_t entry; ! 2701: #if MACH_PAGEMAP ! 2702: vm_size_t size; ! 2703: vm_external_map_t map; ! 2704: #endif /* MACH_PAGEMAP */ ! 2705: ! 2706: XPR(XPR_VM_OBJECT, "vm_object_pager_create, object 0x%X\n", ! 2707: (integer_t)object, 0,0,0,0); ! 2708: ! 2709: if (memory_manager_default_check() != KERN_SUCCESS) ! 2710: return; ! 2711: ! 2712: /* ! 2713: * Prevent collapse or termination by holding a paging reference ! 2714: */ ! 2715: ! 2716: vm_object_paging_begin(object); ! 2717: if (object->pager_created) { ! 2718: /* ! 2719: * Someone else got to it first... ! 2720: * wait for them to finish initializing the ports ! 2721: */ ! 2722: while (!object->pager_initialized) { ! 2723: vm_object_wait( object, ! 2724: VM_OBJECT_EVENT_INITIALIZED, ! 2725: THREAD_UNINT); ! 2726: vm_object_lock(object); ! 2727: } ! 2728: vm_object_paging_end(object); ! 2729: return; ! 2730: } ! 2731: ! 2732: /* ! 2733: * Indicate that a memory object has been assigned ! 2734: * before dropping the lock, to prevent a race. ! 2735: */ ! 2736: ! 2737: object->pager_created = TRUE; ! 2738: object->paging_offset = 0; ! 2739: ! 2740: #if MACH_PAGEMAP ! 2741: size = object->size; ! 2742: #endif /* MACH_PAGEMAP */ ! 2743: vm_object_unlock(object); ! 2744: ! 2745: #if MACH_PAGEMAP ! 2746: map = vm_external_create(size); ! 2747: vm_object_lock(object); ! 2748: assert(object->size == size); ! 2749: object->existence_map = map; ! 2750: vm_object_unlock(object); ! 2751: #endif /* MACH_PAGEMAP */ ! 2752: ! 2753: /* ! 2754: * Create the pager ports, and associate them with this object. ! 2755: * ! 2756: * We make the port association here so that vm_object_enter() ! 2757: * can look up the object to complete initializing it. No ! 2758: * user will ever map this object. ! 2759: */ ! 2760: { ! 2761: ipc_port_t DMM; ! 2762: vm_size_t cluster_size; ! 2763: ! 2764: /* acquire a naked send right for the DMM */ ! 2765: DMM = memory_manager_default_reference(&cluster_size); ! 2766: assert(cluster_size >= PAGE_SIZE); ! 2767: ! 2768: object->cluster_size = cluster_size; /* XXX ??? */ ! 2769: assert(object->temporary); ! 2770: ! 2771: /* consumes the naked send right for DMM */ ! 2772: (void) memory_object_create(DMM, &pager, object->size); ! 2773: assert(IP_VALID(pager)); ! 2774: } ! 2775: ! 2776: entry = vm_object_hash_entry_alloc(pager); ! 2777: ! 2778: vm_object_cache_lock(); ! 2779: vm_object_hash_insert(entry); ! 2780: ! 2781: entry->object = object; ! 2782: vm_object_cache_unlock(); ! 2783: ! 2784: /* ! 2785: * A naked send right was returned by ! 2786: * memory_object_create(), and it is ! 2787: * copied by vm_object_enter(). ! 2788: */ ! 2789: ! 2790: if (vm_object_enter(pager, object->size, TRUE, TRUE) != object) ! 2791: panic("vm_object_pager_create: mismatch"); ! 2792: ! 2793: /* ! 2794: * Drop the naked send right. ! 2795: */ ! 2796: ipc_port_release_send(pager); ! 2797: ! 2798: vm_object_lock(object); ! 2799: ! 2800: /* ! 2801: * Release the paging reference ! 2802: */ ! 2803: vm_object_paging_end(object); ! 2804: } ! 2805: ! 2806: /* ! 2807: * Routine: vm_object_remove ! 2808: * Purpose: ! 2809: * Eliminate the pager/object association ! 2810: * for this pager. ! 2811: * Conditions: ! 2812: * The object cache must be locked. ! 2813: */ ! 2814: void ! 2815: vm_object_remove( ! 2816: vm_object_t object) ! 2817: { ! 2818: ipc_port_t port; ! 2819: ! 2820: if ((port = object->pager) != IP_NULL) { ! 2821: vm_object_hash_entry_t entry; ! 2822: ! 2823: entry = vm_object_hash_lookup(port, FALSE); ! 2824: if (entry != VM_OBJECT_HASH_ENTRY_NULL) ! 2825: entry->object = VM_OBJECT_NULL; ! 2826: } ! 2827: ! 2828: if ((port = object->pager_request) != IP_NULL) { ! 2829: if (ip_kotype(port) == IKOT_PAGING_REQUEST) ! 2830: ipc_kobject_set(port, IKO_NULL, IKOT_NONE); ! 2831: else if (ip_kotype(port) != IKOT_NONE) ! 2832: panic("vm_object_remove: bad request port"); ! 2833: } ! 2834: } ! 2835: ! 2836: /* ! 2837: * Global variables for vm_object_collapse(): ! 2838: * ! 2839: * Counts for normal collapses and bypasses. ! 2840: * Debugging variables, to watch or disable collapse. ! 2841: */ ! 2842: long object_collapses = 0; ! 2843: long object_bypasses = 0; ! 2844: ! 2845: boolean_t vm_object_collapse_allowed = TRUE; ! 2846: boolean_t vm_object_bypass_allowed = TRUE; ! 2847: ! 2848: int vm_external_discarded; ! 2849: int vm_external_collapsed; ! 2850: /* ! 2851: * vm_object_do_collapse: ! 2852: * ! 2853: * Collapse an object with the object backing it. ! 2854: * Pages in the backing object are moved into the ! 2855: * parent, and the backing object is deallocated. ! 2856: * ! 2857: * Both objects and the cache are locked; the page ! 2858: * queues are unlocked. ! 2859: * ! 2860: */ ! 2861: void ! 2862: vm_object_do_collapse( ! 2863: vm_object_t object, ! 2864: vm_object_t backing_object) ! 2865: { ! 2866: vm_page_t p, pp; ! 2867: vm_offset_t new_offset, backing_offset; ! 2868: vm_size_t size; ! 2869: ! 2870: backing_offset = object->shadow_offset; ! 2871: size = object->size; ! 2872: ! 2873: ! 2874: /* ! 2875: * Move all in-memory pages from backing_object ! 2876: * to the parent. Pages that have been paged out ! 2877: * will be overwritten by any of the parent's ! 2878: * pages that shadow them. ! 2879: */ ! 2880: ! 2881: while (!queue_empty(&backing_object->memq)) { ! 2882: ! 2883: p = (vm_page_t) queue_first(&backing_object->memq); ! 2884: ! 2885: new_offset = (p->offset - backing_offset); ! 2886: ! 2887: assert(!p->busy || p->absent); ! 2888: ! 2889: /* ! 2890: * If the parent has a page here, or if ! 2891: * this page falls outside the parent, ! 2892: * dispose of it. ! 2893: * ! 2894: * Otherwise, move it as planned. ! 2895: */ ! 2896: ! 2897: if (p->offset < backing_offset || new_offset >= size) { ! 2898: VM_PAGE_FREE(p); ! 2899: } else { ! 2900: pp = vm_page_lookup(object, new_offset); ! 2901: if (pp == VM_PAGE_NULL) { ! 2902: ! 2903: /* ! 2904: * Parent now has no page. ! 2905: * Move the backing object's page up. ! 2906: */ ! 2907: ! 2908: vm_page_rename(p, object, new_offset); ! 2909: #if MACH_PAGEMAP ! 2910: } else if (pp->absent) { ! 2911: ! 2912: /* ! 2913: * Parent has an absent page... ! 2914: * it's not being paged in, so ! 2915: * it must really be missing from ! 2916: * the parent. ! 2917: * ! 2918: * Throw out the absent page... ! 2919: * any faults looking for that ! 2920: * page will restart with the new ! 2921: * one. ! 2922: */ ! 2923: ! 2924: VM_PAGE_FREE(pp); ! 2925: vm_page_rename(p, object, new_offset); ! 2926: #endif /* MACH_PAGEMAP */ ! 2927: } else { ! 2928: assert(! pp->absent); ! 2929: ! 2930: /* ! 2931: * Parent object has a real page. ! 2932: * Throw away the backing object's ! 2933: * page. ! 2934: */ ! 2935: VM_PAGE_FREE(p); ! 2936: } ! 2937: } ! 2938: } ! 2939: ! 2940: assert(object->pager == IP_NULL || backing_object->pager == IP_NULL); ! 2941: ! 2942: if (backing_object->pager != IP_NULL) { ! 2943: vm_object_hash_entry_t entry; ! 2944: ! 2945: /* ! 2946: * Move the pager from backing_object to object. ! 2947: * ! 2948: * XXX We're only using part of the paging space ! 2949: * for keeps now... we ought to discard the ! 2950: * unused portion. ! 2951: */ ! 2952: ! 2953: object->pager = backing_object->pager; ! 2954: entry = vm_object_hash_lookup(object->pager, FALSE); ! 2955: assert(entry != VM_OBJECT_HASH_ENTRY_NULL); ! 2956: entry->object = object; ! 2957: object->pager_created = backing_object->pager_created; ! 2958: object->pager_request = backing_object->pager_request; ! 2959: object->pager_ready = backing_object->pager_ready; ! 2960: object->pager_initialized = backing_object->pager_initialized; ! 2961: object->cluster_size = backing_object->cluster_size; ! 2962: object->paging_offset = ! 2963: backing_object->paging_offset + backing_offset; ! 2964: if (object->pager_request != IP_NULL) { ! 2965: ipc_kobject_set(object->pager_request, ! 2966: (ipc_kobject_t) object, ! 2967: IKOT_PAGING_REQUEST); ! 2968: } ! 2969: } ! 2970: ! 2971: vm_object_cache_unlock(); ! 2972: ! 2973: object->paging_offset = backing_object->paging_offset + backing_offset; ! 2974: ! 2975: #if MACH_PAGEMAP ! 2976: /* ! 2977: * If the shadow offset is 0, the use the existence map from ! 2978: * the backing object if there is one. If the shadow offset is ! 2979: * not zero, toss it. ! 2980: * ! 2981: * XXX - If the shadow offset is not 0 then a bit copy is needed ! 2982: * if the map is to be salvaged. For now, we just just toss the ! 2983: * old map, giving the collapsed object no map. This means that ! 2984: * the pager is invoked for zero fill pages. If analysis shows ! 2985: * that this happens frequently and is a performance hit, then ! 2986: * this code should be fixed to salvage the map. ! 2987: */ ! 2988: assert(object->existence_map == VM_EXTERNAL_NULL); ! 2989: if (backing_offset || (size != backing_object->size)) { ! 2990: vm_external_discarded++; ! 2991: vm_external_destroy(backing_object->existence_map, ! 2992: backing_object->size); ! 2993: } ! 2994: else { ! 2995: vm_external_collapsed++; ! 2996: object->existence_map = backing_object->existence_map; ! 2997: } ! 2998: backing_object->existence_map = VM_EXTERNAL_NULL; ! 2999: #endif /* MACH_PAGEMAP */ ! 3000: ! 3001: /* ! 3002: * Object now shadows whatever backing_object did. ! 3003: * Note that the reference to backing_object->shadow ! 3004: * moves from within backing_object to within object. ! 3005: */ ! 3006: ! 3007: object->shadow = backing_object->shadow; ! 3008: object->shadow_offset += backing_object->shadow_offset; ! 3009: assert((object->shadow == VM_OBJECT_NULL) || ! 3010: (object->shadow->copy == VM_OBJECT_NULL)); ! 3011: ! 3012: /* ! 3013: * Discard backing_object. ! 3014: * ! 3015: * Since the backing object has no pages, no ! 3016: * pager left, and no object references within it, ! 3017: * all that is necessary is to dispose of it. ! 3018: */ ! 3019: ! 3020: assert((backing_object->ref_count == 1) && ! 3021: (backing_object->resident_page_count == 0) && ! 3022: (backing_object->paging_in_progress == 0)); ! 3023: ! 3024: assert(backing_object->alive); ! 3025: backing_object->alive = FALSE; ! 3026: vm_object_unlock(backing_object); ! 3027: ! 3028: XPR(XPR_VM_OBJECT, "vm_object_collapse, collapsed 0x%X\n", ! 3029: (integer_t)backing_object, 0,0,0,0); ! 3030: ! 3031: zfree(vm_object_zone, (vm_offset_t) backing_object); ! 3032: ! 3033: object_collapses++; ! 3034: } ! 3035: ! 3036: void ! 3037: vm_object_do_bypass( ! 3038: vm_object_t object, ! 3039: vm_object_t backing_object) ! 3040: { ! 3041: /* ! 3042: * Make the parent shadow the next object ! 3043: * in the chain. ! 3044: */ ! 3045: ! 3046: #if TASK_SWAPPER ! 3047: /* ! 3048: * Do object reference in-line to ! 3049: * conditionally increment shadow's ! 3050: * residence count. If object is not ! 3051: * resident, leave residence count ! 3052: * on shadow alone. ! 3053: */ ! 3054: if (backing_object->shadow != VM_OBJECT_NULL) { ! 3055: vm_object_lock(backing_object->shadow); ! 3056: backing_object->shadow->ref_count++; ! 3057: if (object->res_count != 0) ! 3058: vm_object_res_reference(backing_object->shadow); ! 3059: vm_object_unlock(backing_object->shadow); ! 3060: } ! 3061: #else /* TASK_SWAPPER */ ! 3062: vm_object_reference(backing_object->shadow); ! 3063: #endif /* TASK_SWAPPER */ ! 3064: ! 3065: object->shadow = backing_object->shadow; ! 3066: object->shadow_offset += backing_object->shadow_offset; ! 3067: ! 3068: /* ! 3069: * Backing object might have had a copy pointer ! 3070: * to us. If it did, clear it. ! 3071: */ ! 3072: if (backing_object->copy == object) { ! 3073: backing_object->copy = VM_OBJECT_NULL; ! 3074: } ! 3075: ! 3076: /* ! 3077: * Drop the reference count on backing_object. ! 3078: #if TASK_SWAPPER ! 3079: * Since its ref_count was at least 2, it ! 3080: * will not vanish; so we don't need to call ! 3081: * vm_object_deallocate. ! 3082: * [FBDP: that doesn't seem to be true any more] ! 3083: * ! 3084: * The res_count on the backing object is ! 3085: * conditionally decremented. It's possible ! 3086: * (via vm_pageout_scan) to get here with ! 3087: * a "swapped" object, which has a 0 res_count, ! 3088: * in which case, the backing object res_count ! 3089: * is already down by one. ! 3090: #else ! 3091: * Don't call vm_object_deallocate unless ! 3092: * ref_count drops to zero. ! 3093: * ! 3094: * The ref_count can drop to zero here if the ! 3095: * backing object could be bypassed but not ! 3096: * collapsed, such as when the backing object ! 3097: * is temporary and cachable. ! 3098: #endif ! 3099: */ ! 3100: if (backing_object->ref_count > 1) { ! 3101: backing_object->ref_count--; ! 3102: #if TASK_SWAPPER ! 3103: if (object->res_count != 0) ! 3104: vm_object_res_deallocate(backing_object); ! 3105: assert(backing_object->ref_count > 0); ! 3106: #endif /* TASK_SWAPPER */ ! 3107: vm_object_unlock(backing_object); ! 3108: } else { ! 3109: ! 3110: /* ! 3111: * Drop locks so that we can deallocate ! 3112: * the backing object. ! 3113: */ ! 3114: ! 3115: #if TASK_SWAPPER ! 3116: if (object->res_count == 0) { ! 3117: /* XXX get a reference for the deallocate below */ ! 3118: vm_object_res_reference(backing_object); ! 3119: } ! 3120: #endif /* TASK_SWAPPER */ ! 3121: vm_object_unlock(object); ! 3122: vm_object_unlock(backing_object); ! 3123: vm_object_deallocate(backing_object); ! 3124: ! 3125: /* ! 3126: * Relock object. We don't have to reverify ! 3127: * its state since vm_object_collapse will ! 3128: * do that for us as it starts at the ! 3129: * top of its loop. ! 3130: */ ! 3131: ! 3132: vm_object_lock(object); ! 3133: } ! 3134: ! 3135: object_bypasses++; ! 3136: } ! 3137: ! 3138: /* ! 3139: * vm_object_collapse: ! 3140: * ! 3141: * Perform an object collapse or an object bypass if appropriate. ! 3142: * The real work of collapsing and bypassing is performed in ! 3143: * the routines vm_object_do_collapse and vm_object_do_bypass. ! 3144: * ! 3145: * Requires that the object be locked and the page queues be unlocked. ! 3146: * ! 3147: */ ! 3148: void ! 3149: vm_object_collapse( ! 3150: register vm_object_t object) ! 3151: { ! 3152: register vm_object_t backing_object; ! 3153: register vm_offset_t backing_offset; ! 3154: register vm_size_t size; ! 3155: register vm_offset_t new_offset; ! 3156: register vm_page_t p; ! 3157: ! 3158: if (! vm_object_collapse_allowed && ! vm_object_bypass_allowed) { ! 3159: return; ! 3160: } ! 3161: ! 3162: XPR(XPR_VM_OBJECT, "vm_object_collapse, obj 0x%X\n", ! 3163: (integer_t)object, 0,0,0,0); ! 3164: ! 3165: while (TRUE) { ! 3166: /* ! 3167: * Verify that the conditions are right for either ! 3168: * collapse or bypass: ! 3169: * ! 3170: * The object exists and no pages in it are currently ! 3171: * being paged out, and ! 3172: */ ! 3173: if (object == VM_OBJECT_NULL || ! 3174: object->paging_in_progress != 0 || ! 3175: object->absent_count != 0) ! 3176: return; ! 3177: ! 3178: /* ! 3179: * There is a backing object, and ! 3180: */ ! 3181: ! 3182: if ((backing_object = object->shadow) == VM_OBJECT_NULL) ! 3183: return; ! 3184: ! 3185: vm_object_lock(backing_object); ! 3186: ! 3187: /* ! 3188: * ... ! 3189: * The backing object is not read_only, ! 3190: * and no pages in the backing object are ! 3191: * currently being paged out. ! 3192: * The backing object is internal. ! 3193: * ! 3194: */ ! 3195: ! 3196: if (!backing_object->internal || ! 3197: backing_object->paging_in_progress != 0) { ! 3198: vm_object_unlock(backing_object); ! 3199: return; ! 3200: } ! 3201: ! 3202: /* ! 3203: * The backing object can't be a copy-object: ! 3204: * the shadow_offset for the copy-object must stay ! 3205: * as 0. Furthermore (for the 'we have all the ! 3206: * pages' case), if we bypass backing_object and ! 3207: * just shadow the next object in the chain, old ! 3208: * pages from that object would then have to be copied ! 3209: * BOTH into the (former) backing_object and into the ! 3210: * parent object. ! 3211: */ ! 3212: if (backing_object->shadow != VM_OBJECT_NULL && ! 3213: backing_object->shadow->copy != VM_OBJECT_NULL) { ! 3214: vm_object_unlock(backing_object); ! 3215: return; ! 3216: } ! 3217: ! 3218: /* ! 3219: * We can now try to either collapse the backing ! 3220: * object (if the parent is the only reference to ! 3221: * it) or (perhaps) remove the parent's reference ! 3222: * to it. ! 3223: */ ! 3224: ! 3225: /* ! 3226: * If there is exactly one reference to the backing ! 3227: * object, we may be able to collapse it into the parent. ! 3228: * ! 3229: * XXXO (norma vm): ! 3230: * ! 3231: * The backing object must not have a pager ! 3232: * created for it, since collapsing an object ! 3233: * into a backing_object dumps new pages into ! 3234: * the backing_object that its pager doesn't ! 3235: * know about, and we've already declared pages. ! 3236: * This page dumping is deadly if other kernels ! 3237: * are shadowing this object; this is the ! 3238: * distributed equivalent of the ref_count == 1 ! 3239: * condition. ! 3240: * ! 3241: * With some work, we could downgrade this ! 3242: * restriction to the backing object must not ! 3243: * be cachable, since when a temporary object ! 3244: * is uncachable we are allowed to do anything ! 3245: * to it. We would have to do something like ! 3246: * call declare_pages again, and we would have ! 3247: * to be prepared for the memory manager ! 3248: * disabling temporary termination, which right ! 3249: * now is a difficult race to deal with, since ! 3250: * the memory manager currently assumes that ! 3251: * termination is the only possible failure ! 3252: * for disabling temporary termination. ! 3253: */ ! 3254: ! 3255: if (backing_object->ref_count == 1 && ! 3256: ! object->pager_created && ! 3257: vm_object_collapse_allowed) { ! 3258: ! 3259: XPR(XPR_VM_OBJECT, ! 3260: "vm_object_collapse: %x to %x, pager %x, pager_request %x\n", ! 3261: (integer_t)backing_object, (integer_t)object, ! 3262: (integer_t)backing_object->pager, ! 3263: (integer_t)backing_object->pager_request, 0); ! 3264: ! 3265: /* ! 3266: * We need the cache lock for collapsing, ! 3267: * but we must not deadlock. ! 3268: */ ! 3269: ! 3270: if (! vm_object_cache_lock_try()) { ! 3271: vm_object_unlock(backing_object); ! 3272: return; ! 3273: } ! 3274: ! 3275: /* ! 3276: * Collapse the object with its backing ! 3277: * object, and try again with the object's ! 3278: * new backing object. ! 3279: */ ! 3280: ! 3281: vm_object_do_collapse(object, backing_object); ! 3282: continue; ! 3283: } ! 3284: ! 3285: ! 3286: /* ! 3287: * Collapsing the backing object was not possible ! 3288: * or permitted, so let's try bypassing it. ! 3289: */ ! 3290: ! 3291: if (! vm_object_bypass_allowed) { ! 3292: vm_object_unlock(backing_object); ! 3293: return; ! 3294: } ! 3295: ! 3296: /* ! 3297: * If the backing object has a pager but no pagemap, ! 3298: * then we cannot bypass it, because we don't know ! 3299: * what pages it has. ! 3300: */ ! 3301: if (backing_object->pager_created ! 3302: #if MACH_PAGEMAP ! 3303: && (backing_object->existence_map == VM_EXTERNAL_NULL) ! 3304: #endif /* MACH_PAGEMAP */ ! 3305: ) { ! 3306: vm_object_unlock(backing_object); ! 3307: return; ! 3308: } ! 3309: ! 3310: backing_offset = object->shadow_offset; ! 3311: size = object->size; ! 3312: ! 3313: /* ! 3314: * If all of the pages in the backing object are ! 3315: * shadowed by the parent object, the parent ! 3316: * object no longer has to shadow the backing ! 3317: * object; it can shadow the next one in the ! 3318: * chain. ! 3319: * ! 3320: * If the backing object has existence info, ! 3321: * we must check examine its existence info ! 3322: * as well. ! 3323: * ! 3324: * XXX ! 3325: * Should have a check for a 'small' number ! 3326: * of pages here. ! 3327: */ ! 3328: ! 3329: /* ! 3330: * First, check pages resident in the backing object. ! 3331: */ ! 3332: ! 3333: queue_iterate(&backing_object->memq, p, vm_page_t, listq) { ! 3334: ! 3335: /* ! 3336: * If the parent has a page here, or if ! 3337: * this page falls outside the parent, ! 3338: * keep going. ! 3339: * ! 3340: * Otherwise, the backing_object must be ! 3341: * left in the chain. ! 3342: */ ! 3343: ! 3344: new_offset = (p->offset - backing_offset); ! 3345: if (p->offset < backing_offset || new_offset >= size) { ! 3346: ! 3347: /* ! 3348: * Page falls outside of parent. ! 3349: * Keep going. ! 3350: */ ! 3351: ! 3352: continue; ! 3353: } ! 3354: ! 3355: if ((vm_page_lookup(object, new_offset) == VM_PAGE_NULL) ! 3356: #if MACH_PAGEMAP ! 3357: && ! 3358: (vm_external_state_get(object->existence_map, ! 3359: new_offset) ! 3360: != VM_EXTERNAL_STATE_EXISTS) ! 3361: #endif /* MACH_PAGEMAP */ ! 3362: ) { ! 3363: ! 3364: /* ! 3365: * Page still needed. ! 3366: * Can't go any further. ! 3367: */ ! 3368: ! 3369: vm_object_unlock(backing_object); ! 3370: return; ! 3371: } ! 3372: } ! 3373: ! 3374: #if MACH_PAGEMAP ! 3375: /* ! 3376: * Next, if backing object has been paged out, ! 3377: * we must check its existence info for pages ! 3378: * that the parent doesn't have. ! 3379: */ ! 3380: ! 3381: if (backing_object->pager_created) { ! 3382: assert(backing_object->existence_map ! 3383: != VM_EXTERNAL_NULL); ! 3384: for (new_offset = 0; new_offset < object->size; ! 3385: new_offset += PAGE_SIZE) { ! 3386: vm_offset_t ! 3387: offset = new_offset + backing_offset; ! 3388: ! 3389: /* ! 3390: * If this page doesn't exist in ! 3391: * the backing object's existence ! 3392: * info, then continue. ! 3393: */ ! 3394: ! 3395: if (vm_external_state_get( ! 3396: backing_object->existence_map, ! 3397: offset) == VM_EXTERNAL_STATE_ABSENT) { ! 3398: continue; ! 3399: } ! 3400: ! 3401: /* ! 3402: * If this page is neither resident ! 3403: * in the parent nor paged out to ! 3404: * the parent's pager, then we cannot ! 3405: * bypass the backing object. ! 3406: */ ! 3407: ! 3408: if ((vm_page_lookup(object, new_offset) == ! 3409: VM_PAGE_NULL) && ! 3410: ((object->existence_map == VM_EXTERNAL_NULL) ! 3411: || (vm_external_state_get( ! 3412: object->existence_map, new_offset) ! 3413: == VM_EXTERNAL_STATE_ABSENT))) { ! 3414: vm_object_unlock(backing_object); ! 3415: return; ! 3416: } ! 3417: } ! 3418: } ! 3419: #else /* MACH_PAGEMAP */ ! 3420: assert(! backing_object->pager_created); ! 3421: #endif /* MACH_PAGEMAP */ ! 3422: ! 3423: /* ! 3424: * All interesting pages in the backing object ! 3425: * already live in the parent or its pager. ! 3426: * Thus we can bypass the backing object. ! 3427: */ ! 3428: ! 3429: vm_object_do_bypass(object, backing_object); ! 3430: ! 3431: /* ! 3432: * Try again with this object's new backing object. ! 3433: */ ! 3434: ! 3435: continue; ! 3436: } ! 3437: } ! 3438: ! 3439: /* ! 3440: * Routine: vm_object_page_remove: [internal] ! 3441: * Purpose: ! 3442: * Removes all physical pages in the specified ! 3443: * object range from the object's list of pages. ! 3444: * ! 3445: * In/out conditions: ! 3446: * The object must be locked. ! 3447: * The object must not have paging_in_progress, usually ! 3448: * guaranteed by not having a pager. ! 3449: */ ! 3450: unsigned int vm_object_page_remove_lookup = 0; ! 3451: unsigned int vm_object_page_remove_iterate = 0; ! 3452: ! 3453: void ! 3454: vm_object_page_remove( ! 3455: register vm_object_t object, ! 3456: register vm_offset_t start, ! 3457: register vm_offset_t end) ! 3458: { ! 3459: register vm_page_t p, next; ! 3460: ! 3461: /* ! 3462: * One and two page removals are most popular. ! 3463: * The factor of 16 here is somewhat arbitrary. ! 3464: * It balances vm_object_lookup vs iteration. ! 3465: */ ! 3466: ! 3467: if (atop(end - start) < (unsigned)object->resident_page_count/16) { ! 3468: vm_object_page_remove_lookup++; ! 3469: ! 3470: for (; start < end; start += PAGE_SIZE) { ! 3471: p = vm_page_lookup(object, start); ! 3472: if (p != VM_PAGE_NULL) { ! 3473: assert(!p->cleaning && !p->pageout); ! 3474: if (!p->fictitious) ! 3475: pmap_page_protect(p->phys_addr, ! 3476: VM_PROT_NONE); ! 3477: VM_PAGE_FREE(p); ! 3478: } ! 3479: } ! 3480: } else { ! 3481: vm_object_page_remove_iterate++; ! 3482: ! 3483: p = (vm_page_t) queue_first(&object->memq); ! 3484: while (!queue_end(&object->memq, (queue_entry_t) p)) { ! 3485: next = (vm_page_t) queue_next(&p->listq); ! 3486: if ((start <= p->offset) && (p->offset < end)) { ! 3487: assert(!p->cleaning && !p->pageout); ! 3488: if (!p->fictitious) ! 3489: pmap_page_protect(p->phys_addr, ! 3490: VM_PROT_NONE); ! 3491: VM_PAGE_FREE(p); ! 3492: } ! 3493: p = next; ! 3494: } ! 3495: } ! 3496: } ! 3497: ! 3498: /* ! 3499: * Routine: vm_object_coalesce ! 3500: * Function: Coalesces two objects backing up adjoining ! 3501: * regions of memory into a single object. ! 3502: * ! 3503: * returns TRUE if objects were combined. ! 3504: * ! 3505: * NOTE: Only works at the moment if the second object is NULL - ! 3506: * if it's not, which object do we lock first? ! 3507: * ! 3508: * Parameters: ! 3509: * prev_object First object to coalesce ! 3510: * prev_offset Offset into prev_object ! 3511: * next_object Second object into coalesce ! 3512: * next_offset Offset into next_object ! 3513: * ! 3514: * prev_size Size of reference to prev_object ! 3515: * next_size Size of reference to next_object ! 3516: * ! 3517: * Conditions: ! 3518: * The object(s) must *not* be locked. The map must be locked ! 3519: * to preserve the reference to the object(s). ! 3520: */ ! 3521: int vm_object_coalesce_count = 0; ! 3522: ! 3523: boolean_t ! 3524: vm_object_coalesce( ! 3525: register vm_object_t prev_object, ! 3526: vm_object_t next_object, ! 3527: vm_offset_t prev_offset, ! 3528: vm_offset_t next_offset, ! 3529: vm_size_t prev_size, ! 3530: vm_size_t next_size) ! 3531: { ! 3532: vm_size_t newsize; ! 3533: ! 3534: #ifdef lint ! 3535: next_offset++; ! 3536: #endif /* lint */ ! 3537: ! 3538: if (next_object != VM_OBJECT_NULL) { ! 3539: return(FALSE); ! 3540: } ! 3541: ! 3542: if (prev_object == VM_OBJECT_NULL) { ! 3543: return(TRUE); ! 3544: } ! 3545: ! 3546: XPR(XPR_VM_OBJECT, ! 3547: "vm_object_coalesce: 0x%X prev_off 0x%X prev_size 0x%X next_size 0x%X\n", ! 3548: (integer_t)prev_object, prev_offset, prev_size, next_size, 0); ! 3549: ! 3550: vm_object_lock(prev_object); ! 3551: ! 3552: /* ! 3553: * Try to collapse the object first ! 3554: */ ! 3555: vm_object_collapse(prev_object); ! 3556: ! 3557: /* ! 3558: * Can't coalesce if pages not mapped to ! 3559: * prev_entry may be in use any way: ! 3560: * . more than one reference ! 3561: * . paged out ! 3562: * . shadows another object ! 3563: * . has a copy elsewhere ! 3564: * . paging references (pages might be in page-list) ! 3565: */ ! 3566: ! 3567: if ((prev_object->ref_count > 1) || ! 3568: prev_object->pager_created || ! 3569: (prev_object->shadow != VM_OBJECT_NULL) || ! 3570: (prev_object->copy != VM_OBJECT_NULL) || ! 3571: (prev_object->true_share != FALSE) || ! 3572: (prev_object->paging_in_progress != 0)) { ! 3573: vm_object_unlock(prev_object); ! 3574: return(FALSE); ! 3575: } ! 3576: ! 3577: vm_object_coalesce_count++; ! 3578: ! 3579: /* ! 3580: * Remove any pages that may still be in the object from ! 3581: * a previous deallocation. ! 3582: */ ! 3583: vm_object_page_remove(prev_object, ! 3584: prev_offset + prev_size, ! 3585: prev_offset + prev_size + next_size); ! 3586: ! 3587: /* ! 3588: * Extend the object if necessary. ! 3589: */ ! 3590: newsize = prev_offset + prev_size + next_size; ! 3591: if (newsize > prev_object->size) { ! 3592: #if MACH_PAGEMAP ! 3593: /* ! 3594: * We cannot extend an object that has existence info, ! 3595: * since the existence info might then fail to cover ! 3596: * the entire object. ! 3597: * ! 3598: * This assertion must be true because the object ! 3599: * has no pager, and we only create existence info ! 3600: * for objects with pagers. ! 3601: */ ! 3602: assert(prev_object->existence_map == VM_EXTERNAL_NULL); ! 3603: #endif /* MACH_PAGEMAP */ ! 3604: prev_object->size = newsize; ! 3605: } ! 3606: ! 3607: vm_object_unlock(prev_object); ! 3608: return(TRUE); ! 3609: } ! 3610: ! 3611: /* ! 3612: * Attach a set of physical pages to an object, so that they can ! 3613: * be mapped by mapping the object. Typically used to map IO memory. ! 3614: * ! 3615: * The mapping function and its private data are used to obtain the ! 3616: * physical addresses for each page to be mapped. ! 3617: */ ! 3618: void ! 3619: vm_object_page_map( ! 3620: vm_object_t object, ! 3621: vm_offset_t offset, ! 3622: vm_size_t size, ! 3623: vm_offset_t (*map_fn)(void *map_fn_data, vm_offset_t offset), ! 3624: void *map_fn_data) /* private to map_fn */ ! 3625: { ! 3626: int num_pages; ! 3627: int i; ! 3628: vm_page_t m; ! 3629: vm_page_t old_page; ! 3630: vm_offset_t addr; ! 3631: ! 3632: num_pages = atop(size); ! 3633: ! 3634: for (i = 0; i < num_pages; i++, offset += PAGE_SIZE) { ! 3635: ! 3636: addr = (*map_fn)(map_fn_data, offset); ! 3637: ! 3638: while ((m = vm_page_grab_fictitious()) == VM_PAGE_NULL) ! 3639: vm_page_more_fictitious(); ! 3640: ! 3641: vm_object_lock(object); ! 3642: if ((old_page = vm_page_lookup(object, offset)) ! 3643: != VM_PAGE_NULL) ! 3644: { ! 3645: vm_page_lock_queues(); ! 3646: vm_page_free(old_page); ! 3647: vm_page_unlock_queues(); ! 3648: } ! 3649: ! 3650: vm_page_init(m, addr); ! 3651: m->private = TRUE; /* don`t free page */ ! 3652: m->wire_count = 1; ! 3653: vm_page_insert(m, object, offset); ! 3654: ! 3655: PAGE_WAKEUP_DONE(m); ! 3656: vm_object_unlock(object); ! 3657: } ! 3658: } ! 3659: ! 3660: #include <mach_kdb.h> ! 3661: ! 3662: #if MACH_KDB ! 3663: #include <ddb/db_output.h> ! 3664: #include <vm/vm_print.h> ! 3665: ! 3666: #define printf kdbprintf ! 3667: ! 3668: extern boolean_t vm_object_cached( ! 3669: vm_object_t object); ! 3670: ! 3671: extern void print_bitstring( ! 3672: char byte); ! 3673: ! 3674: boolean_t vm_object_print_pages = FALSE; ! 3675: ! 3676: void ! 3677: print_bitstring( ! 3678: char byte) ! 3679: { ! 3680: printf("%c%c%c%c%c%c%c%c", ! 3681: ((byte & (1 << 0)) ? '1' : '0'), ! 3682: ((byte & (1 << 1)) ? '1' : '0'), ! 3683: ((byte & (1 << 2)) ? '1' : '0'), ! 3684: ((byte & (1 << 3)) ? '1' : '0'), ! 3685: ((byte & (1 << 4)) ? '1' : '0'), ! 3686: ((byte & (1 << 5)) ? '1' : '0'), ! 3687: ((byte & (1 << 6)) ? '1' : '0'), ! 3688: ((byte & (1 << 7)) ? '1' : '0')); ! 3689: } ! 3690: ! 3691: boolean_t ! 3692: vm_object_cached( ! 3693: register vm_object_t object) ! 3694: { ! 3695: register vm_object_t o; ! 3696: ! 3697: queue_iterate(&vm_object_cached_list, o, vm_object_t, cached_list) { ! 3698: if (object == o) { ! 3699: return TRUE; ! 3700: } ! 3701: } ! 3702: return FALSE; ! 3703: } ! 3704: ! 3705: #if MACH_PAGEMAP ! 3706: /* ! 3707: * vm_external_print: [ debug ] ! 3708: */ ! 3709: void ! 3710: vm_external_print( ! 3711: vm_external_map_t map, ! 3712: vm_size_t size) ! 3713: { ! 3714: if (map == VM_EXTERNAL_NULL) { ! 3715: printf("0 "); ! 3716: } else { ! 3717: vm_size_t existence_size = stob(size); ! 3718: printf("{ size=%d, map=[", existence_size); ! 3719: if (existence_size > 0) { ! 3720: print_bitstring(map[0]); ! 3721: } ! 3722: if (existence_size > 1) { ! 3723: print_bitstring(map[1]); ! 3724: } ! 3725: if (existence_size > 2) { ! 3726: printf("..."); ! 3727: print_bitstring(map[existence_size-1]); ! 3728: } ! 3729: printf("] }\n"); ! 3730: } ! 3731: return; ! 3732: } ! 3733: #endif /* MACH_PAGEMAP */ ! 3734: ! 3735: int ! 3736: vm_follow_object( ! 3737: vm_object_t object) ! 3738: { ! 3739: extern db_indent; ! 3740: ! 3741: int count = 1; ! 3742: ! 3743: if (object == VM_OBJECT_NULL) ! 3744: return 0; ! 3745: ! 3746: iprintf("object 0x%x", object); ! 3747: printf(", shadow=0x%x", object->shadow); ! 3748: printf(", copy=0x%x", object->copy); ! 3749: printf(", pager=0x%x", object->pager); ! 3750: printf(", ref=%d\n", object->ref_count); ! 3751: ! 3752: db_indent += 2; ! 3753: if (object->shadow) ! 3754: count += vm_follow_object(object->shadow); ! 3755: ! 3756: db_indent -= 2; ! 3757: return count; ! 3758: } ! 3759: ! 3760: /* ! 3761: * vm_object_print: [ debug ] ! 3762: */ ! 3763: void ! 3764: vm_object_print( ! 3765: vm_object_t object, ! 3766: boolean_t have_addr, ! 3767: int arg_count, ! 3768: char *modif) ! 3769: { ! 3770: register vm_page_t p; ! 3771: extern db_indent; ! 3772: char *s; ! 3773: ! 3774: register int count; ! 3775: ! 3776: if (object == VM_OBJECT_NULL) ! 3777: return; ! 3778: ! 3779: iprintf("object 0x%x\n", object); ! 3780: ! 3781: db_indent += 2; ! 3782: ! 3783: iprintf("size=0x%x", object->size); ! 3784: printf(", cluster=0x%x", object->cluster_size); ! 3785: printf(", frozen=0x%x", object->frozen_size); ! 3786: printf(", ref_count=%d\n", object->ref_count); ! 3787: iprintf(""); ! 3788: #if TASK_SWAPPER ! 3789: printf("res_count=%d, ", object->res_count); ! 3790: #endif /* TASK_SWAPPER */ ! 3791: printf("resident_page_count=%d\n", object->resident_page_count); ! 3792: ! 3793: iprintf("shadow=0x%x", object->shadow); ! 3794: if (object->shadow) { ! 3795: register int i = 0; ! 3796: vm_object_t shadow = object; ! 3797: while(shadow = shadow->shadow) ! 3798: i++; ! 3799: printf(" (depth %d)", i); ! 3800: } ! 3801: printf(", copy=0x%x", object->copy); ! 3802: printf(", shadow_offset=0x%x", object->shadow_offset); ! 3803: printf(", last_alloc=0x%x\n", object->last_alloc); ! 3804: ! 3805: iprintf("pager=0x%x", object->pager); ! 3806: printf(", paging_offset=0x%x", object->paging_offset); ! 3807: printf(", pager_request=0x%x\n", object->pager_request); ! 3808: ! 3809: iprintf("copy_strategy=%d[", object->copy_strategy); ! 3810: switch (object->copy_strategy) { ! 3811: case MEMORY_OBJECT_COPY_NONE: ! 3812: printf("copy_none"); ! 3813: break; ! 3814: ! 3815: case MEMORY_OBJECT_COPY_CALL: ! 3816: printf("copy_call"); ! 3817: break; ! 3818: ! 3819: case MEMORY_OBJECT_COPY_DELAY: ! 3820: printf("copy_delay"); ! 3821: break; ! 3822: ! 3823: case MEMORY_OBJECT_COPY_SYMMETRIC: ! 3824: printf("copy_symmetric"); ! 3825: break; ! 3826: ! 3827: case MEMORY_OBJECT_COPY_INVALID: ! 3828: printf("copy_invalid"); ! 3829: break; ! 3830: ! 3831: default: ! 3832: printf("?"); ! 3833: } ! 3834: printf("]"); ! 3835: printf(", absent_count=%d\n", object->absent_count); ! 3836: ! 3837: iprintf("all_wanted=0x%x<", object->all_wanted); ! 3838: s = ""; ! 3839: if (vm_object_wanted(object, VM_OBJECT_EVENT_INITIALIZED)) { ! 3840: printf("%sinit", s); ! 3841: s = ","; ! 3842: } ! 3843: if (vm_object_wanted(object, VM_OBJECT_EVENT_PAGER_READY)) { ! 3844: printf("%sready", s); ! 3845: s = ","; ! 3846: } ! 3847: if (vm_object_wanted(object, VM_OBJECT_EVENT_PAGING_IN_PROGRESS)) { ! 3848: printf("%spaging", s); ! 3849: s = ","; ! 3850: } ! 3851: if (vm_object_wanted(object, VM_OBJECT_EVENT_ABSENT_COUNT)) { ! 3852: printf("%sabsent", s); ! 3853: s = ","; ! 3854: } ! 3855: if (vm_object_wanted(object, VM_OBJECT_EVENT_LOCK_IN_PROGRESS)) { ! 3856: printf("%slock", s); ! 3857: s = ","; ! 3858: } ! 3859: if (vm_object_wanted(object, VM_OBJECT_EVENT_UNCACHING)) { ! 3860: printf("%suncaching", s); ! 3861: s = ","; ! 3862: } ! 3863: if (vm_object_wanted(object, VM_OBJECT_EVENT_COPY_CALL)) { ! 3864: printf("%scopy_call", s); ! 3865: s = ","; ! 3866: } ! 3867: if (vm_object_wanted(object, VM_OBJECT_EVENT_CACHING)) { ! 3868: printf("%scaching", s); ! 3869: s = ","; ! 3870: } ! 3871: printf(">"); ! 3872: printf(", paging_in_progress=%d\n", object->paging_in_progress); ! 3873: ! 3874: iprintf("%screated, %sinit, %sready, %spersist, %strusted, %spageout, %s, %s\n", ! 3875: (object->pager_created ? "" : "!"), ! 3876: (object->pager_initialized ? "" : "!"), ! 3877: (object->pager_ready ? "" : "!"), ! 3878: (object->can_persist ? "" : "!"), ! 3879: (object->pager_trusted ? "" : "!"), ! 3880: (object->pageout ? "" : "!"), ! 3881: (object->internal ? "internal" : "external"), ! 3882: (object->temporary ? "temporary" : "permanent")); ! 3883: iprintf("%salive, %slock_in_progress, %slock_restart, %sshadowed, %scached, %sprivate\n", ! 3884: (object->alive ? "" : "!"), ! 3885: (object->lock_in_progress ? "" : "!"), ! 3886: (object->lock_restart ? "" : "!"), ! 3887: (object->shadowed ? "" : "!"), ! 3888: (vm_object_cached(object) ? "" : "!"), ! 3889: (object->private ? "" : "!")); ! 3890: iprintf("%sadvisory_pageout, %ssilent_overwrite\n", ! 3891: (object->advisory_pageout ? "" : "!"), ! 3892: (object->silent_overwrite ? "" : "!")); ! 3893: ! 3894: #if MACH_PAGEMAP ! 3895: iprintf("existence_map="); ! 3896: vm_external_print(object->existence_map, object->size); ! 3897: #endif /* MACH_PAGEMAP */ ! 3898: #if MACH_ASSERT ! 3899: iprintf("paging_object=0x%x\n", object->paging_object); ! 3900: #endif /* MACH_ASSERT */ ! 3901: ! 3902: if (vm_object_print_pages) { ! 3903: count = 0; ! 3904: p = (vm_page_t) queue_first(&object->memq); ! 3905: while (!queue_end(&object->memq, (queue_entry_t) p)) { ! 3906: if (count == 0) { ! 3907: iprintf("memory:="); ! 3908: } else if (count == 2) { ! 3909: printf("\n"); ! 3910: iprintf(" ..."); ! 3911: count = 0; ! 3912: } else { ! 3913: printf(","); ! 3914: } ! 3915: count++; ! 3916: ! 3917: printf("(off=0x%X,page=0x%X)", p->offset, (integer_t) p); ! 3918: p = (vm_page_t) queue_next(&p->listq); ! 3919: } ! 3920: if (count != 0) { ! 3921: printf("\n"); ! 3922: } ! 3923: } ! 3924: db_indent -= 2; ! 3925: } ! 3926: ! 3927: ! 3928: /* ! 3929: * vm_object_find [ debug ] ! 3930: * ! 3931: * Find all tasks which reference the given vm_object. ! 3932: */ ! 3933: ! 3934: boolean_t vm_object_find(vm_object_t object); ! 3935: boolean_t vm_object_print_verbose = FALSE; ! 3936: ! 3937: boolean_t ! 3938: vm_object_find( ! 3939: vm_object_t object) ! 3940: { ! 3941: task_t task; ! 3942: vm_map_t map; ! 3943: vm_map_entry_t entry; ! 3944: processor_set_t pset; ! 3945: boolean_t found = FALSE; ! 3946: ! 3947: queue_iterate(&all_psets, pset, processor_set_t, all_psets) { ! 3948: queue_iterate(&pset->tasks, task, task_t, pset_tasks) { ! 3949: map = task->map; ! 3950: for (entry = vm_map_first_entry(map); ! 3951: entry && entry != vm_map_to_entry(map); ! 3952: entry = entry->vme_next) { ! 3953: ! 3954: vm_object_t obj; ! 3955: ! 3956: /* ! 3957: * For the time being skip submaps, ! 3958: * only the kernel can have submaps, ! 3959: * and unless we are interested in ! 3960: * kernel objects, we can simply skip ! 3961: * submaps. See sb/dejan/nmk18b7/src/mach_kernel/vm ! 3962: * for a full solution. ! 3963: */ ! 3964: if (entry->is_sub_map) ! 3965: continue; ! 3966: if (entry) ! 3967: obj = entry->object.vm_object; ! 3968: else ! 3969: continue; ! 3970: ! 3971: while (obj != VM_OBJECT_NULL) { ! 3972: if (obj == object) { ! 3973: if (!found) { ! 3974: printf("TASK\t\tMAP\t\tENTRY\n"); ! 3975: found = TRUE; ! 3976: } ! 3977: printf("0x%x\t0x%x\t0x%x\n", ! 3978: task, map, entry); ! 3979: } ! 3980: obj = obj->shadow; ! 3981: } ! 3982: } ! 3983: } ! 3984: } ! 3985: ! 3986: return(found); ! 3987: } ! 3988: ! 3989: #endif /* MACH_KDB */ ! 3990: ! 3991: /* ! 3992: * memory_object_free_from_cache: ! 3993: * ! 3994: * Walk the vm_object cache list, removing and freeing vm_objects ! 3995: * which are backed by the pager identified by the caller, (pager_id). ! 3996: * Remove up to "count" objects, if there are that may available ! 3997: * in the cache. ! 3998: * Walk the list at most once, return the number of vm_objects ! 3999: * actually freed. ! 4000: * ! 4001: */ ! 4002: ! 4003: kern_return_t ! 4004: memory_object_free_from_cache( ! 4005: host_t host, ! 4006: int pager_id, ! 4007: int *count) ! 4008: { ! 4009: ! 4010: int object_released = 0; ! 4011: int i; ! 4012: ! 4013: register vm_object_t object = VM_OBJECT_NULL; ! 4014: vm_object_t shadow; ! 4015: ! 4016: if(host == HOST_NULL) ! 4017: return(KERN_INVALID_ARGUMENT); ! 4018: ! 4019: try_again: ! 4020: vm_object_cache_lock(); ! 4021: ! 4022: queue_iterate(&vm_object_cached_list, object, ! 4023: vm_object_t, cached_list) { ! 4024: if (pager_id == (int) pager_mux_hash_lookup( ! 4025: (ipc_port_t)object->pager)) { ! 4026: vm_object_lock(object); ! 4027: queue_remove(&vm_object_cached_list, object, ! 4028: vm_object_t, cached_list); ! 4029: vm_object_cached_count--; ! 4030: ! 4031: /* ! 4032: * Since this object is in the cache, we know ! 4033: * that it is initialized and has no references. ! 4034: * Take a reference to avoid recursive ! 4035: * deallocations. ! 4036: */ ! 4037: ! 4038: assert(object->pager_initialized); ! 4039: assert(object->ref_count == 0); ! 4040: object->ref_count++; ! 4041: ! 4042: /* ! 4043: * Terminate the object. ! 4044: * If the object had a shadow, we let ! 4045: * vm_object_deallocate deallocate it. ! 4046: * "pageout" objects have a shadow, but ! 4047: * maintain a "paging reference" rather ! 4048: * than a normal reference. ! 4049: * (We are careful here to limit recursion.) ! 4050: */ ! 4051: shadow = object->pageout?VM_OBJECT_NULL:object->shadow; ! 4052: vm_object_terminate(object); ! 4053: if (shadow != VM_OBJECT_NULL) { ! 4054: vm_object_deallocate(shadow); ! 4055: } ! 4056: ! 4057: if(object_released++ == *count) ! 4058: return KERN_SUCCESS; ! 4059: goto try_again; ! 4060: } ! 4061: } ! 4062: vm_object_cache_unlock(); ! 4063: *count = object_released; ! 4064: return KERN_SUCCESS; ! 4065: } ! 4066: ! 4067: /* ! 4068: * memory_object_remove_cached_object: ! 4069: * ! 4070: * Check for the existance of a memory object represented by the ! 4071: * supplied port. If one exists and it is not in use, remove the ! 4072: * memory object from the vm_object cache. ! 4073: * If the memory object is in use, turn off the the "can_persist" ! 4074: * property so that it will not go in the cache when the last user ! 4075: * gives it up. ! 4076: * ! 4077: */ ! 4078: ! 4079: kern_return_t ! 4080: memory_object_remove_cached_object( ! 4081: ipc_port_t port) ! 4082: { ! 4083: vm_object_t object; ! 4084: vm_object_t shadow; ! 4085: ! 4086: repeat_lock_acquire: ! 4087: object = VM_OBJECT_NULL; ! 4088: ! 4089: if (IP_VALID(port)) { ! 4090: vm_object_cache_lock(); ! 4091: ip_lock(port); ! 4092: if (ip_active(port) && ! 4093: (ip_kotype(port) == IKOT_PAGER_LOOKUP_TYPE)) { ! 4094: object = (vm_object_t) port->ip_kobject; ! 4095: if (!vm_object_lock_try(object)) { ! 4096: /* ! 4097: * failed to acquire object lock. Drop the ! 4098: * other two locks and wait for it, then go ! 4099: * back and start over in case the port ! 4100: * associations changed in the interim. ! 4101: */ ! 4102: ip_unlock(port); ! 4103: vm_object_cache_unlock(); ! 4104: vm_object_lock(object); ! 4105: vm_object_unlock(object); ! 4106: goto repeat_lock_acquire; ! 4107: } ! 4108: ! 4109: assert(object->alive); ! 4110: ip_unlock(port); ! 4111: ! 4112: if (object->ref_count == 0) { ! 4113: queue_remove(&vm_object_cached_list, object, ! 4114: vm_object_t, cached_list); ! 4115: vm_object_cached_count--; ! 4116: object->ref_count++; ! 4117: /* ! 4118: * Terminate the object. ! 4119: * If the object had a shadow, we let ! 4120: * vm_object_deallocate deallocate it. ! 4121: * "pageout" objects have a shadow, but ! 4122: * maintain a "paging reference" rather ! 4123: * than a normal reference. ! 4124: * (We are careful here to limit ! 4125: * recursion.) ! 4126: */ ! 4127: shadow = object->pageout? ! 4128: VM_OBJECT_NULL:object->shadow; ! 4129: /* will do the vm_object_cache_unlock */ ! 4130: vm_object_terminate(object); ! 4131: if (shadow != VM_OBJECT_NULL) { ! 4132: /* will lock and unlock cache_lock */ ! 4133: vm_object_deallocate(shadow); ! 4134: } ! 4135: } ! 4136: else { ! 4137: /* ! 4138: * We cannot free object but we can ! 4139: * make sure it doesn't go into the ! 4140: * cache when it is no longer in ! 4141: * use. ! 4142: */ ! 4143: object->can_persist = FALSE; ! 4144: ! 4145: vm_object_unlock(object); ! 4146: vm_object_cache_unlock(); ! 4147: return KERN_RIGHT_EXISTS; ! 4148: } ! 4149: ! 4150: ! 4151: } ! 4152: else { ! 4153: ip_unlock(port); ! 4154: vm_object_cache_unlock(); ! 4155: } ! 4156: } else { ! 4157: return KERN_INVALID_ARGUMENT; ! 4158: } ! 4159: ! 4160: ! 4161: return KERN_SUCCESS; ! 4162: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.