|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1994,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: vm_fault.c ! 31: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 32: * ! 33: * Page fault handling module. ! 34: */ ! 35: #include <mach_pagemap.h> ! 36: #include <mach_kdb.h> ! 37: #include <mach_pcsample.h> ! 38: ! 39: ! 40: #include <vm/vm_fault.h> ! 41: #include <mach/kern_return.h> ! 42: #include <mach/message.h> /* for error codes */ ! 43: #include <kern/counters.h> ! 44: #include <kern/thread.h> ! 45: #include <kern/sched_prim.h> ! 46: #include <vm/vm_map.h> ! 47: #include <vm/vm_object.h> ! 48: #include <vm/vm_page.h> ! 49: #include <vm/pmap.h> ! 50: #include <mach/vm_statistics.h> ! 51: #include <vm/vm_pageout.h> ! 52: #include <mach/vm_param.h> ! 53: #include <mach/memory_object.h> ! 54: #include "memory_object_user.h" ! 55: /* For memory_object_data_{request,unlock} */ ! 56: #include <kern/mach_param.h> ! 57: #include <kern/macro_help.h> ! 58: #include <kern/zalloc.h> ! 59: ! 60: #if MACH_PCSAMPLE ! 61: #include <kern/pc_sample.h> ! 62: #endif ! 63: ! 64: ! 65: ! 66: /* ! 67: * State needed by vm_fault_continue. ! 68: * This is a little hefty to drop directly ! 69: * into the thread structure. ! 70: */ ! 71: typedef struct vm_fault_state { ! 72: struct vm_map *vmf_map; ! 73: vm_offset_t vmf_vaddr; ! 74: vm_prot_t vmf_fault_type; ! 75: boolean_t vmf_change_wiring; ! 76: void (*vmf_continuation)(); ! 77: vm_map_version_t vmf_version; ! 78: boolean_t vmf_wired; ! 79: struct vm_object *vmf_object; ! 80: vm_offset_t vmf_offset; ! 81: vm_prot_t vmf_prot; ! 82: ! 83: boolean_t vmfp_backoff; ! 84: struct vm_object *vmfp_object; ! 85: vm_offset_t vmfp_offset; ! 86: struct vm_page *vmfp_first_m; ! 87: vm_prot_t vmfp_access; ! 88: } vm_fault_state_t; ! 89: ! 90: zone_t vm_fault_state_zone = 0; ! 91: ! 92: int vm_object_absent_max = 50; ! 93: ! 94: int vm_fault_debug = 0; ! 95: ! 96: boolean_t vm_fault_dirty_handling = FALSE; ! 97: boolean_t vm_fault_interruptible = TRUE; ! 98: ! 99: boolean_t software_reference_bits = TRUE; ! 100: ! 101: #if MACH_KDB ! 102: extern struct db_watchpoint *db_watchpoint_list; ! 103: #endif /* MACH_KDB */ ! 104: ! 105: /* ! 106: * Routine: vm_fault_init ! 107: * Purpose: ! 108: * Initialize our private data structures. ! 109: */ ! 110: void vm_fault_init() ! 111: { ! 112: vm_fault_state_zone = zinit(sizeof(vm_fault_state_t), ! 113: THREAD_MAX * sizeof(vm_fault_state_t), ! 114: sizeof(vm_fault_state_t), ! 115: 0, "vm fault state"); ! 116: } ! 117: ! 118: /* ! 119: * Routine: vm_fault_cleanup ! 120: * Purpose: ! 121: * Clean up the result of vm_fault_page. ! 122: * Results: ! 123: * The paging reference for "object" is released. ! 124: * "object" is unlocked. ! 125: * If "top_page" is not null, "top_page" is ! 126: * freed and the paging reference for the object ! 127: * containing it is released. ! 128: * ! 129: * In/out conditions: ! 130: * "object" must be locked. ! 131: */ ! 132: void ! 133: vm_fault_cleanup(object, top_page) ! 134: register vm_object_t object; ! 135: register vm_page_t top_page; ! 136: { ! 137: vm_object_paging_end(object); ! 138: vm_object_unlock(object); ! 139: ! 140: if (top_page != VM_PAGE_NULL) { ! 141: object = top_page->object; ! 142: vm_object_lock(object); ! 143: VM_PAGE_FREE(top_page); ! 144: vm_object_paging_end(object); ! 145: vm_object_unlock(object); ! 146: } ! 147: } ! 148: ! 149: ! 150: #if MACH_PCSAMPLE ! 151: /* ! 152: * Do PC sampling on current thread, assuming ! 153: * that it is the thread taking this page fault. ! 154: * ! 155: * Must check for THREAD_NULL, since faults ! 156: * can occur before threads are running. ! 157: */ ! 158: ! 159: #define vm_stat_sample(flavor) \ ! 160: MACRO_BEGIN \ ! 161: thread_t _thread_ = current_thread(); \ ! 162: \ ! 163: if (_thread_ != THREAD_NULL) \ ! 164: take_pc_sample_macro(_thread_, (flavor)); \ ! 165: MACRO_END ! 166: ! 167: #else ! 168: #define vm_stat_sample(x) ! 169: #endif /* MACH_PCSAMPLE */ ! 170: ! 171: ! 172: ! 173: /* ! 174: * Routine: vm_fault_page ! 175: * Purpose: ! 176: * Find the resident page for the virtual memory ! 177: * specified by the given virtual memory object ! 178: * and offset. ! 179: * Additional arguments: ! 180: * The required permissions for the page is given ! 181: * in "fault_type". Desired permissions are included ! 182: * in "protection". ! 183: * ! 184: * If the desired page is known to be resident (for ! 185: * example, because it was previously wired down), asserting ! 186: * the "unwiring" parameter will speed the search. ! 187: * ! 188: * If the operation can be interrupted (by thread_abort ! 189: * or thread_terminate), then the "interruptible" ! 190: * parameter should be asserted. ! 191: * ! 192: * Results: ! 193: * The page containing the proper data is returned ! 194: * in "result_page". ! 195: * ! 196: * In/out conditions: ! 197: * The source object must be locked and referenced, ! 198: * and must donate one paging reference. The reference ! 199: * is not affected. The paging reference and lock are ! 200: * consumed. ! 201: * ! 202: * If the call succeeds, the object in which "result_page" ! 203: * resides is left locked and holding a paging reference. ! 204: * If this is not the original object, a busy page in the ! 205: * original object is returned in "top_page", to prevent other ! 206: * callers from pursuing this same data, along with a paging ! 207: * reference for the original object. The "top_page" should ! 208: * be destroyed when this guarantee is no longer required. ! 209: * The "result_page" is also left busy. It is not removed ! 210: * from the pageout queues. ! 211: */ ! 212: vm_fault_return_t vm_fault_page(first_object, first_offset, ! 213: fault_type, must_be_resident, interruptible, ! 214: protection, ! 215: result_page, top_page, ! 216: resume, continuation) ! 217: /* Arguments: */ ! 218: vm_object_t first_object; /* Object to begin search */ ! 219: vm_offset_t first_offset; /* Offset into object */ ! 220: vm_prot_t fault_type; /* What access is requested */ ! 221: boolean_t must_be_resident;/* Must page be resident? */ ! 222: boolean_t interruptible; /* May fault be interrupted? */ ! 223: /* Modifies in place: */ ! 224: vm_prot_t *protection; /* Protection for mapping */ ! 225: /* Returns: */ ! 226: vm_page_t *result_page; /* Page found, if successful */ ! 227: vm_page_t *top_page; /* Page in top object, if ! 228: * not result_page. ! 229: */ ! 230: /* More arguments: */ ! 231: boolean_t resume; /* We are restarting. */ ! 232: void (*continuation)(); /* Continuation for blocking. */ ! 233: { ! 234: register ! 235: vm_page_t m; ! 236: register ! 237: vm_object_t object; ! 238: register ! 239: vm_offset_t offset; ! 240: vm_page_t first_m; ! 241: vm_object_t next_object; ! 242: vm_object_t copy_object; ! 243: boolean_t look_for_page; ! 244: vm_prot_t access_required; ! 245: ! 246: #ifdef CONTINUATIONS ! 247: if (resume) { ! 248: register vm_fault_state_t *state = ! 249: (vm_fault_state_t *) current_thread()->ith_other; ! 250: ! 251: if (state->vmfp_backoff) ! 252: goto after_block_and_backoff; ! 253: ! 254: object = state->vmfp_object; ! 255: offset = state->vmfp_offset; ! 256: first_m = state->vmfp_first_m; ! 257: access_required = state->vmfp_access; ! 258: goto after_thread_block; ! 259: } ! 260: #else /* not CONTINUATIONS */ ! 261: assert(continuation == 0); ! 262: assert(!resume); ! 263: #endif /* not CONTINUATIONS */ ! 264: ! 265: vm_stat_sample(SAMPLED_PC_VM_FAULTS_ANY); ! 266: vm_stat.faults++; /* needs lock XXX */ ! 267: ! 268: /* ! 269: * Recovery actions ! 270: */ ! 271: #define RELEASE_PAGE(m) \ ! 272: MACRO_BEGIN \ ! 273: PAGE_WAKEUP_DONE(m); \ ! 274: vm_page_lock_queues(); \ ! 275: if (!m->active && !m->inactive) \ ! 276: vm_page_activate(m); \ ! 277: vm_page_unlock_queues(); \ ! 278: MACRO_END ! 279: ! 280: if (vm_fault_dirty_handling ! 281: #if MACH_KDB ! 282: /* ! 283: * If there are watchpoints set, then ! 284: * we don't want to give away write permission ! 285: * on a read fault. Make the task write fault, ! 286: * so that the watchpoint code notices the access. ! 287: */ ! 288: || db_watchpoint_list ! 289: #endif /* MACH_KDB */ ! 290: ) { ! 291: /* ! 292: * If we aren't asking for write permission, ! 293: * then don't give it away. We're using write ! 294: * faults to set the dirty bit. ! 295: */ ! 296: if (!(fault_type & VM_PROT_WRITE)) ! 297: *protection &= ~VM_PROT_WRITE; ! 298: } ! 299: ! 300: if (!vm_fault_interruptible) ! 301: interruptible = FALSE; ! 302: ! 303: /* ! 304: * INVARIANTS (through entire routine): ! 305: * ! 306: * 1) At all times, we must either have the object ! 307: * lock or a busy page in some object to prevent ! 308: * some other thread from trying to bring in ! 309: * the same page. ! 310: * ! 311: * Note that we cannot hold any locks during the ! 312: * pager access or when waiting for memory, so ! 313: * we use a busy page then. ! 314: * ! 315: * Note also that we aren't as concerned about more than ! 316: * one thread attempting to memory_object_data_unlock ! 317: * the same page at once, so we don't hold the page ! 318: * as busy then, but do record the highest unlock ! 319: * value so far. [Unlock requests may also be delivered ! 320: * out of order.] ! 321: * ! 322: * 2) To prevent another thread from racing us down the ! 323: * shadow chain and entering a new page in the top ! 324: * object before we do, we must keep a busy page in ! 325: * the top object while following the shadow chain. ! 326: * ! 327: * 3) We must increment paging_in_progress on any object ! 328: * for which we have a busy page, to prevent ! 329: * vm_object_collapse from removing the busy page ! 330: * without our noticing. ! 331: * ! 332: * 4) We leave busy pages on the pageout queues. ! 333: * If the pageout daemon comes across a busy page, ! 334: * it will remove the page from the pageout queues. ! 335: */ ! 336: ! 337: /* ! 338: * Search for the page at object/offset. ! 339: */ ! 340: ! 341: object = first_object; ! 342: offset = first_offset; ! 343: first_m = VM_PAGE_NULL; ! 344: access_required = fault_type; ! 345: ! 346: /* ! 347: * See whether this page is resident ! 348: */ ! 349: ! 350: while (TRUE) { ! 351: m = vm_page_lookup(object, offset); ! 352: if (m != VM_PAGE_NULL) { ! 353: /* ! 354: * If the page is being brought in, ! 355: * wait for it and then retry. ! 356: * ! 357: * A possible optimization: if the page ! 358: * is known to be resident, we can ignore ! 359: * pages that are absent (regardless of ! 360: * whether they're busy). ! 361: */ ! 362: ! 363: if (m->busy) { ! 364: kern_return_t wait_result; ! 365: ! 366: PAGE_ASSERT_WAIT(m, interruptible); ! 367: vm_object_unlock(object); ! 368: #ifdef CONTINUATIONS ! 369: if (continuation != (void (*)()) 0) { ! 370: register vm_fault_state_t *state = ! 371: (vm_fault_state_t *) current_thread()->ith_other; ! 372: ! 373: /* ! 374: * Save variables in case ! 375: * thread_block discards ! 376: * our kernel stack. ! 377: */ ! 378: ! 379: state->vmfp_backoff = FALSE; ! 380: state->vmfp_object = object; ! 381: state->vmfp_offset = offset; ! 382: state->vmfp_first_m = first_m; ! 383: state->vmfp_access = ! 384: access_required; ! 385: state->vmf_prot = *protection; ! 386: ! 387: counter(c_vm_fault_page_block_busy_user++); ! 388: thread_block(continuation); ! 389: } else ! 390: #endif /* CONTINUATIONS */ ! 391: { ! 392: counter(c_vm_fault_page_block_busy_kernel++); ! 393: thread_block((void (*)()) 0); ! 394: } ! 395: after_thread_block: ! 396: wait_result = current_thread()->wait_result; ! 397: vm_object_lock(object); ! 398: if (wait_result != THREAD_AWAKENED) { ! 399: vm_fault_cleanup(object, first_m); ! 400: if (wait_result == THREAD_RESTART) ! 401: return(VM_FAULT_RETRY); ! 402: else ! 403: return(VM_FAULT_INTERRUPTED); ! 404: } ! 405: continue; ! 406: } ! 407: ! 408: /* ! 409: * If the page is in error, give up now. ! 410: */ ! 411: ! 412: if (m->error) { ! 413: VM_PAGE_FREE(m); ! 414: vm_fault_cleanup(object, first_m); ! 415: return(VM_FAULT_MEMORY_ERROR); ! 416: } ! 417: ! 418: /* ! 419: * If the page isn't busy, but is absent, ! 420: * then it was deemed "unavailable". ! 421: */ ! 422: ! 423: if (m->absent) { ! 424: /* ! 425: * Remove the non-existent page (unless it's ! 426: * in the top object) and move on down to the ! 427: * next object (if there is one). ! 428: */ ! 429: ! 430: offset += object->shadow_offset; ! 431: access_required = VM_PROT_READ; ! 432: next_object = object->shadow; ! 433: if (next_object == VM_OBJECT_NULL) { ! 434: vm_page_t real_m; ! 435: ! 436: assert(!must_be_resident); ! 437: ! 438: /* ! 439: * Absent page at bottom of shadow ! 440: * chain; zero fill the page we left ! 441: * busy in the first object, and flush ! 442: * the absent page. But first we ! 443: * need to allocate a real page. ! 444: */ ! 445: ! 446: real_m = vm_page_grab(!object->internal); ! 447: if (real_m == VM_PAGE_NULL) { ! 448: vm_fault_cleanup(object, first_m); ! 449: return(VM_FAULT_MEMORY_SHORTAGE); ! 450: } ! 451: ! 452: if (object != first_object) { ! 453: VM_PAGE_FREE(m); ! 454: vm_object_paging_end(object); ! 455: vm_object_unlock(object); ! 456: object = first_object; ! 457: offset = first_offset; ! 458: m = first_m; ! 459: first_m = VM_PAGE_NULL; ! 460: vm_object_lock(object); ! 461: } ! 462: ! 463: VM_PAGE_FREE(m); ! 464: assert(real_m->busy); ! 465: vm_page_lock_queues(); ! 466: vm_page_insert(real_m, object, offset); ! 467: vm_page_unlock_queues(); ! 468: m = real_m; ! 469: ! 470: /* ! 471: * Drop the lock while zero filling ! 472: * page. Then break because this ! 473: * is the page we wanted. Checking ! 474: * the page lock is a waste of time; ! 475: * this page was either absent or ! 476: * newly allocated -- in both cases ! 477: * it can't be page locked by a pager. ! 478: */ ! 479: vm_object_unlock(object); ! 480: ! 481: vm_page_zero_fill(m); ! 482: ! 483: vm_stat_sample(SAMPLED_PC_VM_ZFILL_FAULTS); ! 484: ! 485: vm_stat.zero_fill_count++; ! 486: vm_object_lock(object); ! 487: pmap_clear_modify(m->phys_addr); ! 488: break; ! 489: } else { ! 490: if (must_be_resident) { ! 491: vm_object_paging_end(object); ! 492: } else if (object != first_object) { ! 493: vm_object_paging_end(object); ! 494: VM_PAGE_FREE(m); ! 495: } else { ! 496: first_m = m; ! 497: m->absent = FALSE; ! 498: vm_object_absent_release(object); ! 499: m->busy = TRUE; ! 500: ! 501: vm_page_lock_queues(); ! 502: VM_PAGE_QUEUES_REMOVE(m); ! 503: vm_page_unlock_queues(); ! 504: } ! 505: vm_object_lock(next_object); ! 506: vm_object_unlock(object); ! 507: object = next_object; ! 508: vm_object_paging_begin(object); ! 509: continue; ! 510: } ! 511: } ! 512: ! 513: /* ! 514: * If the desired access to this page has ! 515: * been locked out, request that it be unlocked. ! 516: */ ! 517: ! 518: if (access_required & m->page_lock) { ! 519: if ((access_required & m->unlock_request) != access_required) { ! 520: vm_prot_t new_unlock_request; ! 521: kern_return_t rc; ! 522: ! 523: if (!object->pager_ready) { ! 524: vm_object_assert_wait(object, ! 525: VM_OBJECT_EVENT_PAGER_READY, ! 526: interruptible); ! 527: goto block_and_backoff; ! 528: } ! 529: ! 530: new_unlock_request = m->unlock_request = ! 531: (access_required | m->unlock_request); ! 532: vm_object_unlock(object); ! 533: if ((rc = memory_object_data_unlock( ! 534: object->pager, ! 535: object->pager_request, ! 536: offset + object->paging_offset, ! 537: PAGE_SIZE, ! 538: new_unlock_request)) ! 539: != KERN_SUCCESS) { ! 540: printf("vm_fault: memory_object_data_unlock failed\n"); ! 541: vm_object_lock(object); ! 542: vm_fault_cleanup(object, first_m); ! 543: return((rc == MACH_SEND_INTERRUPTED) ? ! 544: VM_FAULT_INTERRUPTED : ! 545: VM_FAULT_MEMORY_ERROR); ! 546: } ! 547: vm_object_lock(object); ! 548: continue; ! 549: } ! 550: ! 551: PAGE_ASSERT_WAIT(m, interruptible); ! 552: goto block_and_backoff; ! 553: } ! 554: ! 555: /* ! 556: * We mark the page busy and leave it on ! 557: * the pageout queues. If the pageout ! 558: * deamon comes across it, then it will ! 559: * remove the page. ! 560: */ ! 561: ! 562: if (!software_reference_bits) { ! 563: vm_page_lock_queues(); ! 564: if (m->inactive) { ! 565: vm_stat_sample(SAMPLED_PC_VM_REACTIVATION_FAULTS); ! 566: vm_stat.reactivations++; ! 567: } ! 568: ! 569: VM_PAGE_QUEUES_REMOVE(m); ! 570: vm_page_unlock_queues(); ! 571: } ! 572: ! 573: assert(!m->busy); ! 574: m->busy = TRUE; ! 575: assert(!m->absent); ! 576: break; ! 577: } ! 578: ! 579: look_for_page = ! 580: (object->pager_created) ! 581: #if MACH_PAGEMAP ! 582: && (vm_external_state_get(object->existence_info, offset + object->paging_offset) != ! 583: VM_EXTERNAL_STATE_ABSENT) ! 584: #endif /* MACH_PAGEMAP */ ! 585: ; ! 586: ! 587: if ((look_for_page || (object == first_object)) ! 588: && !must_be_resident) { ! 589: /* ! 590: * Allocate a new page for this object/offset ! 591: * pair. ! 592: */ ! 593: ! 594: m = vm_page_grab_fictitious(); ! 595: if (m == VM_PAGE_NULL) { ! 596: vm_fault_cleanup(object, first_m); ! 597: return(VM_FAULT_FICTITIOUS_SHORTAGE); ! 598: } ! 599: ! 600: vm_page_lock_queues(); ! 601: vm_page_insert(m, object, offset); ! 602: vm_page_unlock_queues(); ! 603: } ! 604: ! 605: if (look_for_page && !must_be_resident) { ! 606: kern_return_t rc; ! 607: ! 608: /* ! 609: * If the memory manager is not ready, we ! 610: * cannot make requests. ! 611: */ ! 612: if (!object->pager_ready) { ! 613: vm_object_assert_wait(object, ! 614: VM_OBJECT_EVENT_PAGER_READY, ! 615: interruptible); ! 616: VM_PAGE_FREE(m); ! 617: goto block_and_backoff; ! 618: } ! 619: ! 620: if (object->internal) { ! 621: /* ! 622: * Requests to the default pager ! 623: * must reserve a real page in advance, ! 624: * because the pager's data-provided ! 625: * won't block for pages. ! 626: */ ! 627: ! 628: if (m->fictitious && !vm_page_convert(m, FALSE)) { ! 629: VM_PAGE_FREE(m); ! 630: vm_fault_cleanup(object, first_m); ! 631: return(VM_FAULT_MEMORY_SHORTAGE); ! 632: } ! 633: } else if (object->absent_count > ! 634: vm_object_absent_max) { ! 635: /* ! 636: * If there are too many outstanding page ! 637: * requests pending on this object, we ! 638: * wait for them to be resolved now. ! 639: */ ! 640: ! 641: vm_object_absent_assert_wait(object, interruptible); ! 642: VM_PAGE_FREE(m); ! 643: goto block_and_backoff; ! 644: } ! 645: ! 646: /* ! 647: * Indicate that the page is waiting for data ! 648: * from the memory manager. ! 649: */ ! 650: ! 651: m->absent = TRUE; ! 652: object->absent_count++; ! 653: ! 654: /* ! 655: * We have a busy page, so we can ! 656: * release the object lock. ! 657: */ ! 658: vm_object_unlock(object); ! 659: ! 660: /* ! 661: * Call the memory manager to retrieve the data. ! 662: */ ! 663: ! 664: vm_stat.pageins++; ! 665: vm_stat_sample(SAMPLED_PC_VM_PAGEIN_FAULTS); ! 666: ! 667: if ((rc = memory_object_data_request(object->pager, ! 668: object->pager_request, ! 669: m->offset + object->paging_offset, ! 670: PAGE_SIZE, access_required)) != KERN_SUCCESS) { ! 671: if (rc != MACH_SEND_INTERRUPTED) ! 672: printf("%s(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) failed, %d\n", ! 673: "memory_object_data_request", ! 674: object->pager, ! 675: object->pager_request, ! 676: m->offset + object->paging_offset, ! 677: PAGE_SIZE, access_required, rc); ! 678: /* ! 679: * Don't want to leave a busy page around, ! 680: * but the data request may have blocked, ! 681: * so check if it's still there and busy. ! 682: */ ! 683: vm_object_lock(object); ! 684: if (m == vm_page_lookup(object,offset) && ! 685: m->absent && m->busy) ! 686: VM_PAGE_FREE(m); ! 687: vm_fault_cleanup(object, first_m); ! 688: return((rc == MACH_SEND_INTERRUPTED) ? ! 689: VM_FAULT_INTERRUPTED : ! 690: VM_FAULT_MEMORY_ERROR); ! 691: } ! 692: ! 693: /* ! 694: * Retry with same object/offset, since new data may ! 695: * be in a different page (i.e., m is meaningless at ! 696: * this point). ! 697: */ ! 698: vm_object_lock(object); ! 699: continue; ! 700: } ! 701: ! 702: /* ! 703: * For the XP system, the only case in which we get here is if ! 704: * object has no pager (or unwiring). If the pager doesn't ! 705: * have the page this is handled in the m->absent case above ! 706: * (and if you change things here you should look above). ! 707: */ ! 708: if (object == first_object) ! 709: first_m = m; ! 710: else ! 711: { ! 712: assert(m == VM_PAGE_NULL); ! 713: } ! 714: ! 715: /* ! 716: * Move on to the next object. Lock the next ! 717: * object before unlocking the current one. ! 718: */ ! 719: access_required = VM_PROT_READ; ! 720: ! 721: offset += object->shadow_offset; ! 722: next_object = object->shadow; ! 723: if (next_object == VM_OBJECT_NULL) { ! 724: assert(!must_be_resident); ! 725: ! 726: /* ! 727: * If there's no object left, fill the page ! 728: * in the top object with zeros. But first we ! 729: * need to allocate a real page. ! 730: */ ! 731: ! 732: if (object != first_object) { ! 733: vm_object_paging_end(object); ! 734: vm_object_unlock(object); ! 735: ! 736: object = first_object; ! 737: offset = first_offset; ! 738: vm_object_lock(object); ! 739: } ! 740: ! 741: m = first_m; ! 742: assert(m->object == object); ! 743: first_m = VM_PAGE_NULL; ! 744: ! 745: if (m->fictitious && !vm_page_convert(m, !object->internal)) { ! 746: VM_PAGE_FREE(m); ! 747: vm_fault_cleanup(object, VM_PAGE_NULL); ! 748: return(VM_FAULT_MEMORY_SHORTAGE); ! 749: } ! 750: ! 751: vm_object_unlock(object); ! 752: vm_page_zero_fill(m); ! 753: vm_stat_sample(SAMPLED_PC_VM_ZFILL_FAULTS); ! 754: vm_stat.zero_fill_count++; ! 755: vm_object_lock(object); ! 756: pmap_clear_modify(m->phys_addr); ! 757: break; ! 758: } ! 759: else { ! 760: vm_object_lock(next_object); ! 761: if ((object != first_object) || must_be_resident) ! 762: vm_object_paging_end(object); ! 763: vm_object_unlock(object); ! 764: object = next_object; ! 765: vm_object_paging_begin(object); ! 766: } ! 767: } ! 768: ! 769: /* ! 770: * PAGE HAS BEEN FOUND. ! 771: * ! 772: * This page (m) is: ! 773: * busy, so that we can play with it; ! 774: * not absent, so that nobody else will fill it; ! 775: * possibly eligible for pageout; ! 776: * ! 777: * The top-level page (first_m) is: ! 778: * VM_PAGE_NULL if the page was found in the ! 779: * top-level object; ! 780: * busy, not absent, and ineligible for pageout. ! 781: * ! 782: * The current object (object) is locked. A paging ! 783: * reference is held for the current and top-level ! 784: * objects. ! 785: */ ! 786: ! 787: #if EXTRA_ASSERTIONS ! 788: assert(m->busy && !m->absent); ! 789: assert((first_m == VM_PAGE_NULL) || ! 790: (first_m->busy && !first_m->absent && ! 791: !first_m->active && !first_m->inactive)); ! 792: #endif /* EXTRA_ASSERTIONS */ ! 793: ! 794: /* ! 795: * If the page is being written, but isn't ! 796: * already owned by the top-level object, ! 797: * we have to copy it into a new page owned ! 798: * by the top-level object. ! 799: */ ! 800: ! 801: if (object != first_object) { ! 802: /* ! 803: * We only really need to copy if we ! 804: * want to write it. ! 805: */ ! 806: ! 807: if (fault_type & VM_PROT_WRITE) { ! 808: vm_page_t copy_m; ! 809: ! 810: assert(!must_be_resident); ! 811: ! 812: /* ! 813: * If we try to collapse first_object at this ! 814: * point, we may deadlock when we try to get ! 815: * the lock on an intermediate object (since we ! 816: * have the bottom object locked). We can't ! 817: * unlock the bottom object, because the page ! 818: * we found may move (by collapse) if we do. ! 819: * ! 820: * Instead, we first copy the page. Then, when ! 821: * we have no more use for the bottom object, ! 822: * we unlock it and try to collapse. ! 823: * ! 824: * Note that we copy the page even if we didn't ! 825: * need to... that's the breaks. ! 826: */ ! 827: ! 828: /* ! 829: * Allocate a page for the copy ! 830: */ ! 831: copy_m = vm_page_grab(!first_object->internal); ! 832: if (copy_m == VM_PAGE_NULL) { ! 833: RELEASE_PAGE(m); ! 834: vm_fault_cleanup(object, first_m); ! 835: return(VM_FAULT_MEMORY_SHORTAGE); ! 836: } ! 837: ! 838: vm_object_unlock(object); ! 839: vm_page_copy(m, copy_m); ! 840: vm_object_lock(object); ! 841: ! 842: /* ! 843: * If another map is truly sharing this ! 844: * page with us, we have to flush all ! 845: * uses of the original page, since we ! 846: * can't distinguish those which want the ! 847: * original from those which need the ! 848: * new copy. ! 849: * ! 850: * XXXO If we know that only one map has ! 851: * access to this page, then we could ! 852: * avoid the pmap_page_protect() call. ! 853: */ ! 854: ! 855: vm_page_lock_queues(); ! 856: vm_page_deactivate(m); ! 857: pmap_page_protect(m->phys_addr, VM_PROT_NONE); ! 858: vm_page_unlock_queues(); ! 859: ! 860: /* ! 861: * We no longer need the old page or object. ! 862: */ ! 863: ! 864: PAGE_WAKEUP_DONE(m); ! 865: vm_object_paging_end(object); ! 866: vm_object_unlock(object); ! 867: ! 868: vm_stat.cow_faults++; ! 869: vm_stat_sample(SAMPLED_PC_VM_COW_FAULTS); ! 870: object = first_object; ! 871: offset = first_offset; ! 872: ! 873: vm_object_lock(object); ! 874: VM_PAGE_FREE(first_m); ! 875: first_m = VM_PAGE_NULL; ! 876: assert(copy_m->busy); ! 877: vm_page_lock_queues(); ! 878: vm_page_insert(copy_m, object, offset); ! 879: vm_page_unlock_queues(); ! 880: m = copy_m; ! 881: ! 882: /* ! 883: * Now that we've gotten the copy out of the ! 884: * way, let's try to collapse the top object. ! 885: * But we have to play ugly games with ! 886: * paging_in_progress to do that... ! 887: */ ! 888: ! 889: vm_object_paging_end(object); ! 890: vm_object_collapse(object); ! 891: vm_object_paging_begin(object); ! 892: } ! 893: else { ! 894: *protection &= (~VM_PROT_WRITE); ! 895: } ! 896: } ! 897: ! 898: /* ! 899: * Now check whether the page needs to be pushed into the ! 900: * copy object. The use of asymmetric copy on write for ! 901: * shared temporary objects means that we may do two copies to ! 902: * satisfy the fault; one above to get the page from a ! 903: * shadowed object, and one here to push it into the copy. ! 904: */ ! 905: ! 906: while ((copy_object = first_object->copy) != VM_OBJECT_NULL) { ! 907: vm_offset_t copy_offset; ! 908: vm_page_t copy_m; ! 909: ! 910: /* ! 911: * If the page is being written, but hasn't been ! 912: * copied to the copy-object, we have to copy it there. ! 913: */ ! 914: ! 915: if ((fault_type & VM_PROT_WRITE) == 0) { ! 916: *protection &= ~VM_PROT_WRITE; ! 917: break; ! 918: } ! 919: ! 920: /* ! 921: * If the page was guaranteed to be resident, ! 922: * we must have already performed the copy. ! 923: */ ! 924: ! 925: if (must_be_resident) ! 926: break; ! 927: ! 928: /* ! 929: * Try to get the lock on the copy_object. ! 930: */ ! 931: if (!vm_object_lock_try(copy_object)) { ! 932: vm_object_unlock(object); ! 933: ! 934: simple_lock_pause(); /* wait a bit */ ! 935: ! 936: vm_object_lock(object); ! 937: continue; ! 938: } ! 939: ! 940: /* ! 941: * Make another reference to the copy-object, ! 942: * to keep it from disappearing during the ! 943: * copy. ! 944: */ ! 945: assert(copy_object->ref_count > 0); ! 946: copy_object->ref_count++; ! 947: ! 948: /* ! 949: * Does the page exist in the copy? ! 950: */ ! 951: copy_offset = first_offset - copy_object->shadow_offset; ! 952: copy_m = vm_page_lookup(copy_object, copy_offset); ! 953: if (copy_m != VM_PAGE_NULL) { ! 954: if (copy_m->busy) { ! 955: /* ! 956: * If the page is being brought ! 957: * in, wait for it and then retry. ! 958: */ ! 959: PAGE_ASSERT_WAIT(copy_m, interruptible); ! 960: RELEASE_PAGE(m); ! 961: copy_object->ref_count--; ! 962: assert(copy_object->ref_count > 0); ! 963: vm_object_unlock(copy_object); ! 964: goto block_and_backoff; ! 965: } ! 966: } ! 967: else { ! 968: /* ! 969: * Allocate a page for the copy ! 970: */ ! 971: copy_m = vm_page_alloc(copy_object, copy_offset); ! 972: if (copy_m == VM_PAGE_NULL) { ! 973: RELEASE_PAGE(m); ! 974: copy_object->ref_count--; ! 975: assert(copy_object->ref_count > 0); ! 976: vm_object_unlock(copy_object); ! 977: vm_fault_cleanup(object, first_m); ! 978: return(VM_FAULT_MEMORY_SHORTAGE); ! 979: } ! 980: ! 981: /* ! 982: * Must copy page into copy-object. ! 983: */ ! 984: ! 985: vm_page_copy(m, copy_m); ! 986: ! 987: /* ! 988: * If the old page was in use by any users ! 989: * of the copy-object, it must be removed ! 990: * from all pmaps. (We can't know which ! 991: * pmaps use it.) ! 992: */ ! 993: ! 994: vm_page_lock_queues(); ! 995: pmap_page_protect(m->phys_addr, VM_PROT_NONE); ! 996: copy_m->dirty = TRUE; ! 997: vm_page_unlock_queues(); ! 998: ! 999: /* ! 1000: * If there's a pager, then immediately ! 1001: * page out this page, using the "initialize" ! 1002: * option. Else, we use the copy. ! 1003: */ ! 1004: ! 1005: if (!copy_object->pager_created) { ! 1006: vm_page_lock_queues(); ! 1007: vm_page_activate(copy_m); ! 1008: vm_page_unlock_queues(); ! 1009: PAGE_WAKEUP_DONE(copy_m); ! 1010: } else { ! 1011: /* ! 1012: * The page is already ready for pageout: ! 1013: * not on pageout queues and busy. ! 1014: * Unlock everything except the ! 1015: * copy_object itself. ! 1016: */ ! 1017: ! 1018: vm_object_unlock(object); ! 1019: ! 1020: /* ! 1021: * Write the page to the copy-object, ! 1022: * flushing it from the kernel. ! 1023: */ ! 1024: ! 1025: vm_pageout_page(copy_m, TRUE, TRUE); ! 1026: ! 1027: /* ! 1028: * Since the pageout may have ! 1029: * temporarily dropped the ! 1030: * copy_object's lock, we ! 1031: * check whether we'll have ! 1032: * to deallocate the hard way. ! 1033: */ ! 1034: ! 1035: if ((copy_object->shadow != object) || ! 1036: (copy_object->ref_count == 1)) { ! 1037: vm_object_unlock(copy_object); ! 1038: vm_object_deallocate(copy_object); ! 1039: vm_object_lock(object); ! 1040: continue; ! 1041: } ! 1042: ! 1043: /* ! 1044: * Pick back up the old object's ! 1045: * lock. [It is safe to do so, ! 1046: * since it must be deeper in the ! 1047: * object tree.] ! 1048: */ ! 1049: ! 1050: vm_object_lock(object); ! 1051: } ! 1052: ! 1053: /* ! 1054: * Because we're pushing a page upward ! 1055: * in the object tree, we must restart ! 1056: * any faults that are waiting here. ! 1057: * [Note that this is an expansion of ! 1058: * PAGE_WAKEUP that uses the THREAD_RESTART ! 1059: * wait result]. Can't turn off the page's ! 1060: * busy bit because we're not done with it. ! 1061: */ ! 1062: ! 1063: if (m->wanted) { ! 1064: m->wanted = FALSE; ! 1065: thread_wakeup_with_result((event_t) m, ! 1066: THREAD_RESTART); ! 1067: } ! 1068: } ! 1069: ! 1070: /* ! 1071: * The reference count on copy_object must be ! 1072: * at least 2: one for our extra reference, ! 1073: * and at least one from the outside world ! 1074: * (we checked that when we last locked ! 1075: * copy_object). ! 1076: */ ! 1077: copy_object->ref_count--; ! 1078: assert(copy_object->ref_count > 0); ! 1079: vm_object_unlock(copy_object); ! 1080: ! 1081: break; ! 1082: } ! 1083: ! 1084: *result_page = m; ! 1085: *top_page = first_m; ! 1086: ! 1087: /* ! 1088: * If the page can be written, assume that it will be. ! 1089: * [Earlier, we restrict the permission to allow write ! 1090: * access only if the fault so required, so we don't ! 1091: * mark read-only data as dirty.] ! 1092: */ ! 1093: ! 1094: if (vm_fault_dirty_handling && (*protection & VM_PROT_WRITE)) ! 1095: m->dirty = TRUE; ! 1096: ! 1097: return(VM_FAULT_SUCCESS); ! 1098: ! 1099: block_and_backoff: ! 1100: vm_fault_cleanup(object, first_m); ! 1101: ! 1102: #ifdef CONTINUATIONS ! 1103: if (continuation != (void (*)()) 0) { ! 1104: register vm_fault_state_t *state = ! 1105: (vm_fault_state_t *) current_thread()->ith_other; ! 1106: ! 1107: /* ! 1108: * Save variables in case we must restart. ! 1109: */ ! 1110: ! 1111: state->vmfp_backoff = TRUE; ! 1112: state->vmf_prot = *protection; ! 1113: ! 1114: counter(c_vm_fault_page_block_backoff_user++); ! 1115: thread_block(continuation); ! 1116: } else ! 1117: #endif /* CONTINUATIONS */ ! 1118: { ! 1119: counter(c_vm_fault_page_block_backoff_kernel++); ! 1120: thread_block((void (*)()) 0); ! 1121: } ! 1122: after_block_and_backoff: ! 1123: if (current_thread()->wait_result == THREAD_AWAKENED) ! 1124: return VM_FAULT_RETRY; ! 1125: else ! 1126: return VM_FAULT_INTERRUPTED; ! 1127: ! 1128: #undef RELEASE_PAGE ! 1129: } ! 1130: ! 1131: /* ! 1132: * Routine: vm_fault ! 1133: * Purpose: ! 1134: * Handle page faults, including pseudo-faults ! 1135: * used to change the wiring status of pages. ! 1136: * Returns: ! 1137: * If an explicit (expression) continuation is supplied, ! 1138: * then we call the continuation instead of returning. ! 1139: * Implementation: ! 1140: * Explicit continuations make this a little icky, ! 1141: * because it hasn't been rewritten to embrace CPS. ! 1142: * Instead, we have resume arguments for vm_fault and ! 1143: * vm_fault_page, to let continue the fault computation. ! 1144: * ! 1145: * vm_fault and vm_fault_page save mucho state ! 1146: * in the moral equivalent of a closure. The state ! 1147: * structure is allocated when first entering vm_fault ! 1148: * and deallocated when leaving vm_fault. ! 1149: */ ! 1150: ! 1151: #ifdef CONTINUATIONS ! 1152: void ! 1153: vm_fault_continue() ! 1154: { ! 1155: register vm_fault_state_t *state = ! 1156: (vm_fault_state_t *) current_thread()->ith_other; ! 1157: ! 1158: (void) vm_fault(state->vmf_map, ! 1159: state->vmf_vaddr, ! 1160: state->vmf_fault_type, ! 1161: state->vmf_change_wiring, ! 1162: TRUE, state->vmf_continuation); ! 1163: /*NOTREACHED*/ ! 1164: } ! 1165: #endif /* CONTINUATIONS */ ! 1166: ! 1167: kern_return_t vm_fault(map, vaddr, fault_type, change_wiring, ! 1168: resume, continuation) ! 1169: vm_map_t map; ! 1170: vm_offset_t vaddr; ! 1171: vm_prot_t fault_type; ! 1172: boolean_t change_wiring; ! 1173: boolean_t resume; ! 1174: void (*continuation)(); ! 1175: { ! 1176: vm_map_version_t version; /* Map version for verificiation */ ! 1177: boolean_t wired; /* Should mapping be wired down? */ ! 1178: vm_object_t object; /* Top-level object */ ! 1179: vm_offset_t offset; /* Top-level offset */ ! 1180: vm_prot_t prot; /* Protection for mapping */ ! 1181: vm_object_t old_copy_object; /* Saved copy object */ ! 1182: vm_page_t result_page; /* Result of vm_fault_page */ ! 1183: vm_page_t top_page; /* Placeholder page */ ! 1184: kern_return_t kr; ! 1185: ! 1186: register ! 1187: vm_page_t m; /* Fast access to result_page */ ! 1188: ! 1189: #ifdef CONTINUATIONS ! 1190: if (resume) { ! 1191: register vm_fault_state_t *state = ! 1192: (vm_fault_state_t *) current_thread()->ith_other; ! 1193: ! 1194: /* ! 1195: * Retrieve cached variables and ! 1196: * continue vm_fault_page. ! 1197: */ ! 1198: ! 1199: object = state->vmf_object; ! 1200: if (object == VM_OBJECT_NULL) ! 1201: goto RetryFault; ! 1202: version = state->vmf_version; ! 1203: wired = state->vmf_wired; ! 1204: offset = state->vmf_offset; ! 1205: prot = state->vmf_prot; ! 1206: ! 1207: kr = vm_fault_page(object, offset, fault_type, ! 1208: (change_wiring && !wired), !change_wiring, ! 1209: &prot, &result_page, &top_page, ! 1210: TRUE, vm_fault_continue); ! 1211: goto after_vm_fault_page; ! 1212: } ! 1213: ! 1214: if (continuation != (void (*)()) 0) { ! 1215: /* ! 1216: * We will probably need to save state. ! 1217: */ ! 1218: ! 1219: char * state; ! 1220: ! 1221: /* ! 1222: * if this assignment stmt is written as ! 1223: * 'active_threads[cpu_number()] = zalloc()', ! 1224: * cpu_number may be evaluated before zalloc; ! 1225: * if zalloc blocks, cpu_number will be wrong ! 1226: */ ! 1227: ! 1228: state = (char *) zalloc(vm_fault_state_zone); ! 1229: current_thread()->ith_other = state; ! 1230: ! 1231: } ! 1232: #else /* not CONTINUATIONS */ ! 1233: assert(continuation == 0); ! 1234: assert(!resume); ! 1235: #endif /* not CONTINUATIONS */ ! 1236: ! 1237: RetryFault: ; ! 1238: ! 1239: /* ! 1240: * Find the backing store object and offset into ! 1241: * it to begin the search. ! 1242: */ ! 1243: ! 1244: if ((kr = vm_map_lookup(&map, vaddr, fault_type, &version, ! 1245: &object, &offset, ! 1246: &prot, &wired)) != KERN_SUCCESS) { ! 1247: goto done; ! 1248: } ! 1249: ! 1250: /* ! 1251: * If the page is wired, we must fault for the current protection ! 1252: * value, to avoid further faults. ! 1253: */ ! 1254: ! 1255: if (wired) ! 1256: fault_type = prot; ! 1257: ! 1258: /* ! 1259: * Make a reference to this object to ! 1260: * prevent its disposal while we are messing with ! 1261: * it. Once we have the reference, the map is free ! 1262: * to be diddled. Since objects reference their ! 1263: * shadows (and copies), they will stay around as well. ! 1264: */ ! 1265: ! 1266: assert(object->ref_count > 0); ! 1267: object->ref_count++; ! 1268: vm_object_paging_begin(object); ! 1269: ! 1270: #ifdef CONTINUATIONS ! 1271: if (continuation != (void (*)()) 0) { ! 1272: register vm_fault_state_t *state = ! 1273: (vm_fault_state_t *) current_thread()->ith_other; ! 1274: ! 1275: /* ! 1276: * Save variables, in case vm_fault_page discards ! 1277: * our kernel stack and we have to restart. ! 1278: */ ! 1279: ! 1280: state->vmf_map = map; ! 1281: state->vmf_vaddr = vaddr; ! 1282: state->vmf_fault_type = fault_type; ! 1283: state->vmf_change_wiring = change_wiring; ! 1284: state->vmf_continuation = continuation; ! 1285: ! 1286: state->vmf_version = version; ! 1287: state->vmf_wired = wired; ! 1288: state->vmf_object = object; ! 1289: state->vmf_offset = offset; ! 1290: state->vmf_prot = prot; ! 1291: ! 1292: kr = vm_fault_page(object, offset, fault_type, ! 1293: (change_wiring && !wired), !change_wiring, ! 1294: &prot, &result_page, &top_page, ! 1295: FALSE, vm_fault_continue); ! 1296: } else ! 1297: #endif /* CONTINUATIONS */ ! 1298: { ! 1299: kr = vm_fault_page(object, offset, fault_type, ! 1300: (change_wiring && !wired), !change_wiring, ! 1301: &prot, &result_page, &top_page, ! 1302: FALSE, (void (*)()) 0); ! 1303: } ! 1304: after_vm_fault_page: ! 1305: ! 1306: /* ! 1307: * If we didn't succeed, lose the object reference immediately. ! 1308: */ ! 1309: ! 1310: if (kr != VM_FAULT_SUCCESS) ! 1311: vm_object_deallocate(object); ! 1312: ! 1313: /* ! 1314: * See why we failed, and take corrective action. ! 1315: */ ! 1316: ! 1317: switch (kr) { ! 1318: case VM_FAULT_SUCCESS: ! 1319: break; ! 1320: case VM_FAULT_RETRY: ! 1321: goto RetryFault; ! 1322: case VM_FAULT_INTERRUPTED: ! 1323: kr = KERN_SUCCESS; ! 1324: goto done; ! 1325: case VM_FAULT_MEMORY_SHORTAGE: ! 1326: #ifdef CONTINUATIONS ! 1327: if (continuation != (void (*)()) 0) { ! 1328: register vm_fault_state_t *state = ! 1329: (vm_fault_state_t *) current_thread()->ith_other; ! 1330: ! 1331: /* ! 1332: * Save variables in case VM_PAGE_WAIT ! 1333: * discards our kernel stack. ! 1334: */ ! 1335: ! 1336: state->vmf_map = map; ! 1337: state->vmf_vaddr = vaddr; ! 1338: state->vmf_fault_type = fault_type; ! 1339: state->vmf_change_wiring = change_wiring; ! 1340: state->vmf_continuation = continuation; ! 1341: state->vmf_object = VM_OBJECT_NULL; ! 1342: ! 1343: VM_PAGE_WAIT(vm_fault_continue); ! 1344: } else ! 1345: #endif /* CONTINUATIONS */ ! 1346: VM_PAGE_WAIT((void (*)()) 0); ! 1347: goto RetryFault; ! 1348: case VM_FAULT_FICTITIOUS_SHORTAGE: ! 1349: vm_page_more_fictitious(); ! 1350: goto RetryFault; ! 1351: case VM_FAULT_MEMORY_ERROR: ! 1352: kr = KERN_MEMORY_ERROR; ! 1353: goto done; ! 1354: } ! 1355: ! 1356: m = result_page; ! 1357: ! 1358: assert((change_wiring && !wired) ? ! 1359: (top_page == VM_PAGE_NULL) : ! 1360: ((top_page == VM_PAGE_NULL) == (m->object == object))); ! 1361: ! 1362: /* ! 1363: * How to clean up the result of vm_fault_page. This ! 1364: * happens whether the mapping is entered or not. ! 1365: */ ! 1366: ! 1367: #define UNLOCK_AND_DEALLOCATE \ ! 1368: MACRO_BEGIN \ ! 1369: vm_fault_cleanup(m->object, top_page); \ ! 1370: vm_object_deallocate(object); \ ! 1371: MACRO_END ! 1372: ! 1373: /* ! 1374: * What to do with the resulting page from vm_fault_page ! 1375: * if it doesn't get entered into the physical map: ! 1376: */ ! 1377: ! 1378: #define RELEASE_PAGE(m) \ ! 1379: MACRO_BEGIN \ ! 1380: PAGE_WAKEUP_DONE(m); \ ! 1381: vm_page_lock_queues(); \ ! 1382: if (!m->active && !m->inactive) \ ! 1383: vm_page_activate(m); \ ! 1384: vm_page_unlock_queues(); \ ! 1385: MACRO_END ! 1386: ! 1387: /* ! 1388: * We must verify that the maps have not changed ! 1389: * since our last lookup. ! 1390: */ ! 1391: ! 1392: old_copy_object = m->object->copy; ! 1393: ! 1394: vm_object_unlock(m->object); ! 1395: while (!vm_map_verify(map, &version)) { ! 1396: vm_object_t retry_object; ! 1397: vm_offset_t retry_offset; ! 1398: vm_prot_t retry_prot; ! 1399: ! 1400: /* ! 1401: * To avoid trying to write_lock the map while another ! 1402: * thread has it read_locked (in vm_map_pageable), we ! 1403: * do not try for write permission. If the page is ! 1404: * still writable, we will get write permission. If it ! 1405: * is not, or has been marked needs_copy, we enter the ! 1406: * mapping without write permission, and will merely ! 1407: * take another fault. ! 1408: */ ! 1409: kr = vm_map_lookup(&map, vaddr, ! 1410: fault_type & ~VM_PROT_WRITE, &version, ! 1411: &retry_object, &retry_offset, &retry_prot, ! 1412: &wired); ! 1413: ! 1414: if (kr != KERN_SUCCESS) { ! 1415: vm_object_lock(m->object); ! 1416: RELEASE_PAGE(m); ! 1417: UNLOCK_AND_DEALLOCATE; ! 1418: goto done; ! 1419: } ! 1420: ! 1421: vm_object_unlock(retry_object); ! 1422: vm_object_lock(m->object); ! 1423: ! 1424: if ((retry_object != object) || ! 1425: (retry_offset != offset)) { ! 1426: RELEASE_PAGE(m); ! 1427: UNLOCK_AND_DEALLOCATE; ! 1428: goto RetryFault; ! 1429: } ! 1430: ! 1431: /* ! 1432: * Check whether the protection has changed or the object ! 1433: * has been copied while we left the map unlocked. ! 1434: */ ! 1435: prot &= retry_prot; ! 1436: vm_object_unlock(m->object); ! 1437: } ! 1438: vm_object_lock(m->object); ! 1439: ! 1440: /* ! 1441: * If the copy object changed while the top-level object ! 1442: * was unlocked, then we must take away write permission. ! 1443: */ ! 1444: ! 1445: if (m->object->copy != old_copy_object) ! 1446: prot &= ~VM_PROT_WRITE; ! 1447: ! 1448: /* ! 1449: * If we want to wire down this page, but no longer have ! 1450: * adequate permissions, we must start all over. ! 1451: */ ! 1452: ! 1453: if (wired && (prot != fault_type)) { ! 1454: vm_map_verify_done(map, &version); ! 1455: RELEASE_PAGE(m); ! 1456: UNLOCK_AND_DEALLOCATE; ! 1457: goto RetryFault; ! 1458: } ! 1459: ! 1460: /* ! 1461: * It's critically important that a wired-down page be faulted ! 1462: * only once in each map for which it is wired. ! 1463: */ ! 1464: ! 1465: vm_object_unlock(m->object); ! 1466: ! 1467: /* ! 1468: * Put this page into the physical map. ! 1469: * We had to do the unlock above because pmap_enter ! 1470: * may cause other faults. The page may be on ! 1471: * the pageout queues. If the pageout daemon comes ! 1472: * across the page, it will remove it from the queues. ! 1473: */ ! 1474: ! 1475: PMAP_ENTER(map->pmap, vaddr, m, prot, wired); ! 1476: ! 1477: /* ! 1478: * If the page is not wired down and isn't already ! 1479: * on a pageout queue, then put it where the ! 1480: * pageout daemon can find it. ! 1481: */ ! 1482: vm_object_lock(m->object); ! 1483: vm_page_lock_queues(); ! 1484: if (change_wiring) { ! 1485: if (wired) ! 1486: vm_page_wire(m); ! 1487: else ! 1488: vm_page_unwire(m); ! 1489: } else if (software_reference_bits) { ! 1490: if (!m->active && !m->inactive) ! 1491: vm_page_activate(m); ! 1492: m->reference = TRUE; ! 1493: } else { ! 1494: vm_page_activate(m); ! 1495: } ! 1496: vm_page_unlock_queues(); ! 1497: ! 1498: /* ! 1499: * Unlock everything, and return ! 1500: */ ! 1501: ! 1502: vm_map_verify_done(map, &version); ! 1503: PAGE_WAKEUP_DONE(m); ! 1504: kr = KERN_SUCCESS; ! 1505: UNLOCK_AND_DEALLOCATE; ! 1506: ! 1507: #undef UNLOCK_AND_DEALLOCATE ! 1508: #undef RELEASE_PAGE ! 1509: ! 1510: done: ! 1511: #ifdef CONTINUATIONS ! 1512: if (continuation != (void (*)()) 0) { ! 1513: register vm_fault_state_t *state = ! 1514: (vm_fault_state_t *) current_thread()->ith_other; ! 1515: ! 1516: zfree(vm_fault_state_zone, (vm_offset_t) state); ! 1517: (*continuation)(kr); ! 1518: /*NOTREACHED*/ ! 1519: } ! 1520: #endif /* CONTINUATIONS */ ! 1521: ! 1522: return(kr); ! 1523: } ! 1524: ! 1525: kern_return_t vm_fault_wire_fast(); ! 1526: ! 1527: /* ! 1528: * vm_fault_wire: ! 1529: * ! 1530: * Wire down a range of virtual addresses in a map. ! 1531: */ ! 1532: void vm_fault_wire(map, entry) ! 1533: vm_map_t map; ! 1534: vm_map_entry_t entry; ! 1535: { ! 1536: ! 1537: register vm_offset_t va; ! 1538: register pmap_t pmap; ! 1539: register vm_offset_t end_addr = entry->vme_end; ! 1540: ! 1541: pmap = vm_map_pmap(map); ! 1542: ! 1543: /* ! 1544: * Inform the physical mapping system that the ! 1545: * range of addresses may not fault, so that ! 1546: * page tables and such can be locked down as well. ! 1547: */ ! 1548: ! 1549: pmap_pageable(pmap, entry->vme_start, end_addr, FALSE); ! 1550: ! 1551: /* ! 1552: * We simulate a fault to get the page and enter it ! 1553: * in the physical map. ! 1554: */ ! 1555: ! 1556: for (va = entry->vme_start; va < end_addr; va += PAGE_SIZE) { ! 1557: if (vm_fault_wire_fast(map, va, entry) != KERN_SUCCESS) ! 1558: (void) vm_fault(map, va, VM_PROT_NONE, TRUE, ! 1559: FALSE, (void (*)()) 0); ! 1560: } ! 1561: } ! 1562: ! 1563: /* ! 1564: * vm_fault_unwire: ! 1565: * ! 1566: * Unwire a range of virtual addresses in a map. ! 1567: */ ! 1568: void vm_fault_unwire(map, entry) ! 1569: vm_map_t map; ! 1570: vm_map_entry_t entry; ! 1571: { ! 1572: register vm_offset_t va; ! 1573: register pmap_t pmap; ! 1574: register vm_offset_t end_addr = entry->vme_end; ! 1575: vm_object_t object; ! 1576: ! 1577: pmap = vm_map_pmap(map); ! 1578: ! 1579: object = (entry->is_sub_map) ! 1580: ? VM_OBJECT_NULL : entry->object.vm_object; ! 1581: ! 1582: /* ! 1583: * Since the pages are wired down, we must be able to ! 1584: * get their mappings from the physical map system. ! 1585: */ ! 1586: ! 1587: for (va = entry->vme_start; va < end_addr; va += PAGE_SIZE) { ! 1588: pmap_change_wiring(pmap, va, FALSE); ! 1589: ! 1590: if (object == VM_OBJECT_NULL) { ! 1591: vm_map_lock_set_recursive(map); ! 1592: (void) vm_fault(map, va, VM_PROT_NONE, TRUE, ! 1593: FALSE, (void (*)()) 0); ! 1594: vm_map_lock_clear_recursive(map); ! 1595: } else { ! 1596: vm_prot_t prot; ! 1597: vm_page_t result_page; ! 1598: vm_page_t top_page; ! 1599: vm_fault_return_t result; ! 1600: ! 1601: do { ! 1602: prot = VM_PROT_NONE; ! 1603: ! 1604: vm_object_lock(object); ! 1605: vm_object_paging_begin(object); ! 1606: result = vm_fault_page(object, ! 1607: entry->offset + ! 1608: (va - entry->vme_start), ! 1609: VM_PROT_NONE, TRUE, ! 1610: FALSE, &prot, ! 1611: &result_page, ! 1612: &top_page, ! 1613: FALSE, (void (*)()) 0); ! 1614: } while (result == VM_FAULT_RETRY); ! 1615: ! 1616: if (result != VM_FAULT_SUCCESS) ! 1617: panic("vm_fault_unwire: failure"); ! 1618: ! 1619: vm_page_lock_queues(); ! 1620: vm_page_unwire(result_page); ! 1621: vm_page_unlock_queues(); ! 1622: PAGE_WAKEUP_DONE(result_page); ! 1623: ! 1624: vm_fault_cleanup(result_page->object, top_page); ! 1625: } ! 1626: } ! 1627: ! 1628: /* ! 1629: * Inform the physical mapping system that the range ! 1630: * of addresses may fault, so that page tables and ! 1631: * such may be unwired themselves. ! 1632: */ ! 1633: ! 1634: pmap_pageable(pmap, entry->vme_start, end_addr, TRUE); ! 1635: } ! 1636: ! 1637: /* ! 1638: * vm_fault_wire_fast: ! 1639: * ! 1640: * Handle common case of a wire down page fault at the given address. ! 1641: * If successful, the page is inserted into the associated physical map. ! 1642: * The map entry is passed in to avoid the overhead of a map lookup. ! 1643: * ! 1644: * NOTE: the given address should be truncated to the ! 1645: * proper page address. ! 1646: * ! 1647: * KERN_SUCCESS is returned if the page fault is handled; otherwise, ! 1648: * a standard error specifying why the fault is fatal is returned. ! 1649: * ! 1650: * The map in question must be referenced, and remains so. ! 1651: * Caller has a read lock on the map. ! 1652: * ! 1653: * This is a stripped version of vm_fault() for wiring pages. Anything ! 1654: * other than the common case will return KERN_FAILURE, and the caller ! 1655: * is expected to call vm_fault(). ! 1656: */ ! 1657: kern_return_t vm_fault_wire_fast(map, va, entry) ! 1658: vm_map_t map; ! 1659: vm_offset_t va; ! 1660: vm_map_entry_t entry; ! 1661: { ! 1662: vm_object_t object; ! 1663: vm_offset_t offset; ! 1664: register vm_page_t m; ! 1665: vm_prot_t prot; ! 1666: ! 1667: vm_stat.faults++; /* needs lock XXX */ ! 1668: /* ! 1669: * Recovery actions ! 1670: */ ! 1671: ! 1672: #undef RELEASE_PAGE ! 1673: #define RELEASE_PAGE(m) { \ ! 1674: PAGE_WAKEUP_DONE(m); \ ! 1675: vm_page_lock_queues(); \ ! 1676: vm_page_unwire(m); \ ! 1677: vm_page_unlock_queues(); \ ! 1678: } ! 1679: ! 1680: ! 1681: #undef UNLOCK_THINGS ! 1682: #define UNLOCK_THINGS { \ ! 1683: object->paging_in_progress--; \ ! 1684: vm_object_unlock(object); \ ! 1685: } ! 1686: ! 1687: #undef UNLOCK_AND_DEALLOCATE ! 1688: #define UNLOCK_AND_DEALLOCATE { \ ! 1689: UNLOCK_THINGS; \ ! 1690: vm_object_deallocate(object); \ ! 1691: } ! 1692: /* ! 1693: * Give up and have caller do things the hard way. ! 1694: */ ! 1695: ! 1696: #define GIVE_UP { \ ! 1697: UNLOCK_AND_DEALLOCATE; \ ! 1698: return(KERN_FAILURE); \ ! 1699: } ! 1700: ! 1701: ! 1702: /* ! 1703: * If this entry is not directly to a vm_object, bail out. ! 1704: */ ! 1705: if (entry->is_sub_map) ! 1706: return(KERN_FAILURE); ! 1707: ! 1708: /* ! 1709: * Find the backing store object and offset into it. ! 1710: */ ! 1711: ! 1712: object = entry->object.vm_object; ! 1713: offset = (va - entry->vme_start) + entry->offset; ! 1714: prot = entry->protection; ! 1715: ! 1716: /* ! 1717: * Make a reference to this object to prevent its ! 1718: * disposal while we are messing with it. ! 1719: */ ! 1720: ! 1721: vm_object_lock(object); ! 1722: assert(object->ref_count > 0); ! 1723: object->ref_count++; ! 1724: object->paging_in_progress++; ! 1725: ! 1726: /* ! 1727: * INVARIANTS (through entire routine): ! 1728: * ! 1729: * 1) At all times, we must either have the object ! 1730: * lock or a busy page in some object to prevent ! 1731: * some other thread from trying to bring in ! 1732: * the same page. ! 1733: * ! 1734: * 2) Once we have a busy page, we must remove it from ! 1735: * the pageout queues, so that the pageout daemon ! 1736: * will not grab it away. ! 1737: * ! 1738: */ ! 1739: ! 1740: /* ! 1741: * Look for page in top-level object. If it's not there or ! 1742: * there's something going on, give up. ! 1743: */ ! 1744: m = vm_page_lookup(object, offset); ! 1745: if ((m == VM_PAGE_NULL) || (m->error) || ! 1746: (m->busy) || (m->absent) || (prot & m->page_lock)) { ! 1747: GIVE_UP; ! 1748: } ! 1749: ! 1750: /* ! 1751: * Wire the page down now. All bail outs beyond this ! 1752: * point must unwire the page. ! 1753: */ ! 1754: ! 1755: vm_page_lock_queues(); ! 1756: vm_page_wire(m); ! 1757: vm_page_unlock_queues(); ! 1758: ! 1759: /* ! 1760: * Mark page busy for other threads. ! 1761: */ ! 1762: assert(!m->busy); ! 1763: m->busy = TRUE; ! 1764: assert(!m->absent); ! 1765: ! 1766: /* ! 1767: * Give up if the page is being written and there's a copy object ! 1768: */ ! 1769: if ((object->copy != VM_OBJECT_NULL) && (prot & VM_PROT_WRITE)) { ! 1770: RELEASE_PAGE(m); ! 1771: GIVE_UP; ! 1772: } ! 1773: ! 1774: /* ! 1775: * Put this page into the physical map. ! 1776: * We have to unlock the object because pmap_enter ! 1777: * may cause other faults. ! 1778: */ ! 1779: vm_object_unlock(object); ! 1780: ! 1781: PMAP_ENTER(map->pmap, va, m, prot, TRUE); ! 1782: ! 1783: /* ! 1784: * Must relock object so that paging_in_progress can be cleared. ! 1785: */ ! 1786: vm_object_lock(object); ! 1787: ! 1788: /* ! 1789: * Unlock everything, and return ! 1790: */ ! 1791: ! 1792: PAGE_WAKEUP_DONE(m); ! 1793: UNLOCK_AND_DEALLOCATE; ! 1794: ! 1795: return(KERN_SUCCESS); ! 1796: ! 1797: } ! 1798: ! 1799: /* ! 1800: * Routine: vm_fault_copy_cleanup ! 1801: * Purpose: ! 1802: * Release a page used by vm_fault_copy. ! 1803: */ ! 1804: ! 1805: void vm_fault_copy_cleanup(page, top_page) ! 1806: vm_page_t page; ! 1807: vm_page_t top_page; ! 1808: { ! 1809: vm_object_t object = page->object; ! 1810: ! 1811: vm_object_lock(object); ! 1812: PAGE_WAKEUP_DONE(page); ! 1813: vm_page_lock_queues(); ! 1814: if (!page->active && !page->inactive) ! 1815: vm_page_activate(page); ! 1816: vm_page_unlock_queues(); ! 1817: vm_fault_cleanup(object, top_page); ! 1818: } ! 1819: ! 1820: /* ! 1821: * Routine: vm_fault_copy ! 1822: * ! 1823: * Purpose: ! 1824: * Copy pages from one virtual memory object to another -- ! 1825: * neither the source nor destination pages need be resident. ! 1826: * ! 1827: * Before actually copying a page, the version associated with ! 1828: * the destination address map wil be verified. ! 1829: * ! 1830: * In/out conditions: ! 1831: * The caller must hold a reference, but not a lock, to ! 1832: * each of the source and destination objects and to the ! 1833: * destination map. ! 1834: * ! 1835: * Results: ! 1836: * Returns KERN_SUCCESS if no errors were encountered in ! 1837: * reading or writing the data. Returns KERN_INTERRUPTED if ! 1838: * the operation was interrupted (only possible if the ! 1839: * "interruptible" argument is asserted). Other return values ! 1840: * indicate a permanent error in copying the data. ! 1841: * ! 1842: * The actual amount of data copied will be returned in the ! 1843: * "copy_size" argument. In the event that the destination map ! 1844: * verification failed, this amount may be less than the amount ! 1845: * requested. ! 1846: */ ! 1847: kern_return_t vm_fault_copy( ! 1848: src_object, ! 1849: src_offset, ! 1850: src_size, ! 1851: dst_object, ! 1852: dst_offset, ! 1853: dst_map, ! 1854: dst_version, ! 1855: interruptible ! 1856: ) ! 1857: vm_object_t src_object; ! 1858: vm_offset_t src_offset; ! 1859: vm_size_t *src_size; /* INOUT */ ! 1860: vm_object_t dst_object; ! 1861: vm_offset_t dst_offset; ! 1862: vm_map_t dst_map; ! 1863: vm_map_version_t *dst_version; ! 1864: boolean_t interruptible; ! 1865: { ! 1866: vm_page_t result_page; ! 1867: vm_prot_t prot; ! 1868: ! 1869: vm_page_t src_page; ! 1870: vm_page_t src_top_page; ! 1871: ! 1872: vm_page_t dst_page; ! 1873: vm_page_t dst_top_page; ! 1874: ! 1875: vm_size_t amount_done; ! 1876: vm_object_t old_copy_object; ! 1877: ! 1878: #define RETURN(x) \ ! 1879: MACRO_BEGIN \ ! 1880: *src_size = amount_done; \ ! 1881: MACRO_RETURN(x); \ ! 1882: MACRO_END ! 1883: ! 1884: amount_done = 0; ! 1885: do { /* while (amount_done != *src_size) */ ! 1886: ! 1887: RetrySourceFault: ; ! 1888: ! 1889: if (src_object == VM_OBJECT_NULL) { ! 1890: /* ! 1891: * No source object. We will just ! 1892: * zero-fill the page in dst_object. ! 1893: */ ! 1894: ! 1895: src_page = VM_PAGE_NULL; ! 1896: } else { ! 1897: prot = VM_PROT_READ; ! 1898: ! 1899: vm_object_lock(src_object); ! 1900: vm_object_paging_begin(src_object); ! 1901: ! 1902: switch (vm_fault_page(src_object, src_offset, ! 1903: VM_PROT_READ, FALSE, interruptible, ! 1904: &prot, &result_page, &src_top_page, ! 1905: FALSE, (void (*)()) 0)) { ! 1906: ! 1907: case VM_FAULT_SUCCESS: ! 1908: break; ! 1909: case VM_FAULT_RETRY: ! 1910: goto RetrySourceFault; ! 1911: case VM_FAULT_INTERRUPTED: ! 1912: RETURN(MACH_SEND_INTERRUPTED); ! 1913: case VM_FAULT_MEMORY_SHORTAGE: ! 1914: VM_PAGE_WAIT((void (*)()) 0); ! 1915: goto RetrySourceFault; ! 1916: case VM_FAULT_FICTITIOUS_SHORTAGE: ! 1917: vm_page_more_fictitious(); ! 1918: goto RetrySourceFault; ! 1919: case VM_FAULT_MEMORY_ERROR: ! 1920: return(KERN_MEMORY_ERROR); ! 1921: } ! 1922: ! 1923: src_page = result_page; ! 1924: ! 1925: assert((src_top_page == VM_PAGE_NULL) == ! 1926: (src_page->object == src_object)); ! 1927: ! 1928: assert ((prot & VM_PROT_READ) != VM_PROT_NONE); ! 1929: ! 1930: vm_object_unlock(src_page->object); ! 1931: } ! 1932: ! 1933: RetryDestinationFault: ; ! 1934: ! 1935: prot = VM_PROT_WRITE; ! 1936: ! 1937: vm_object_lock(dst_object); ! 1938: vm_object_paging_begin(dst_object); ! 1939: ! 1940: switch (vm_fault_page(dst_object, dst_offset, VM_PROT_WRITE, ! 1941: FALSE, FALSE /* interruptible */, ! 1942: &prot, &result_page, &dst_top_page, ! 1943: FALSE, (void (*)()) 0)) { ! 1944: ! 1945: case VM_FAULT_SUCCESS: ! 1946: break; ! 1947: case VM_FAULT_RETRY: ! 1948: goto RetryDestinationFault; ! 1949: case VM_FAULT_INTERRUPTED: ! 1950: if (src_page != VM_PAGE_NULL) ! 1951: vm_fault_copy_cleanup(src_page, ! 1952: src_top_page); ! 1953: RETURN(MACH_SEND_INTERRUPTED); ! 1954: case VM_FAULT_MEMORY_SHORTAGE: ! 1955: VM_PAGE_WAIT((void (*)()) 0); ! 1956: goto RetryDestinationFault; ! 1957: case VM_FAULT_FICTITIOUS_SHORTAGE: ! 1958: vm_page_more_fictitious(); ! 1959: goto RetryDestinationFault; ! 1960: case VM_FAULT_MEMORY_ERROR: ! 1961: if (src_page != VM_PAGE_NULL) ! 1962: vm_fault_copy_cleanup(src_page, ! 1963: src_top_page); ! 1964: return(KERN_MEMORY_ERROR); ! 1965: } ! 1966: assert ((prot & VM_PROT_WRITE) != VM_PROT_NONE); ! 1967: ! 1968: dst_page = result_page; ! 1969: ! 1970: old_copy_object = dst_page->object->copy; ! 1971: ! 1972: vm_object_unlock(dst_page->object); ! 1973: ! 1974: if (!vm_map_verify(dst_map, dst_version)) { ! 1975: ! 1976: BailOut: ; ! 1977: ! 1978: if (src_page != VM_PAGE_NULL) ! 1979: vm_fault_copy_cleanup(src_page, src_top_page); ! 1980: vm_fault_copy_cleanup(dst_page, dst_top_page); ! 1981: break; ! 1982: } ! 1983: ! 1984: ! 1985: vm_object_lock(dst_page->object); ! 1986: if (dst_page->object->copy != old_copy_object) { ! 1987: vm_object_unlock(dst_page->object); ! 1988: vm_map_verify_done(dst_map, dst_version); ! 1989: goto BailOut; ! 1990: } ! 1991: vm_object_unlock(dst_page->object); ! 1992: ! 1993: /* ! 1994: * Copy the page, and note that it is dirty ! 1995: * immediately. ! 1996: */ ! 1997: ! 1998: if (src_page == VM_PAGE_NULL) ! 1999: vm_page_zero_fill(dst_page); ! 2000: else ! 2001: vm_page_copy(src_page, dst_page); ! 2002: dst_page->dirty = TRUE; ! 2003: ! 2004: /* ! 2005: * Unlock everything, and return ! 2006: */ ! 2007: ! 2008: vm_map_verify_done(dst_map, dst_version); ! 2009: ! 2010: if (src_page != VM_PAGE_NULL) ! 2011: vm_fault_copy_cleanup(src_page, src_top_page); ! 2012: vm_fault_copy_cleanup(dst_page, dst_top_page); ! 2013: ! 2014: amount_done += PAGE_SIZE; ! 2015: src_offset += PAGE_SIZE; ! 2016: dst_offset += PAGE_SIZE; ! 2017: ! 2018: } while (amount_done != *src_size); ! 2019: ! 2020: RETURN(KERN_SUCCESS); ! 2021: #undef RETURN ! 2022: ! 2023: /*NOTREACHED*/ ! 2024: } ! 2025: ! 2026: ! 2027: ! 2028: ! 2029: ! 2030: #ifdef notdef ! 2031: ! 2032: /* ! 2033: * Routine: vm_fault_page_overwrite ! 2034: * ! 2035: * Description: ! 2036: * A form of vm_fault_page that assumes that the ! 2037: * resulting page will be overwritten in its entirety, ! 2038: * making it unnecessary to obtain the correct *contents* ! 2039: * of the page. ! 2040: * ! 2041: * Implementation: ! 2042: * XXX Untested. Also unused. Eventually, this technology ! 2043: * could be used in vm_fault_copy() to advantage. ! 2044: */ ! 2045: vm_fault_return_t vm_fault_page_overwrite(dst_object, dst_offset, result_page) ! 2046: register ! 2047: vm_object_t dst_object; ! 2048: vm_offset_t dst_offset; ! 2049: vm_page_t *result_page; /* OUT */ ! 2050: { ! 2051: register ! 2052: vm_page_t dst_page; ! 2053: ! 2054: #define interruptible FALSE /* XXX */ ! 2055: ! 2056: while (TRUE) { ! 2057: /* ! 2058: * Look for a page at this offset ! 2059: */ ! 2060: ! 2061: while ((dst_page = vm_page_lookup(dst_object, dst_offset)) ! 2062: == VM_PAGE_NULL) { ! 2063: /* ! 2064: * No page, no problem... just allocate one. ! 2065: */ ! 2066: ! 2067: dst_page = vm_page_alloc(dst_object, dst_offset); ! 2068: if (dst_page == VM_PAGE_NULL) { ! 2069: vm_object_unlock(dst_object); ! 2070: VM_PAGE_WAIT((void (*)()) 0); ! 2071: vm_object_lock(dst_object); ! 2072: continue; ! 2073: } ! 2074: ! 2075: /* ! 2076: * Pretend that the memory manager ! 2077: * write-protected the page. ! 2078: * ! 2079: * Note that we will be asking for write ! 2080: * permission without asking for the data ! 2081: * first. ! 2082: */ ! 2083: ! 2084: dst_page->overwriting = TRUE; ! 2085: dst_page->page_lock = VM_PROT_WRITE; ! 2086: dst_page->absent = TRUE; ! 2087: dst_object->absent_count++; ! 2088: ! 2089: break; ! 2090: ! 2091: /* ! 2092: * When we bail out, we might have to throw ! 2093: * away the page created here. ! 2094: */ ! 2095: ! 2096: #define DISCARD_PAGE \ ! 2097: MACRO_BEGIN \ ! 2098: vm_object_lock(dst_object); \ ! 2099: dst_page = vm_page_lookup(dst_object, dst_offset); \ ! 2100: if ((dst_page != VM_PAGE_NULL) && dst_page->overwriting) \ ! 2101: VM_PAGE_FREE(dst_page); \ ! 2102: vm_object_unlock(dst_object); \ ! 2103: MACRO_END ! 2104: } ! 2105: ! 2106: /* ! 2107: * If the page is write-protected... ! 2108: */ ! 2109: ! 2110: if (dst_page->page_lock & VM_PROT_WRITE) { ! 2111: /* ! 2112: * ... and an unlock request hasn't been sent ! 2113: */ ! 2114: ! 2115: if ( ! (dst_page->unlock_request & VM_PROT_WRITE)) { ! 2116: vm_prot_t u; ! 2117: kern_return_t rc; ! 2118: ! 2119: /* ! 2120: * ... then send one now. ! 2121: */ ! 2122: ! 2123: if (!dst_object->pager_ready) { ! 2124: vm_object_assert_wait(dst_object, ! 2125: VM_OBJECT_EVENT_PAGER_READY, ! 2126: interruptible); ! 2127: vm_object_unlock(dst_object); ! 2128: thread_block((void (*)()) 0); ! 2129: if (current_thread()->wait_result != ! 2130: THREAD_AWAKENED) { ! 2131: DISCARD_PAGE; ! 2132: return(VM_FAULT_INTERRUPTED); ! 2133: } ! 2134: continue; ! 2135: } ! 2136: ! 2137: u = dst_page->unlock_request |= VM_PROT_WRITE; ! 2138: vm_object_unlock(dst_object); ! 2139: ! 2140: if ((rc = memory_object_data_unlock( ! 2141: dst_object->pager, ! 2142: dst_object->pager_request, ! 2143: dst_offset + dst_object->paging_offset, ! 2144: PAGE_SIZE, ! 2145: u)) != KERN_SUCCESS) { ! 2146: printf("vm_object_overwrite: memory_object_data_unlock failed\n"); ! 2147: DISCARD_PAGE; ! 2148: return((rc == MACH_SEND_INTERRUPTED) ? ! 2149: VM_FAULT_INTERRUPTED : ! 2150: VM_FAULT_MEMORY_ERROR); ! 2151: } ! 2152: vm_object_lock(dst_object); ! 2153: continue; ! 2154: } ! 2155: ! 2156: /* ... fall through to wait below */ ! 2157: } else { ! 2158: /* ! 2159: * If the page isn't being used for other ! 2160: * purposes, then we're done. ! 2161: */ ! 2162: if ( ! (dst_page->busy || dst_page->absent || dst_page->error) ) ! 2163: break; ! 2164: } ! 2165: ! 2166: PAGE_ASSERT_WAIT(dst_page, interruptible); ! 2167: vm_object_unlock(dst_object); ! 2168: thread_block((void (*)()) 0); ! 2169: if (current_thread()->wait_result != THREAD_AWAKENED) { ! 2170: DISCARD_PAGE; ! 2171: return(VM_FAULT_INTERRUPTED); ! 2172: } ! 2173: } ! 2174: ! 2175: *result_page = dst_page; ! 2176: return(VM_FAULT_SUCCESS); ! 2177: ! 2178: #undef interruptible ! 2179: #undef DISCARD_PAGE ! 2180: } ! 2181: ! 2182: #endif /* notdef */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.