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