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