|
|
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_fault.c 7.6 (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: * Page fault handling module. ! 67: */ ! 68: ! 69: #include "param.h" ! 70: ! 71: #include "vm.h" ! 72: #include "vm_page.h" ! 73: #include "vm_pageout.h" ! 74: ! 75: /* ! 76: * vm_fault: ! 77: * ! 78: * Handle a page fault occuring at the given address, ! 79: * requiring the given permissions, in the map specified. ! 80: * If successful, the page is inserted into the ! 81: * associated physical map. ! 82: * ! 83: * NOTE: the given address should be truncated to the ! 84: * proper page address. ! 85: * ! 86: * KERN_SUCCESS is returned if the page fault is handled; otherwise, ! 87: * a standard error specifying why the fault is fatal is returned. ! 88: * ! 89: * ! 90: * The map in question must be referenced, and remains so. ! 91: * Caller may hold no locks. ! 92: */ ! 93: vm_fault(map, vaddr, fault_type, change_wiring) ! 94: vm_map_t map; ! 95: vm_offset_t vaddr; ! 96: vm_prot_t fault_type; ! 97: boolean_t change_wiring; ! 98: { ! 99: vm_object_t first_object; ! 100: vm_offset_t first_offset; ! 101: vm_map_entry_t entry; ! 102: register vm_object_t object; ! 103: register vm_offset_t offset; ! 104: register vm_page_t m; ! 105: vm_page_t first_m; ! 106: vm_prot_t prot; ! 107: int result; ! 108: boolean_t wired; ! 109: boolean_t su; ! 110: boolean_t lookup_still_valid; ! 111: boolean_t page_exists; ! 112: vm_page_t old_m; ! 113: vm_object_t next_object; ! 114: ! 115: vm_stat.faults++; /* needs lock XXX */ ! 116: /* ! 117: * Recovery actions ! 118: */ ! 119: #define FREE_PAGE(m) { \ ! 120: PAGE_WAKEUP(m); \ ! 121: vm_page_lock_queues(); \ ! 122: vm_page_free(m); \ ! 123: vm_page_unlock_queues(); \ ! 124: } ! 125: ! 126: #define RELEASE_PAGE(m) { \ ! 127: PAGE_WAKEUP(m); \ ! 128: vm_page_lock_queues(); \ ! 129: vm_page_activate(m); \ ! 130: vm_page_unlock_queues(); \ ! 131: } ! 132: ! 133: #define UNLOCK_MAP { \ ! 134: if (lookup_still_valid) { \ ! 135: vm_map_lookup_done(map, entry); \ ! 136: lookup_still_valid = FALSE; \ ! 137: } \ ! 138: } ! 139: ! 140: #define UNLOCK_THINGS { \ ! 141: object->paging_in_progress--; \ ! 142: vm_object_unlock(object); \ ! 143: if (object != first_object) { \ ! 144: vm_object_lock(first_object); \ ! 145: FREE_PAGE(first_m); \ ! 146: first_object->paging_in_progress--; \ ! 147: vm_object_unlock(first_object); \ ! 148: } \ ! 149: UNLOCK_MAP; \ ! 150: } ! 151: ! 152: #define UNLOCK_AND_DEALLOCATE { \ ! 153: UNLOCK_THINGS; \ ! 154: vm_object_deallocate(first_object); \ ! 155: } ! 156: ! 157: RetryFault: ; ! 158: ! 159: /* ! 160: * Find the backing store object and offset into ! 161: * it to begin the search. ! 162: */ ! 163: ! 164: if ((result = vm_map_lookup(&map, vaddr, fault_type, &entry, ! 165: &first_object, &first_offset, ! 166: &prot, &wired, &su)) != KERN_SUCCESS) { ! 167: return(result); ! 168: } ! 169: lookup_still_valid = TRUE; ! 170: ! 171: if (wired) ! 172: fault_type = prot; ! 173: ! 174: first_m = NULL; ! 175: ! 176: /* ! 177: * Make a reference to this object to ! 178: * prevent its disposal while we are messing with ! 179: * it. Once we have the reference, the map is free ! 180: * to be diddled. Since objects reference their ! 181: * shadows (and copies), they will stay around as well. ! 182: */ ! 183: ! 184: vm_object_lock(first_object); ! 185: ! 186: first_object->ref_count++; ! 187: first_object->paging_in_progress++; ! 188: ! 189: /* ! 190: * INVARIANTS (through entire routine): ! 191: * ! 192: * 1) At all times, we must either have the object ! 193: * lock or a busy page in some object to prevent ! 194: * some other thread from trying to bring in ! 195: * the same page. ! 196: * ! 197: * Note that we cannot hold any locks during the ! 198: * pager access or when waiting for memory, so ! 199: * we use a busy page then. ! 200: * ! 201: * Note also that we aren't as concerned about ! 202: * more than one thead attempting to pager_data_unlock ! 203: * the same page at once, so we don't hold the page ! 204: * as busy then, but do record the highest unlock ! 205: * value so far. [Unlock requests may also be delivered ! 206: * out of order.] ! 207: * ! 208: * 2) Once we have a busy page, we must remove it from ! 209: * the pageout queues, so that the pageout daemon ! 210: * will not grab it away. ! 211: * ! 212: * 3) To prevent another thread from racing us down the ! 213: * shadow chain and entering a new page in the top ! 214: * object before we do, we must keep a busy page in ! 215: * the top object while following the shadow chain. ! 216: * ! 217: * 4) We must increment paging_in_progress on any object ! 218: * for which we have a busy page, to prevent ! 219: * vm_object_collapse from removing the busy page ! 220: * without our noticing. ! 221: */ ! 222: ! 223: /* ! 224: * Search for the page at object/offset. ! 225: */ ! 226: ! 227: object = first_object; ! 228: offset = first_offset; ! 229: ! 230: /* ! 231: * See whether this page is resident ! 232: */ ! 233: ! 234: while (TRUE) { ! 235: m = vm_page_lookup(object, offset); ! 236: if (m != NULL) { ! 237: /* ! 238: * If the page is being brought in, ! 239: * wait for it and then retry. ! 240: */ ! 241: if (m->busy) { ! 242: #ifdef DOTHREADS ! 243: int wait_result; ! 244: ! 245: PAGE_ASSERT_WAIT(m, !change_wiring); ! 246: UNLOCK_THINGS; ! 247: thread_block(); ! 248: wait_result = current_thread()->wait_result; ! 249: vm_object_deallocate(first_object); ! 250: if (wait_result != THREAD_AWAKENED) ! 251: return(KERN_SUCCESS); ! 252: goto RetryFault; ! 253: #else ! 254: PAGE_ASSERT_WAIT(m, !change_wiring); ! 255: UNLOCK_THINGS; ! 256: thread_block(); ! 257: vm_object_deallocate(first_object); ! 258: goto RetryFault; ! 259: #endif ! 260: } ! 261: ! 262: if (m->absent) ! 263: panic("vm_fault: absent"); ! 264: ! 265: /* ! 266: * If the desired access to this page has ! 267: * been locked out, request that it be unlocked. ! 268: */ ! 269: ! 270: if (fault_type & m->page_lock) { ! 271: #ifdef DOTHREADS ! 272: int wait_result; ! 273: ! 274: if ((fault_type & m->unlock_request) != fault_type) ! 275: panic("vm_fault: pager_data_unlock"); ! 276: ! 277: PAGE_ASSERT_WAIT(m, !change_wiring); ! 278: UNLOCK_THINGS; ! 279: thread_block(); ! 280: wait_result = current_thread()->wait_result; ! 281: vm_object_deallocate(first_object); ! 282: if (wait_result != THREAD_AWAKENED) ! 283: return(KERN_SUCCESS); ! 284: goto RetryFault; ! 285: #else ! 286: if ((fault_type & m->unlock_request) != fault_type) ! 287: panic("vm_fault: pager_data_unlock"); ! 288: ! 289: PAGE_ASSERT_WAIT(m, !change_wiring); ! 290: UNLOCK_THINGS; ! 291: thread_block(); ! 292: vm_object_deallocate(first_object); ! 293: goto RetryFault; ! 294: #endif ! 295: } ! 296: ! 297: /* ! 298: * Remove the page from the pageout daemon's ! 299: * reach while we play with it. ! 300: */ ! 301: ! 302: vm_page_lock_queues(); ! 303: if (m->inactive) { ! 304: queue_remove(&vm_page_queue_inactive, m, ! 305: vm_page_t, pageq); ! 306: m->inactive = FALSE; ! 307: vm_page_inactive_count--; ! 308: vm_stat.reactivations++; ! 309: } ! 310: ! 311: if (m->active) { ! 312: queue_remove(&vm_page_queue_active, m, ! 313: vm_page_t, pageq); ! 314: m->active = FALSE; ! 315: vm_page_active_count--; ! 316: } ! 317: vm_page_unlock_queues(); ! 318: ! 319: /* ! 320: * Mark page busy for other threads. ! 321: */ ! 322: m->busy = TRUE; ! 323: m->absent = FALSE; ! 324: break; ! 325: } ! 326: ! 327: if (((object->pager != NULL) && ! 328: (!change_wiring || wired)) ! 329: || (object == first_object)) { ! 330: ! 331: /* ! 332: * Allocate a new page for this object/offset ! 333: * pair. ! 334: */ ! 335: ! 336: m = vm_page_alloc(object, offset); ! 337: ! 338: if (m == NULL) { ! 339: UNLOCK_AND_DEALLOCATE; ! 340: VM_WAIT; ! 341: goto RetryFault; ! 342: } ! 343: } ! 344: ! 345: if ((object->pager != NULL) && ! 346: (!change_wiring || wired)) { ! 347: int rv; ! 348: ! 349: /* ! 350: * Now that we have a busy page, we can ! 351: * release the object lock. ! 352: */ ! 353: vm_object_unlock(object); ! 354: ! 355: /* ! 356: * Call the pager to retrieve the data, if any, ! 357: * after releasing the lock on the map. ! 358: */ ! 359: UNLOCK_MAP; ! 360: ! 361: rv = vm_pager_get(object->pager, m, TRUE); ! 362: if (rv == VM_PAGER_OK) { ! 363: /* ! 364: * Found the page. ! 365: * Leave it busy while we play with it. ! 366: */ ! 367: vm_object_lock(object); ! 368: ! 369: /* ! 370: * Relookup in case pager changed page. ! 371: * Pager is responsible for disposition ! 372: * of old page if moved. ! 373: */ ! 374: m = vm_page_lookup(object, offset); ! 375: ! 376: vm_stat.pageins++; ! 377: m->fake = FALSE; ! 378: pmap_clear_modify(VM_PAGE_TO_PHYS(m)); ! 379: break; ! 380: } ! 381: ! 382: /* ! 383: * Remove the bogus page (which does not ! 384: * exist at this object/offset); before ! 385: * doing so, we must get back our object ! 386: * lock to preserve our invariant. ! 387: * ! 388: * Also wake up any other thread that may want ! 389: * to bring in this page. ! 390: * ! 391: * If this is the top-level object, we must ! 392: * leave the busy page to prevent another ! 393: * thread from rushing past us, and inserting ! 394: * the page in that object at the same time ! 395: * that we are. ! 396: */ ! 397: ! 398: vm_object_lock(object); ! 399: /* ! 400: * Data outside the range of the pager; an error ! 401: */ ! 402: if (rv == VM_PAGER_BAD) { ! 403: FREE_PAGE(m); ! 404: UNLOCK_AND_DEALLOCATE; ! 405: return(KERN_PROTECTION_FAILURE); /* XXX */ ! 406: } ! 407: if (object != first_object) { ! 408: FREE_PAGE(m); ! 409: /* ! 410: * XXX - we cannot just fall out at this ! 411: * point, m has been freed and is invalid! ! 412: */ ! 413: } ! 414: } ! 415: ! 416: /* ! 417: * We get here if the object has no pager (or unwiring) ! 418: * or the pager doesn't have the page. ! 419: */ ! 420: if (object == first_object) ! 421: first_m = m; ! 422: ! 423: /* ! 424: * Move on to the next object. Lock the next ! 425: * object before unlocking the current one. ! 426: */ ! 427: ! 428: offset += object->shadow_offset; ! 429: next_object = object->shadow; ! 430: if (next_object == NULL) { ! 431: /* ! 432: * If there's no object left, fill the page ! 433: * in the top object with zeros. ! 434: */ ! 435: if (object != first_object) { ! 436: object->paging_in_progress--; ! 437: vm_object_unlock(object); ! 438: ! 439: object = first_object; ! 440: offset = first_offset; ! 441: m = first_m; ! 442: vm_object_lock(object); ! 443: } ! 444: first_m = NULL; ! 445: ! 446: vm_page_zero_fill(m); ! 447: vm_stat.zero_fill_count++; ! 448: m->fake = FALSE; ! 449: m->absent = FALSE; ! 450: break; ! 451: } ! 452: else { ! 453: vm_object_lock(next_object); ! 454: if (object != first_object) ! 455: object->paging_in_progress--; ! 456: vm_object_unlock(object); ! 457: object = next_object; ! 458: object->paging_in_progress++; ! 459: } ! 460: } ! 461: ! 462: if (m->absent || m->active || m->inactive || !m->busy) ! 463: panic("vm_fault: absent or active or inactive or not busy after main loop"); ! 464: ! 465: /* ! 466: * PAGE HAS BEEN FOUND. ! 467: * [Loop invariant still holds -- the object lock ! 468: * is held.] ! 469: */ ! 470: ! 471: old_m = m; /* save page that would be copied */ ! 472: ! 473: /* ! 474: * If the page is being written, but isn't ! 475: * already owned by the top-level object, ! 476: * we have to copy it into a new page owned ! 477: * by the top-level object. ! 478: */ ! 479: ! 480: if (object != first_object) { ! 481: /* ! 482: * We only really need to copy if we ! 483: * want to write it. ! 484: */ ! 485: ! 486: if (fault_type & VM_PROT_WRITE) { ! 487: ! 488: /* ! 489: * If we try to collapse first_object at this ! 490: * point, we may deadlock when we try to get ! 491: * the lock on an intermediate object (since we ! 492: * have the bottom object locked). We can't ! 493: * unlock the bottom object, because the page ! 494: * we found may move (by collapse) if we do. ! 495: * ! 496: * Instead, we first copy the page. Then, when ! 497: * we have no more use for the bottom object, ! 498: * we unlock it and try to collapse. ! 499: * ! 500: * Note that we copy the page even if we didn't ! 501: * need to... that's the breaks. ! 502: */ ! 503: ! 504: /* ! 505: * We already have an empty page in ! 506: * first_object - use it. ! 507: */ ! 508: ! 509: vm_page_copy(m, first_m); ! 510: first_m->fake = FALSE; ! 511: first_m->absent = FALSE; ! 512: ! 513: /* ! 514: * If another map is truly sharing this ! 515: * page with us, we have to flush all ! 516: * uses of the original page, since we ! 517: * can't distinguish those which want the ! 518: * original from those which need the ! 519: * new copy. ! 520: * ! 521: * XXX If we know that only one map has ! 522: * access to this page, then we could ! 523: * avoid the pmap_page_protect() call. ! 524: */ ! 525: ! 526: vm_page_lock_queues(); ! 527: vm_page_deactivate(m); ! 528: pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE); ! 529: vm_page_unlock_queues(); ! 530: ! 531: /* ! 532: * We no longer need the old page or object. ! 533: */ ! 534: PAGE_WAKEUP(m); ! 535: object->paging_in_progress--; ! 536: vm_object_unlock(object); ! 537: ! 538: /* ! 539: * Only use the new page below... ! 540: */ ! 541: ! 542: vm_stat.cow_faults++; ! 543: m = first_m; ! 544: object = first_object; ! 545: offset = first_offset; ! 546: ! 547: /* ! 548: * Now that we've gotten the copy out of the ! 549: * way, let's try to collapse the top object. ! 550: */ ! 551: vm_object_lock(object); ! 552: /* ! 553: * But we have to play ugly games with ! 554: * paging_in_progress to do that... ! 555: */ ! 556: object->paging_in_progress--; ! 557: vm_object_collapse(object); ! 558: object->paging_in_progress++; ! 559: } ! 560: else { ! 561: prot &= (~VM_PROT_WRITE); ! 562: m->copy_on_write = TRUE; ! 563: } ! 564: } ! 565: ! 566: if (m->active || m->inactive) ! 567: panic("vm_fault: active or inactive before copy object handling"); ! 568: ! 569: /* ! 570: * If the page is being written, but hasn't been ! 571: * copied to the copy-object, we have to copy it there. ! 572: */ ! 573: RetryCopy: ! 574: if (first_object->copy != NULL) { ! 575: vm_object_t copy_object = first_object->copy; ! 576: vm_offset_t copy_offset; ! 577: vm_page_t copy_m; ! 578: ! 579: /* ! 580: * We only need to copy if we want to write it. ! 581: */ ! 582: if ((fault_type & VM_PROT_WRITE) == 0) { ! 583: prot &= ~VM_PROT_WRITE; ! 584: m->copy_on_write = TRUE; ! 585: } ! 586: else { ! 587: /* ! 588: * Try to get the lock on the copy_object. ! 589: */ ! 590: if (!vm_object_lock_try(copy_object)) { ! 591: vm_object_unlock(object); ! 592: /* should spin a bit here... */ ! 593: vm_object_lock(object); ! 594: goto RetryCopy; ! 595: } ! 596: ! 597: /* ! 598: * Make another reference to the copy-object, ! 599: * to keep it from disappearing during the ! 600: * copy. ! 601: */ ! 602: copy_object->ref_count++; ! 603: ! 604: /* ! 605: * Does the page exist in the copy? ! 606: */ ! 607: copy_offset = first_offset ! 608: - copy_object->shadow_offset; ! 609: copy_m = vm_page_lookup(copy_object, copy_offset); ! 610: if (page_exists = (copy_m != NULL)) { ! 611: if (copy_m->busy) { ! 612: #ifdef DOTHREADS ! 613: int wait_result; ! 614: ! 615: /* ! 616: * If the page is being brought ! 617: * in, wait for it and then retry. ! 618: */ ! 619: PAGE_ASSERT_WAIT(copy_m, !change_wiring); ! 620: RELEASE_PAGE(m); ! 621: copy_object->ref_count--; ! 622: vm_object_unlock(copy_object); ! 623: UNLOCK_THINGS; ! 624: thread_block(); ! 625: wait_result = current_thread()->wait_result; ! 626: vm_object_deallocate(first_object); ! 627: if (wait_result != THREAD_AWAKENED) ! 628: return(KERN_SUCCESS); ! 629: goto RetryFault; ! 630: #else ! 631: /* ! 632: * If the page is being brought ! 633: * in, wait for it and then retry. ! 634: */ ! 635: PAGE_ASSERT_WAIT(copy_m, !change_wiring); ! 636: RELEASE_PAGE(m); ! 637: copy_object->ref_count--; ! 638: vm_object_unlock(copy_object); ! 639: UNLOCK_THINGS; ! 640: thread_block(); ! 641: vm_object_deallocate(first_object); ! 642: goto RetryFault; ! 643: #endif ! 644: } ! 645: } ! 646: ! 647: /* ! 648: * If the page is not in memory (in the object) ! 649: * and the object has a pager, we have to check ! 650: * if the pager has the data in secondary ! 651: * storage. ! 652: */ ! 653: if (!page_exists) { ! 654: ! 655: /* ! 656: * If we don't allocate a (blank) page ! 657: * here... another thread could try ! 658: * to page it in, allocate a page, and ! 659: * then block on the busy page in its ! 660: * shadow (first_object). Then we'd ! 661: * trip over the busy page after we ! 662: * found that the copy_object's pager ! 663: * doesn't have the page... ! 664: */ ! 665: copy_m = vm_page_alloc(copy_object, ! 666: copy_offset); ! 667: if (copy_m == NULL) { ! 668: /* ! 669: * Wait for a page, then retry. ! 670: */ ! 671: RELEASE_PAGE(m); ! 672: copy_object->ref_count--; ! 673: vm_object_unlock(copy_object); ! 674: UNLOCK_AND_DEALLOCATE; ! 675: VM_WAIT; ! 676: goto RetryFault; ! 677: } ! 678: ! 679: if (copy_object->pager != NULL) { ! 680: vm_object_unlock(object); ! 681: vm_object_unlock(copy_object); ! 682: UNLOCK_MAP; ! 683: ! 684: page_exists = vm_pager_has_page( ! 685: copy_object->pager, ! 686: (copy_offset + copy_object->paging_offset)); ! 687: ! 688: vm_object_lock(copy_object); ! 689: ! 690: /* ! 691: * Since the map is unlocked, someone ! 692: * else could have copied this object ! 693: * and put a different copy_object ! 694: * between the two. Or, the last ! 695: * reference to the copy-object (other ! 696: * than the one we have) may have ! 697: * disappeared - if that has happened, ! 698: * we don't need to make the copy. ! 699: */ ! 700: if (copy_object->shadow != object || ! 701: copy_object->ref_count == 1) { ! 702: /* ! 703: * Gaah... start over! ! 704: */ ! 705: FREE_PAGE(copy_m); ! 706: vm_object_unlock(copy_object); ! 707: vm_object_deallocate(copy_object); ! 708: /* may block */ ! 709: vm_object_lock(object); ! 710: goto RetryCopy; ! 711: } ! 712: vm_object_lock(object); ! 713: ! 714: if (page_exists) { ! 715: /* ! 716: * We didn't need the page ! 717: */ ! 718: FREE_PAGE(copy_m); ! 719: } ! 720: } ! 721: } ! 722: if (!page_exists) { ! 723: /* ! 724: * Must copy page into copy-object. ! 725: */ ! 726: vm_page_copy(m, copy_m); ! 727: copy_m->fake = FALSE; ! 728: copy_m->absent = FALSE; ! 729: ! 730: /* ! 731: * Things to remember: ! 732: * 1. The copied page must be marked 'dirty' ! 733: * so it will be paged out to the copy ! 734: * object. ! 735: * 2. If the old page was in use by any users ! 736: * of the copy-object, it must be removed ! 737: * from all pmaps. (We can't know which ! 738: * pmaps use it.) ! 739: */ ! 740: vm_page_lock_queues(); ! 741: pmap_page_protect(VM_PAGE_TO_PHYS(old_m), ! 742: VM_PROT_NONE); ! 743: copy_m->clean = FALSE; ! 744: vm_page_activate(copy_m); /* XXX */ ! 745: vm_page_unlock_queues(); ! 746: ! 747: PAGE_WAKEUP(copy_m); ! 748: } ! 749: /* ! 750: * The reference count on copy_object must be ! 751: * at least 2: one for our extra reference, ! 752: * and at least one from the outside world ! 753: * (we checked that when we last locked ! 754: * copy_object). ! 755: */ ! 756: copy_object->ref_count--; ! 757: vm_object_unlock(copy_object); ! 758: m->copy_on_write = FALSE; ! 759: } ! 760: } ! 761: ! 762: if (m->active || m->inactive) ! 763: panic("vm_fault: active or inactive before retrying lookup"); ! 764: ! 765: /* ! 766: * We must verify that the maps have not changed ! 767: * since our last lookup. ! 768: */ ! 769: ! 770: if (!lookup_still_valid) { ! 771: vm_object_t retry_object; ! 772: vm_offset_t retry_offset; ! 773: vm_prot_t retry_prot; ! 774: ! 775: /* ! 776: * Since map entries may be pageable, make sure we can ! 777: * take a page fault on them. ! 778: */ ! 779: vm_object_unlock(object); ! 780: ! 781: /* ! 782: * To avoid trying to write_lock the map while another ! 783: * thread has it read_locked (in vm_map_pageable), we ! 784: * do not try for write permission. If the page is ! 785: * still writable, we will get write permission. If it ! 786: * is not, or has been marked needs_copy, we enter the ! 787: * mapping without write permission, and will merely ! 788: * take another fault. ! 789: */ ! 790: result = vm_map_lookup(&map, vaddr, ! 791: fault_type & ~VM_PROT_WRITE, &entry, ! 792: &retry_object, &retry_offset, &retry_prot, ! 793: &wired, &su); ! 794: ! 795: vm_object_lock(object); ! 796: ! 797: /* ! 798: * If we don't need the page any longer, put it on the ! 799: * active list (the easiest thing to do here). If no ! 800: * one needs it, pageout will grab it eventually. ! 801: */ ! 802: ! 803: if (result != KERN_SUCCESS) { ! 804: RELEASE_PAGE(m); ! 805: UNLOCK_AND_DEALLOCATE; ! 806: return(result); ! 807: } ! 808: ! 809: lookup_still_valid = TRUE; ! 810: ! 811: if ((retry_object != first_object) || ! 812: (retry_offset != first_offset)) { ! 813: RELEASE_PAGE(m); ! 814: UNLOCK_AND_DEALLOCATE; ! 815: goto RetryFault; ! 816: } ! 817: ! 818: /* ! 819: * Check whether the protection has changed or the object ! 820: * has been copied while we left the map unlocked. ! 821: * Changing from read to write permission is OK - we leave ! 822: * the page write-protected, and catch the write fault. ! 823: * Changing from write to read permission means that we ! 824: * can't mark the page write-enabled after all. ! 825: */ ! 826: prot &= retry_prot; ! 827: if (m->copy_on_write) ! 828: prot &= ~VM_PROT_WRITE; ! 829: } ! 830: ! 831: /* ! 832: * (the various bits we're fiddling with here are locked by ! 833: * the object's lock) ! 834: */ ! 835: ! 836: /* XXX This distorts the meaning of the copy_on_write bit */ ! 837: ! 838: if (prot & VM_PROT_WRITE) ! 839: m->copy_on_write = FALSE; ! 840: ! 841: /* ! 842: * It's critically important that a wired-down page be faulted ! 843: * only once in each map for which it is wired. ! 844: */ ! 845: ! 846: if (m->active || m->inactive) ! 847: panic("vm_fault: active or inactive before pmap_enter"); ! 848: ! 849: vm_object_unlock(object); ! 850: ! 851: /* ! 852: * Put this page into the physical map. ! 853: * We had to do the unlock above because pmap_enter ! 854: * may cause other faults. We don't put the ! 855: * page back on the active queue until later so ! 856: * that the page-out daemon won't find us (yet). ! 857: */ ! 858: ! 859: pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), ! 860: prot & ~(m->page_lock), wired); ! 861: ! 862: /* ! 863: * If the page is not wired down, then put it where the ! 864: * pageout daemon can find it. ! 865: */ ! 866: vm_object_lock(object); ! 867: vm_page_lock_queues(); ! 868: if (change_wiring) { ! 869: if (wired) ! 870: vm_page_wire(m); ! 871: else ! 872: vm_page_unwire(m); ! 873: } ! 874: else ! 875: vm_page_activate(m); ! 876: vm_page_unlock_queues(); ! 877: ! 878: /* ! 879: * Unlock everything, and return ! 880: */ ! 881: ! 882: PAGE_WAKEUP(m); ! 883: UNLOCK_AND_DEALLOCATE; ! 884: ! 885: return(KERN_SUCCESS); ! 886: ! 887: } ! 888: ! 889: /* ! 890: * vm_fault_wire: ! 891: * ! 892: * Wire down a range of virtual addresses in a map. ! 893: */ ! 894: void vm_fault_wire(map, start, end) ! 895: vm_map_t map; ! 896: vm_offset_t start, end; ! 897: { ! 898: ! 899: register vm_offset_t va; ! 900: register pmap_t pmap; ! 901: ! 902: pmap = vm_map_pmap(map); ! 903: ! 904: /* ! 905: * Inform the physical mapping system that the ! 906: * range of addresses may not fault, so that ! 907: * page tables and such can be locked down as well. ! 908: */ ! 909: ! 910: pmap_pageable(pmap, start, end, FALSE); ! 911: ! 912: /* ! 913: * We simulate a fault to get the page and enter it ! 914: * in the physical map. ! 915: */ ! 916: ! 917: for (va = start; va < end; va += PAGE_SIZE) { ! 918: (void) vm_fault(map, va, VM_PROT_NONE, TRUE); ! 919: } ! 920: } ! 921: ! 922: ! 923: /* ! 924: * vm_fault_unwire: ! 925: * ! 926: * Unwire a range of virtual addresses in a map. ! 927: */ ! 928: void vm_fault_unwire(map, start, end) ! 929: vm_map_t map; ! 930: vm_offset_t start, end; ! 931: { ! 932: ! 933: register vm_offset_t va, pa; ! 934: register pmap_t pmap; ! 935: ! 936: pmap = vm_map_pmap(map); ! 937: ! 938: /* ! 939: * Since the pages are wired down, we must be able to ! 940: * get their mappings from the physical map system. ! 941: */ ! 942: ! 943: vm_page_lock_queues(); ! 944: ! 945: for (va = start; va < end; va += PAGE_SIZE) { ! 946: pa = pmap_extract(pmap, va); ! 947: if (pa == (vm_offset_t) 0) { ! 948: panic("unwire: page not in pmap"); ! 949: } ! 950: pmap_change_wiring(pmap, va, FALSE); ! 951: vm_page_unwire(PHYS_TO_VM_PAGE(pa)); ! 952: } ! 953: vm_page_unlock_queues(); ! 954: ! 955: /* ! 956: * Inform the physical mapping system that the range ! 957: * of addresses may fault, so that page tables and ! 958: * such may be unwired themselves. ! 959: */ ! 960: ! 961: pmap_pageable(pmap, start, end, TRUE); ! 962: ! 963: } ! 964: ! 965: /* ! 966: * Routine: ! 967: * vm_fault_copy_entry ! 968: * Function: ! 969: * Copy all of the pages from a wired-down map entry to another. ! 970: * ! 971: * In/out conditions: ! 972: * The source and destination maps must be locked for write. ! 973: * The source map entry must be wired down (or be a sharing map ! 974: * entry corresponding to a main map entry that is wired down). ! 975: */ ! 976: ! 977: void vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry) ! 978: vm_map_t dst_map; ! 979: vm_map_t src_map; ! 980: vm_map_entry_t dst_entry; ! 981: vm_map_entry_t src_entry; ! 982: { ! 983: ! 984: vm_object_t dst_object; ! 985: vm_object_t src_object; ! 986: vm_offset_t dst_offset; ! 987: vm_offset_t src_offset; ! 988: vm_prot_t prot; ! 989: vm_offset_t vaddr; ! 990: vm_page_t dst_m; ! 991: vm_page_t src_m; ! 992: ! 993: #ifdef lint ! 994: src_map++; ! 995: #endif lint ! 996: ! 997: src_object = src_entry->object.vm_object; ! 998: src_offset = src_entry->offset; ! 999: ! 1000: /* ! 1001: * Create the top-level object for the destination entry. ! 1002: * (Doesn't actually shadow anything - we copy the pages ! 1003: * directly.) ! 1004: */ ! 1005: dst_object = vm_object_allocate( ! 1006: (vm_size_t) (dst_entry->end - dst_entry->start)); ! 1007: ! 1008: dst_entry->object.vm_object = dst_object; ! 1009: dst_entry->offset = 0; ! 1010: ! 1011: prot = dst_entry->max_protection; ! 1012: ! 1013: /* ! 1014: * Loop through all of the pages in the entry's range, copying ! 1015: * each one from the source object (it should be there) to the ! 1016: * destination object. ! 1017: */ ! 1018: for (vaddr = dst_entry->start, dst_offset = 0; ! 1019: vaddr < dst_entry->end; ! 1020: vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) { ! 1021: ! 1022: /* ! 1023: * Allocate a page in the destination object ! 1024: */ ! 1025: vm_object_lock(dst_object); ! 1026: do { ! 1027: dst_m = vm_page_alloc(dst_object, dst_offset); ! 1028: if (dst_m == NULL) { ! 1029: vm_object_unlock(dst_object); ! 1030: VM_WAIT; ! 1031: vm_object_lock(dst_object); ! 1032: } ! 1033: } while (dst_m == NULL); ! 1034: ! 1035: /* ! 1036: * Find the page in the source object, and copy it in. ! 1037: * (Because the source is wired down, the page will be ! 1038: * in memory.) ! 1039: */ ! 1040: vm_object_lock(src_object); ! 1041: src_m = vm_page_lookup(src_object, dst_offset + src_offset); ! 1042: if (src_m == NULL) ! 1043: panic("vm_fault_copy_wired: page missing"); ! 1044: ! 1045: vm_page_copy(src_m, dst_m); ! 1046: ! 1047: /* ! 1048: * Enter it in the pmap... ! 1049: */ ! 1050: vm_object_unlock(src_object); ! 1051: vm_object_unlock(dst_object); ! 1052: ! 1053: pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m), ! 1054: prot, FALSE); ! 1055: ! 1056: /* ! 1057: * Mark it no longer busy, and put it on the active list. ! 1058: */ ! 1059: vm_object_lock(dst_object); ! 1060: vm_page_lock_queues(); ! 1061: vm_page_activate(dst_m); ! 1062: vm_page_unlock_queues(); ! 1063: PAGE_WAKEUP(dst_m); ! 1064: vm_object_unlock(dst_object); ! 1065: } ! 1066: ! 1067: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.