145748Smckusick /* 2*47592Smckusick * Copyright (c) 1987 Carnegie-Mellon University. 345748Smckusick * Copyright (c) 1991 Regents of the University of California. 445748Smckusick * All rights reserved. 545748Smckusick * 645748Smckusick * This code is derived from software contributed to Berkeley by 745748Smckusick * The Mach Operating System project at Carnegie-Mellon University. 8*47592Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 9*47592Smckusick * 10*47592Smckusick * Permission to use, copy, modify and distribute this software and 11*47592Smckusick * its documentation is hereby granted, provided that both the copyright 12*47592Smckusick * notice and this permission notice appear in all copies of the 13*47592Smckusick * software, derivative works or modified versions, and any portions 14*47592Smckusick * thereof, and that both notices appear in supporting documentation. 15*47592Smckusick * 16*47592Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17*47592Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18*47592Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19*47592Smckusick * 20*47592Smckusick * Carnegie Mellon requests users of this software to return to Carnegie 21*47592Smckusick * any improvements or extensions that they make and grant Carnegie 22*47592Smckusick * the rights to redistribute these changes. We can be reached at 23*47592Smckusick * mach@cs.cmu.edu or 24*47592Smckusick * Project Mach 25*47592Smckusick * School of Computer Science 26*47592Smckusick * Carnegie Mellon University 27*47592Smckusick * Pittsburgh PA 15213-3890 2845748Smckusick * 29*47592Smckusick * %sccs.include.redist.c% 3045748Smckusick * 31*47592Smckusick * @(#)vm_fault.c 7.2 (Berkeley) 03/19/91 3245748Smckusick */ 3345748Smckusick 3445748Smckusick /* 3545748Smckusick * Page fault handling module. 3645748Smckusick */ 3745748Smckusick 3845748Smckusick #include "param.h" 3945748Smckusick #include "../vm/vm_param.h" 4045748Smckusick #include "../vm/vm_map.h" 4145748Smckusick #include "../vm/vm_object.h" 4245748Smckusick #include "../vm/vm_page.h" 4345748Smckusick #include "../vm/pmap.h" 4445748Smckusick #include "../vm/vm_statistics.h" 4545748Smckusick #include "../vm/vm_pageout.h" 4645748Smckusick 4745748Smckusick /* 4845748Smckusick * vm_fault: 4945748Smckusick * 5045748Smckusick * Handle a page fault occuring at the given address, 5145748Smckusick * requiring the given permissions, in the map specified. 5245748Smckusick * If successful, the page is inserted into the 5345748Smckusick * associated physical map. 5445748Smckusick * 5545748Smckusick * NOTE: the given address should be truncated to the 5645748Smckusick * proper page address. 5745748Smckusick * 5845748Smckusick * KERN_SUCCESS is returned if the page fault is handled; otherwise, 5945748Smckusick * a standard error specifying why the fault is fatal is returned. 6045748Smckusick * 6145748Smckusick * 6245748Smckusick * The map in question must be referenced, and remains so. 6345748Smckusick * Caller may hold no locks. 6445748Smckusick */ 6545748Smckusick vm_fault(map, vaddr, fault_type, change_wiring) 6645748Smckusick vm_map_t map; 6745748Smckusick vm_offset_t vaddr; 6845748Smckusick vm_prot_t fault_type; 6945748Smckusick boolean_t change_wiring; 7045748Smckusick { 7145748Smckusick vm_object_t first_object; 7245748Smckusick vm_offset_t first_offset; 7345748Smckusick vm_map_entry_t entry; 7445748Smckusick register vm_object_t object; 7545748Smckusick register vm_offset_t offset; 7645748Smckusick register vm_page_t m; 7745748Smckusick vm_page_t first_m; 7845748Smckusick vm_prot_t prot; 7945748Smckusick int result; 8045748Smckusick boolean_t wired; 8145748Smckusick boolean_t su; 8245748Smckusick boolean_t lookup_still_valid; 8345748Smckusick boolean_t page_exists; 8445748Smckusick vm_page_t old_m; 8545748Smckusick vm_object_t next_object; 8645748Smckusick 8745748Smckusick vm_stat.faults++; /* needs lock XXX */ 8845748Smckusick /* 8945748Smckusick * Recovery actions 9045748Smckusick */ 9145748Smckusick #define FREE_PAGE(m) { \ 9245748Smckusick PAGE_WAKEUP(m); \ 9345748Smckusick vm_page_lock_queues(); \ 9445748Smckusick vm_page_free(m); \ 9545748Smckusick vm_page_unlock_queues(); \ 9645748Smckusick } 9745748Smckusick 9845748Smckusick #define RELEASE_PAGE(m) { \ 9945748Smckusick PAGE_WAKEUP(m); \ 10045748Smckusick vm_page_lock_queues(); \ 10145748Smckusick vm_page_activate(m); \ 10245748Smckusick vm_page_unlock_queues(); \ 10345748Smckusick } 10445748Smckusick 10545748Smckusick #define UNLOCK_MAP { \ 10645748Smckusick if (lookup_still_valid) { \ 10745748Smckusick vm_map_lookup_done(map, entry); \ 10845748Smckusick lookup_still_valid = FALSE; \ 10945748Smckusick } \ 11045748Smckusick } 11145748Smckusick 11245748Smckusick #define UNLOCK_THINGS { \ 11345748Smckusick object->paging_in_progress--; \ 11445748Smckusick vm_object_unlock(object); \ 11545748Smckusick if (object != first_object) { \ 11645748Smckusick vm_object_lock(first_object); \ 11745748Smckusick FREE_PAGE(first_m); \ 11845748Smckusick first_object->paging_in_progress--; \ 11945748Smckusick vm_object_unlock(first_object); \ 12045748Smckusick } \ 12145748Smckusick UNLOCK_MAP; \ 12245748Smckusick } 12345748Smckusick 12445748Smckusick #define UNLOCK_AND_DEALLOCATE { \ 12545748Smckusick UNLOCK_THINGS; \ 12645748Smckusick vm_object_deallocate(first_object); \ 12745748Smckusick } 12845748Smckusick 12945748Smckusick RetryFault: ; 13045748Smckusick 13145748Smckusick /* 13245748Smckusick * Find the backing store object and offset into 13345748Smckusick * it to begin the search. 13445748Smckusick */ 13545748Smckusick 13645748Smckusick if ((result = vm_map_lookup(&map, vaddr, fault_type, &entry, 13745748Smckusick &first_object, &first_offset, 13845748Smckusick &prot, &wired, &su)) != KERN_SUCCESS) { 13945748Smckusick return(result); 14045748Smckusick } 14145748Smckusick lookup_still_valid = TRUE; 14245748Smckusick 14345748Smckusick if (wired) 14445748Smckusick fault_type = prot; 14545748Smckusick 14645748Smckusick first_m = VM_PAGE_NULL; 14745748Smckusick 14845748Smckusick /* 14945748Smckusick * Make a reference to this object to 15045748Smckusick * prevent its disposal while we are messing with 15145748Smckusick * it. Once we have the reference, the map is free 15245748Smckusick * to be diddled. Since objects reference their 15345748Smckusick * shadows (and copies), they will stay around as well. 15445748Smckusick */ 15545748Smckusick 15645748Smckusick vm_object_lock(first_object); 15745748Smckusick 15845748Smckusick first_object->ref_count++; 15945748Smckusick first_object->paging_in_progress++; 16045748Smckusick 16145748Smckusick /* 16245748Smckusick * INVARIANTS (through entire routine): 16345748Smckusick * 16445748Smckusick * 1) At all times, we must either have the object 16545748Smckusick * lock or a busy page in some object to prevent 16645748Smckusick * some other thread from trying to bring in 16745748Smckusick * the same page. 16845748Smckusick * 16945748Smckusick * Note that we cannot hold any locks during the 17045748Smckusick * pager access or when waiting for memory, so 17145748Smckusick * we use a busy page then. 17245748Smckusick * 17345748Smckusick * Note also that we aren't as concerned about 17445748Smckusick * more than one thead attempting to pager_data_unlock 17545748Smckusick * the same page at once, so we don't hold the page 17645748Smckusick * as busy then, but do record the highest unlock 17745748Smckusick * value so far. [Unlock requests may also be delivered 17845748Smckusick * out of order.] 17945748Smckusick * 18045748Smckusick * 2) Once we have a busy page, we must remove it from 18145748Smckusick * the pageout queues, so that the pageout daemon 18245748Smckusick * will not grab it away. 18345748Smckusick * 18445748Smckusick * 3) To prevent another thread from racing us down the 18545748Smckusick * shadow chain and entering a new page in the top 18645748Smckusick * object before we do, we must keep a busy page in 18745748Smckusick * the top object while following the shadow chain. 18845748Smckusick * 18945748Smckusick * 4) We must increment paging_in_progress on any object 19045748Smckusick * for which we have a busy page, to prevent 19145748Smckusick * vm_object_collapse from removing the busy page 19245748Smckusick * without our noticing. 19345748Smckusick */ 19445748Smckusick 19545748Smckusick /* 19645748Smckusick * Search for the page at object/offset. 19745748Smckusick */ 19845748Smckusick 19945748Smckusick object = first_object; 20045748Smckusick offset = first_offset; 20145748Smckusick 20245748Smckusick /* 20345748Smckusick * See whether this page is resident 20445748Smckusick */ 20545748Smckusick 20645748Smckusick while (TRUE) { 20745748Smckusick m = vm_page_lookup(object, offset); 20845748Smckusick if (m != VM_PAGE_NULL) { 20945748Smckusick /* 21045748Smckusick * If the page is being brought in, 21145748Smckusick * wait for it and then retry. 21245748Smckusick */ 21345748Smckusick if (m->busy) { 21445748Smckusick #ifdef DOTHREADS 21545748Smckusick int wait_result; 21645748Smckusick 21745748Smckusick PAGE_ASSERT_WAIT(m, !change_wiring); 21845748Smckusick UNLOCK_THINGS; 21945748Smckusick thread_block(); 22045748Smckusick wait_result = current_thread()->wait_result; 22145748Smckusick vm_object_deallocate(first_object); 22245748Smckusick if (wait_result != THREAD_AWAKENED) 22345748Smckusick return(KERN_SUCCESS); 22445748Smckusick goto RetryFault; 22545748Smckusick #else 22645748Smckusick PAGE_ASSERT_WAIT(m, !change_wiring); 22745748Smckusick UNLOCK_THINGS; 22845748Smckusick thread_block(); 22945748Smckusick vm_object_deallocate(first_object); 23045748Smckusick goto RetryFault; 23145748Smckusick #endif 23245748Smckusick } 23345748Smckusick 23445748Smckusick if (m->absent) 23545748Smckusick panic("vm_fault: absent"); 23645748Smckusick 23745748Smckusick /* 23845748Smckusick * If the desired access to this page has 23945748Smckusick * been locked out, request that it be unlocked. 24045748Smckusick */ 24145748Smckusick 24245748Smckusick if (fault_type & m->page_lock) { 24345748Smckusick #ifdef DOTHREADS 24445748Smckusick int wait_result; 24545748Smckusick 24645748Smckusick if ((fault_type & m->unlock_request) != fault_type) 24745748Smckusick panic("vm_fault: pager_data_unlock"); 24845748Smckusick 24945748Smckusick PAGE_ASSERT_WAIT(m, !change_wiring); 25045748Smckusick UNLOCK_THINGS; 25145748Smckusick thread_block(); 25245748Smckusick wait_result = current_thread()->wait_result; 25345748Smckusick vm_object_deallocate(first_object); 25445748Smckusick if (wait_result != THREAD_AWAKENED) 25545748Smckusick return(KERN_SUCCESS); 25645748Smckusick goto RetryFault; 25745748Smckusick #else 25845748Smckusick if ((fault_type & m->unlock_request) != fault_type) 25945748Smckusick panic("vm_fault: pager_data_unlock"); 26045748Smckusick 26145748Smckusick PAGE_ASSERT_WAIT(m, !change_wiring); 26245748Smckusick UNLOCK_THINGS; 26345748Smckusick thread_block(); 26445748Smckusick vm_object_deallocate(first_object); 26545748Smckusick goto RetryFault; 26645748Smckusick #endif 26745748Smckusick } 26845748Smckusick 26945748Smckusick /* 27045748Smckusick * Remove the page from the pageout daemon's 27145748Smckusick * reach while we play with it. 27245748Smckusick */ 27345748Smckusick 27445748Smckusick vm_page_lock_queues(); 27545748Smckusick if (m->inactive) { 27645748Smckusick queue_remove(&vm_page_queue_inactive, m, 27745748Smckusick vm_page_t, pageq); 27845748Smckusick m->inactive = FALSE; 27945748Smckusick vm_page_inactive_count--; 28045748Smckusick vm_stat.reactivations++; 28145748Smckusick } 28245748Smckusick 28345748Smckusick if (m->active) { 28445748Smckusick queue_remove(&vm_page_queue_active, m, 28545748Smckusick vm_page_t, pageq); 28645748Smckusick m->active = FALSE; 28745748Smckusick vm_page_active_count--; 28845748Smckusick } 28945748Smckusick vm_page_unlock_queues(); 29045748Smckusick 29145748Smckusick /* 29245748Smckusick * Mark page busy for other threads. 29345748Smckusick */ 29445748Smckusick m->busy = TRUE; 29545748Smckusick m->absent = FALSE; 29645748Smckusick break; 29745748Smckusick } 29845748Smckusick 29945748Smckusick if (((object->pager != vm_pager_null) && 30045748Smckusick (!change_wiring || wired)) 30145748Smckusick || (object == first_object)) { 30245748Smckusick 30345748Smckusick /* 30445748Smckusick * Allocate a new page for this object/offset 30545748Smckusick * pair. 30645748Smckusick */ 30745748Smckusick 30845748Smckusick m = vm_page_alloc(object, offset); 30945748Smckusick 31045748Smckusick if (m == VM_PAGE_NULL) { 31145748Smckusick UNLOCK_AND_DEALLOCATE; 31245748Smckusick VM_WAIT; 31345748Smckusick goto RetryFault; 31445748Smckusick } 31545748Smckusick } 31645748Smckusick 31745748Smckusick if ((object->pager != vm_pager_null) && 31845748Smckusick (!change_wiring || wired)) { 31945748Smckusick int rv; 32045748Smckusick 32145748Smckusick /* 32245748Smckusick * Now that we have a busy page, we can 32345748Smckusick * release the object lock. 32445748Smckusick */ 32545748Smckusick vm_object_unlock(object); 32645748Smckusick 32745748Smckusick /* 32845748Smckusick * Call the pager to retrieve the data, if any, 32945748Smckusick * after releasing the lock on the map. 33045748Smckusick */ 33145748Smckusick UNLOCK_MAP; 33245748Smckusick 33345748Smckusick rv = vm_pager_get(object->pager, m, TRUE); 33445748Smckusick if (rv == VM_PAGER_OK) { 33545748Smckusick /* 33645748Smckusick * Found the page. 33745748Smckusick * Leave it busy while we play with it. 33845748Smckusick */ 33945748Smckusick vm_object_lock(object); 34045748Smckusick 34145748Smckusick /* 34245748Smckusick * Relookup in case pager changed page. 34345748Smckusick * Pager is responsible for disposition 34445748Smckusick * of old page if moved. 34545748Smckusick */ 34645748Smckusick m = vm_page_lookup(object, offset); 34745748Smckusick 34845748Smckusick vm_stat.pageins++; 34945748Smckusick m->fake = FALSE; 35045748Smckusick pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 35145748Smckusick break; 35245748Smckusick } 35345748Smckusick 35445748Smckusick /* 35545748Smckusick * Remove the bogus page (which does not 35645748Smckusick * exist at this object/offset); before 35745748Smckusick * doing so, we must get back our object 35845748Smckusick * lock to preserve our invariant. 35945748Smckusick * 36045748Smckusick * Also wake up any other thread that may want 36145748Smckusick * to bring in this page. 36245748Smckusick * 36345748Smckusick * If this is the top-level object, we must 36445748Smckusick * leave the busy page to prevent another 36545748Smckusick * thread from rushing past us, and inserting 36645748Smckusick * the page in that object at the same time 36745748Smckusick * that we are. 36845748Smckusick */ 36945748Smckusick 37045748Smckusick vm_object_lock(object); 37145748Smckusick /* 37245748Smckusick * Data outside the range of the pager; an error 37345748Smckusick */ 37445748Smckusick if (rv == VM_PAGER_BAD) { 37545748Smckusick FREE_PAGE(m); 37645748Smckusick UNLOCK_AND_DEALLOCATE; 37745748Smckusick return(KERN_PROTECTION_FAILURE); /* XXX */ 37845748Smckusick } 37945748Smckusick if (object != first_object) { 38045748Smckusick FREE_PAGE(m); 38145748Smckusick /* 38245748Smckusick * XXX - we cannot just fall out at this 38345748Smckusick * point, m has been freed and is invalid! 38445748Smckusick */ 38545748Smckusick } 38645748Smckusick } 38745748Smckusick 38845748Smckusick /* 38945748Smckusick * We get here if the object has no pager (or unwiring) 39045748Smckusick * or the pager doesn't have the page. 39145748Smckusick */ 39245748Smckusick if (object == first_object) 39345748Smckusick first_m = m; 39445748Smckusick 39545748Smckusick /* 39645748Smckusick * Move on to the next object. Lock the next 39745748Smckusick * object before unlocking the current one. 39845748Smckusick */ 39945748Smckusick 40045748Smckusick offset += object->shadow_offset; 40145748Smckusick next_object = object->shadow; 40245748Smckusick if (next_object == VM_OBJECT_NULL) { 40345748Smckusick /* 40445748Smckusick * If there's no object left, fill the page 40545748Smckusick * in the top object with zeros. 40645748Smckusick */ 40745748Smckusick if (object != first_object) { 40845748Smckusick object->paging_in_progress--; 40945748Smckusick vm_object_unlock(object); 41045748Smckusick 41145748Smckusick object = first_object; 41245748Smckusick offset = first_offset; 41345748Smckusick m = first_m; 41445748Smckusick vm_object_lock(object); 41545748Smckusick } 41645748Smckusick first_m = VM_PAGE_NULL; 41745748Smckusick 41845748Smckusick vm_page_zero_fill(m); 41945748Smckusick vm_stat.zero_fill_count++; 42045748Smckusick m->fake = FALSE; 42145748Smckusick m->absent = FALSE; 42245748Smckusick break; 42345748Smckusick } 42445748Smckusick else { 42545748Smckusick vm_object_lock(next_object); 42645748Smckusick if (object != first_object) 42745748Smckusick object->paging_in_progress--; 42845748Smckusick vm_object_unlock(object); 42945748Smckusick object = next_object; 43045748Smckusick object->paging_in_progress++; 43145748Smckusick } 43245748Smckusick } 43345748Smckusick 43445748Smckusick if (m->absent || m->active || m->inactive || !m->busy) 43545748Smckusick panic("vm_fault: absent or active or inactive or not busy after main loop"); 43645748Smckusick 43745748Smckusick /* 43845748Smckusick * PAGE HAS BEEN FOUND. 43945748Smckusick * [Loop invariant still holds -- the object lock 44045748Smckusick * is held.] 44145748Smckusick */ 44245748Smckusick 44345748Smckusick old_m = m; /* save page that would be copied */ 44445748Smckusick 44545748Smckusick /* 44645748Smckusick * If the page is being written, but isn't 44745748Smckusick * already owned by the top-level object, 44845748Smckusick * we have to copy it into a new page owned 44945748Smckusick * by the top-level object. 45045748Smckusick */ 45145748Smckusick 45245748Smckusick if (object != first_object) { 45345748Smckusick /* 45445748Smckusick * We only really need to copy if we 45545748Smckusick * want to write it. 45645748Smckusick */ 45745748Smckusick 45845748Smckusick if (fault_type & VM_PROT_WRITE) { 45945748Smckusick 46045748Smckusick /* 46145748Smckusick * If we try to collapse first_object at this 46245748Smckusick * point, we may deadlock when we try to get 46345748Smckusick * the lock on an intermediate object (since we 46445748Smckusick * have the bottom object locked). We can't 46545748Smckusick * unlock the bottom object, because the page 46645748Smckusick * we found may move (by collapse) if we do. 46745748Smckusick * 46845748Smckusick * Instead, we first copy the page. Then, when 46945748Smckusick * we have no more use for the bottom object, 47045748Smckusick * we unlock it and try to collapse. 47145748Smckusick * 47245748Smckusick * Note that we copy the page even if we didn't 47345748Smckusick * need to... that's the breaks. 47445748Smckusick */ 47545748Smckusick 47645748Smckusick /* 47745748Smckusick * We already have an empty page in 47845748Smckusick * first_object - use it. 47945748Smckusick */ 48045748Smckusick 48145748Smckusick vm_page_copy(m, first_m); 48245748Smckusick first_m->fake = FALSE; 48345748Smckusick first_m->absent = FALSE; 48445748Smckusick 48545748Smckusick /* 48645748Smckusick * If another map is truly sharing this 48745748Smckusick * page with us, we have to flush all 48845748Smckusick * uses of the original page, since we 48945748Smckusick * can't distinguish those which want the 49045748Smckusick * original from those which need the 49145748Smckusick * new copy. 49245748Smckusick */ 49345748Smckusick 49445748Smckusick vm_page_lock_queues(); 49545748Smckusick if (!su) { 49645748Smckusick /* 49745748Smckusick * Also, once it's no longer in 49845748Smckusick * use by any maps, move it to 49945748Smckusick * the inactive queue instead. 50045748Smckusick */ 50145748Smckusick 50245748Smckusick vm_page_deactivate(m); 50345748Smckusick pmap_remove_all(VM_PAGE_TO_PHYS(m)); 50445748Smckusick } 50545748Smckusick else { 50645748Smckusick /* 50745748Smckusick * Old page is only (possibly) 50845748Smckusick * in use by faulting map. We 50945748Smckusick * should do a pmap_remove on 51045748Smckusick * that mapping, but we know 51145748Smckusick * that pmap_enter will remove 51245748Smckusick * the old mapping before 51345748Smckusick * inserting the new one. 51445748Smckusick */ 51545748Smckusick vm_page_activate(m); 51645748Smckusick } 51745748Smckusick vm_page_unlock_queues(); 51845748Smckusick 51945748Smckusick /* 52045748Smckusick * We no longer need the old page or object. 52145748Smckusick */ 52245748Smckusick PAGE_WAKEUP(m); 52345748Smckusick object->paging_in_progress--; 52445748Smckusick vm_object_unlock(object); 52545748Smckusick 52645748Smckusick /* 52745748Smckusick * Only use the new page below... 52845748Smckusick */ 52945748Smckusick 53045748Smckusick vm_stat.cow_faults++; 53145748Smckusick m = first_m; 53245748Smckusick object = first_object; 53345748Smckusick offset = first_offset; 53445748Smckusick 53545748Smckusick /* 53645748Smckusick * Now that we've gotten the copy out of the 53745748Smckusick * way, let's try to collapse the top object. 53845748Smckusick */ 53945748Smckusick vm_object_lock(object); 54045748Smckusick /* 54145748Smckusick * But we have to play ugly games with 54245748Smckusick * paging_in_progress to do that... 54345748Smckusick */ 54445748Smckusick object->paging_in_progress--; 54545748Smckusick vm_object_collapse(object); 54645748Smckusick object->paging_in_progress++; 54745748Smckusick } 54845748Smckusick else { 54945748Smckusick prot &= (~VM_PROT_WRITE); 55045748Smckusick m->copy_on_write = TRUE; 55145748Smckusick } 55245748Smckusick } 55345748Smckusick 55445748Smckusick if (m->active || m->inactive) 55545748Smckusick panic("vm_fault: active or inactive before copy object handling"); 55645748Smckusick 55745748Smckusick /* 55845748Smckusick * If the page is being written, but hasn't been 55945748Smckusick * copied to the copy-object, we have to copy it there. 56045748Smckusick */ 56145748Smckusick RetryCopy: 56245748Smckusick if (first_object->copy != VM_OBJECT_NULL) { 56345748Smckusick vm_object_t copy_object = first_object->copy; 56445748Smckusick vm_offset_t copy_offset; 56545748Smckusick vm_page_t copy_m; 56645748Smckusick 56745748Smckusick /* 56845748Smckusick * We only need to copy if we want to write it. 56945748Smckusick */ 57045748Smckusick if ((fault_type & VM_PROT_WRITE) == 0) { 57145748Smckusick prot &= ~VM_PROT_WRITE; 57245748Smckusick m->copy_on_write = TRUE; 57345748Smckusick } 57445748Smckusick else { 57545748Smckusick /* 57645748Smckusick * Try to get the lock on the copy_object. 57745748Smckusick */ 57845748Smckusick if (!vm_object_lock_try(copy_object)) { 57945748Smckusick vm_object_unlock(object); 58045748Smckusick /* should spin a bit here... */ 58145748Smckusick vm_object_lock(object); 58245748Smckusick goto RetryCopy; 58345748Smckusick } 58445748Smckusick 58545748Smckusick /* 58645748Smckusick * Make another reference to the copy-object, 58745748Smckusick * to keep it from disappearing during the 58845748Smckusick * copy. 58945748Smckusick */ 59045748Smckusick copy_object->ref_count++; 59145748Smckusick 59245748Smckusick /* 59345748Smckusick * Does the page exist in the copy? 59445748Smckusick */ 59545748Smckusick copy_offset = first_offset 59645748Smckusick - copy_object->shadow_offset; 59745748Smckusick copy_m = vm_page_lookup(copy_object, copy_offset); 59845748Smckusick if (page_exists = (copy_m != VM_PAGE_NULL)) { 59945748Smckusick if (copy_m->busy) { 60045748Smckusick #ifdef DOTHREADS 60145748Smckusick int wait_result; 60245748Smckusick 60345748Smckusick /* 60445748Smckusick * If the page is being brought 60545748Smckusick * in, wait for it and then retry. 60645748Smckusick */ 60745748Smckusick PAGE_ASSERT_WAIT(copy_m, !change_wiring); 60845748Smckusick RELEASE_PAGE(m); 60945748Smckusick copy_object->ref_count--; 61045748Smckusick vm_object_unlock(copy_object); 61145748Smckusick UNLOCK_THINGS; 61245748Smckusick thread_block(); 61345748Smckusick wait_result = current_thread()->wait_result; 61445748Smckusick vm_object_deallocate(first_object); 61545748Smckusick if (wait_result != THREAD_AWAKENED) 61645748Smckusick return(KERN_SUCCESS); 61745748Smckusick goto RetryFault; 61845748Smckusick #else 61945748Smckusick /* 62045748Smckusick * If the page is being brought 62145748Smckusick * in, wait for it and then retry. 62245748Smckusick */ 62345748Smckusick PAGE_ASSERT_WAIT(copy_m, !change_wiring); 62445748Smckusick RELEASE_PAGE(m); 62545748Smckusick copy_object->ref_count--; 62645748Smckusick vm_object_unlock(copy_object); 62745748Smckusick UNLOCK_THINGS; 62845748Smckusick thread_block(); 62945748Smckusick vm_object_deallocate(first_object); 63045748Smckusick goto RetryFault; 63145748Smckusick #endif 63245748Smckusick } 63345748Smckusick } 63445748Smckusick 63545748Smckusick /* 63645748Smckusick * If the page is not in memory (in the object) 63745748Smckusick * and the object has a pager, we have to check 63845748Smckusick * if the pager has the data in secondary 63945748Smckusick * storage. 64045748Smckusick */ 64145748Smckusick if (!page_exists) { 64245748Smckusick 64345748Smckusick /* 64445748Smckusick * If we don't allocate a (blank) page 64545748Smckusick * here... another thread could try 64645748Smckusick * to page it in, allocate a page, and 64745748Smckusick * then block on the busy page in its 64845748Smckusick * shadow (first_object). Then we'd 64945748Smckusick * trip over the busy page after we 65045748Smckusick * found that the copy_object's pager 65145748Smckusick * doesn't have the page... 65245748Smckusick */ 65345748Smckusick copy_m = vm_page_alloc(copy_object, 65445748Smckusick copy_offset); 65545748Smckusick if (copy_m == VM_PAGE_NULL) { 65645748Smckusick /* 65745748Smckusick * Wait for a page, then retry. 65845748Smckusick */ 65945748Smckusick RELEASE_PAGE(m); 66045748Smckusick copy_object->ref_count--; 66145748Smckusick vm_object_unlock(copy_object); 66245748Smckusick UNLOCK_AND_DEALLOCATE; 66345748Smckusick VM_WAIT; 66445748Smckusick goto RetryFault; 66545748Smckusick } 66645748Smckusick 66745748Smckusick if (copy_object->pager != vm_pager_null) { 66845748Smckusick vm_object_unlock(object); 66945748Smckusick vm_object_unlock(copy_object); 67045748Smckusick UNLOCK_MAP; 67145748Smckusick 67245748Smckusick page_exists = vm_pager_has_page( 67345748Smckusick copy_object->pager, 67445748Smckusick (copy_offset + copy_object->paging_offset)); 67545748Smckusick 67645748Smckusick vm_object_lock(copy_object); 67745748Smckusick 67845748Smckusick /* 67945748Smckusick * Since the map is unlocked, someone 68045748Smckusick * else could have copied this object 68145748Smckusick * and put a different copy_object 68245748Smckusick * between the two. Or, the last 68345748Smckusick * reference to the copy-object (other 68445748Smckusick * than the one we have) may have 68545748Smckusick * disappeared - if that has happened, 68645748Smckusick * we don't need to make the copy. 68745748Smckusick */ 68845748Smckusick if (copy_object->shadow != object || 68945748Smckusick copy_object->ref_count == 1) { 69045748Smckusick /* 69145748Smckusick * Gaah... start over! 69245748Smckusick */ 69345748Smckusick FREE_PAGE(copy_m); 69445748Smckusick vm_object_unlock(copy_object); 69545748Smckusick vm_object_deallocate(copy_object); 69645748Smckusick /* may block */ 69745748Smckusick vm_object_lock(object); 69845748Smckusick goto RetryCopy; 69945748Smckusick } 70045748Smckusick vm_object_lock(object); 70145748Smckusick 70245748Smckusick if (page_exists) { 70345748Smckusick /* 70445748Smckusick * We didn't need the page 70545748Smckusick */ 70645748Smckusick FREE_PAGE(copy_m); 70745748Smckusick } 70845748Smckusick } 70945748Smckusick } 71045748Smckusick if (!page_exists) { 71145748Smckusick /* 71245748Smckusick * Must copy page into copy-object. 71345748Smckusick */ 71445748Smckusick vm_page_copy(m, copy_m); 71545748Smckusick copy_m->fake = FALSE; 71645748Smckusick copy_m->absent = FALSE; 71745748Smckusick 71845748Smckusick /* 71945748Smckusick * Things to remember: 72045748Smckusick * 1. The copied page must be marked 'dirty' 72145748Smckusick * so it will be paged out to the copy 72245748Smckusick * object. 72345748Smckusick * 2. If the old page was in use by any users 72445748Smckusick * of the copy-object, it must be removed 72545748Smckusick * from all pmaps. (We can't know which 72645748Smckusick * pmaps use it.) 72745748Smckusick */ 72845748Smckusick vm_page_lock_queues(); 72945748Smckusick pmap_remove_all(VM_PAGE_TO_PHYS(old_m)); 73045748Smckusick copy_m->clean = FALSE; 73145748Smckusick vm_page_activate(copy_m); /* XXX */ 73245748Smckusick vm_page_unlock_queues(); 73345748Smckusick 73445748Smckusick PAGE_WAKEUP(copy_m); 73545748Smckusick } 73645748Smckusick /* 73745748Smckusick * The reference count on copy_object must be 73845748Smckusick * at least 2: one for our extra reference, 73945748Smckusick * and at least one from the outside world 74045748Smckusick * (we checked that when we last locked 74145748Smckusick * copy_object). 74245748Smckusick */ 74345748Smckusick copy_object->ref_count--; 74445748Smckusick vm_object_unlock(copy_object); 74545748Smckusick m->copy_on_write = FALSE; 74645748Smckusick } 74745748Smckusick } 74845748Smckusick 74945748Smckusick if (m->active || m->inactive) 75045748Smckusick panic("vm_fault: active or inactive before retrying lookup"); 75145748Smckusick 75245748Smckusick /* 75345748Smckusick * We must verify that the maps have not changed 75445748Smckusick * since our last lookup. 75545748Smckusick */ 75645748Smckusick 75745748Smckusick if (!lookup_still_valid) { 75845748Smckusick vm_object_t retry_object; 75945748Smckusick vm_offset_t retry_offset; 76045748Smckusick vm_prot_t retry_prot; 76145748Smckusick 76245748Smckusick /* 76345748Smckusick * Since map entries may be pageable, make sure we can 76445748Smckusick * take a page fault on them. 76545748Smckusick */ 76645748Smckusick vm_object_unlock(object); 76745748Smckusick 76845748Smckusick /* 76945748Smckusick * To avoid trying to write_lock the map while another 77045748Smckusick * thread has it read_locked (in vm_map_pageable), we 77145748Smckusick * do not try for write permission. If the page is 77245748Smckusick * still writable, we will get write permission. If it 77345748Smckusick * is not, or has been marked needs_copy, we enter the 77445748Smckusick * mapping without write permission, and will merely 77545748Smckusick * take another fault. 77645748Smckusick */ 77745748Smckusick result = vm_map_lookup(&map, vaddr, 77845748Smckusick fault_type & ~VM_PROT_WRITE, &entry, 77945748Smckusick &retry_object, &retry_offset, &retry_prot, 78045748Smckusick &wired, &su); 78145748Smckusick 78245748Smckusick vm_object_lock(object); 78345748Smckusick 78445748Smckusick /* 78545748Smckusick * If we don't need the page any longer, put it on the 78645748Smckusick * active list (the easiest thing to do here). If no 78745748Smckusick * one needs it, pageout will grab it eventually. 78845748Smckusick */ 78945748Smckusick 79045748Smckusick if (result != KERN_SUCCESS) { 79145748Smckusick RELEASE_PAGE(m); 79245748Smckusick UNLOCK_AND_DEALLOCATE; 79345748Smckusick return(result); 79445748Smckusick } 79545748Smckusick 79645748Smckusick lookup_still_valid = TRUE; 79745748Smckusick 79845748Smckusick if ((retry_object != first_object) || 79945748Smckusick (retry_offset != first_offset)) { 80045748Smckusick RELEASE_PAGE(m); 80145748Smckusick UNLOCK_AND_DEALLOCATE; 80245748Smckusick goto RetryFault; 80345748Smckusick } 80445748Smckusick 80545748Smckusick /* 80645748Smckusick * Check whether the protection has changed or the object 80745748Smckusick * has been copied while we left the map unlocked. 80845748Smckusick * Changing from read to write permission is OK - we leave 80945748Smckusick * the page write-protected, and catch the write fault. 81045748Smckusick * Changing from write to read permission means that we 81145748Smckusick * can't mark the page write-enabled after all. 81245748Smckusick */ 81345748Smckusick prot &= retry_prot; 81445748Smckusick if (m->copy_on_write) 81545748Smckusick prot &= ~VM_PROT_WRITE; 81645748Smckusick } 81745748Smckusick 81845748Smckusick /* 81945748Smckusick * (the various bits we're fiddling with here are locked by 82045748Smckusick * the object's lock) 82145748Smckusick */ 82245748Smckusick 82345748Smckusick /* XXX This distorts the meaning of the copy_on_write bit */ 82445748Smckusick 82545748Smckusick if (prot & VM_PROT_WRITE) 82645748Smckusick m->copy_on_write = FALSE; 82745748Smckusick 82845748Smckusick /* 82945748Smckusick * It's critically important that a wired-down page be faulted 83045748Smckusick * only once in each map for which it is wired. 83145748Smckusick */ 83245748Smckusick 83345748Smckusick if (m->active || m->inactive) 83445748Smckusick panic("vm_fault: active or inactive before pmap_enter"); 83545748Smckusick 83645748Smckusick vm_object_unlock(object); 83745748Smckusick 83845748Smckusick /* 83945748Smckusick * Put this page into the physical map. 84045748Smckusick * We had to do the unlock above because pmap_enter 84145748Smckusick * may cause other faults. We don't put the 84245748Smckusick * page back on the active queue until later so 84345748Smckusick * that the page-out daemon won't find us (yet). 84445748Smckusick */ 84545748Smckusick 84645748Smckusick pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), 84745748Smckusick prot & ~(m->page_lock), wired); 84845748Smckusick 84945748Smckusick /* 85045748Smckusick * If the page is not wired down, then put it where the 85145748Smckusick * pageout daemon can find it. 85245748Smckusick */ 85345748Smckusick vm_object_lock(object); 85445748Smckusick vm_page_lock_queues(); 85545748Smckusick if (change_wiring) { 85645748Smckusick if (wired) 85745748Smckusick vm_page_wire(m); 85845748Smckusick else 85945748Smckusick vm_page_unwire(m); 86045748Smckusick } 86145748Smckusick else 86245748Smckusick vm_page_activate(m); 86345748Smckusick vm_page_unlock_queues(); 86445748Smckusick 86545748Smckusick /* 86645748Smckusick * Unlock everything, and return 86745748Smckusick */ 86845748Smckusick 86945748Smckusick PAGE_WAKEUP(m); 87045748Smckusick UNLOCK_AND_DEALLOCATE; 87145748Smckusick 87245748Smckusick return(KERN_SUCCESS); 87345748Smckusick 87445748Smckusick } 87545748Smckusick 87645748Smckusick /* 87745748Smckusick * vm_fault_wire: 87845748Smckusick * 87945748Smckusick * Wire down a range of virtual addresses in a map. 88045748Smckusick */ 88145748Smckusick void vm_fault_wire(map, start, end) 88245748Smckusick vm_map_t map; 88345748Smckusick vm_offset_t start, end; 88445748Smckusick { 88545748Smckusick 88645748Smckusick register vm_offset_t va; 88745748Smckusick register pmap_t pmap; 88845748Smckusick 88945748Smckusick pmap = vm_map_pmap(map); 89045748Smckusick 89145748Smckusick /* 89245748Smckusick * Inform the physical mapping system that the 89345748Smckusick * range of addresses may not fault, so that 89445748Smckusick * page tables and such can be locked down as well. 89545748Smckusick */ 89645748Smckusick 89745748Smckusick pmap_pageable(pmap, start, end, FALSE); 89845748Smckusick 89945748Smckusick /* 90045748Smckusick * We simulate a fault to get the page and enter it 90145748Smckusick * in the physical map. 90245748Smckusick */ 90345748Smckusick 90445748Smckusick for (va = start; va < end; va += PAGE_SIZE) { 90545748Smckusick (void) vm_fault(map, va, VM_PROT_NONE, TRUE); 90645748Smckusick } 90745748Smckusick } 90845748Smckusick 90945748Smckusick 91045748Smckusick /* 91145748Smckusick * vm_fault_unwire: 91245748Smckusick * 91345748Smckusick * Unwire a range of virtual addresses in a map. 91445748Smckusick */ 91545748Smckusick void vm_fault_unwire(map, start, end) 91645748Smckusick vm_map_t map; 91745748Smckusick vm_offset_t start, end; 91845748Smckusick { 91945748Smckusick 92045748Smckusick register vm_offset_t va, pa; 92145748Smckusick register pmap_t pmap; 92245748Smckusick 92345748Smckusick pmap = vm_map_pmap(map); 92445748Smckusick 92545748Smckusick /* 92645748Smckusick * Since the pages are wired down, we must be able to 92745748Smckusick * get their mappings from the physical map system. 92845748Smckusick */ 92945748Smckusick 93045748Smckusick vm_page_lock_queues(); 93145748Smckusick 93245748Smckusick for (va = start; va < end; va += PAGE_SIZE) { 93345748Smckusick pa = pmap_extract(pmap, va); 93445748Smckusick if (pa == (vm_offset_t) 0) { 93545748Smckusick panic("unwire: page not in pmap"); 93645748Smckusick } 93745748Smckusick pmap_change_wiring(pmap, va, FALSE); 93845748Smckusick vm_page_unwire(PHYS_TO_VM_PAGE(pa)); 93945748Smckusick } 94045748Smckusick vm_page_unlock_queues(); 94145748Smckusick 94245748Smckusick /* 94345748Smckusick * Inform the physical mapping system that the range 94445748Smckusick * of addresses may fault, so that page tables and 94545748Smckusick * such may be unwired themselves. 94645748Smckusick */ 94745748Smckusick 94845748Smckusick pmap_pageable(pmap, start, end, TRUE); 94945748Smckusick 95045748Smckusick } 95145748Smckusick 95245748Smckusick /* 95345748Smckusick * Routine: 95445748Smckusick * vm_fault_copy_entry 95545748Smckusick * Function: 95645748Smckusick * Copy all of the pages from a wired-down map entry to another. 95745748Smckusick * 95845748Smckusick * In/out conditions: 95945748Smckusick * The source and destination maps must be locked for write. 96045748Smckusick * The source map entry must be wired down (or be a sharing map 96145748Smckusick * entry corresponding to a main map entry that is wired down). 96245748Smckusick */ 96345748Smckusick 96445748Smckusick void vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry) 96545748Smckusick vm_map_t dst_map; 96645748Smckusick vm_map_t src_map; 96745748Smckusick vm_map_entry_t dst_entry; 96845748Smckusick vm_map_entry_t src_entry; 96945748Smckusick { 97045748Smckusick 97145748Smckusick vm_object_t dst_object; 97245748Smckusick vm_object_t src_object; 97345748Smckusick vm_offset_t dst_offset; 97445748Smckusick vm_offset_t src_offset; 97545748Smckusick vm_prot_t prot; 97645748Smckusick vm_offset_t vaddr; 97745748Smckusick vm_page_t dst_m; 97845748Smckusick vm_page_t src_m; 97945748Smckusick 98045748Smckusick #ifdef lint 98145748Smckusick src_map++; 98245748Smckusick #endif lint 98345748Smckusick 98445748Smckusick src_object = src_entry->object.vm_object; 98545748Smckusick src_offset = src_entry->offset; 98645748Smckusick 98745748Smckusick /* 98845748Smckusick * Create the top-level object for the destination entry. 98945748Smckusick * (Doesn't actually shadow anything - we copy the pages 99045748Smckusick * directly.) 99145748Smckusick */ 99245748Smckusick dst_object = vm_object_allocate( 99345748Smckusick (vm_size_t) (dst_entry->end - dst_entry->start)); 99445748Smckusick 99545748Smckusick dst_entry->object.vm_object = dst_object; 99645748Smckusick dst_entry->offset = 0; 99745748Smckusick 99845748Smckusick prot = dst_entry->max_protection; 99945748Smckusick 100045748Smckusick /* 100145748Smckusick * Loop through all of the pages in the entry's range, copying 100245748Smckusick * each one from the source object (it should be there) to the 100345748Smckusick * destination object. 100445748Smckusick */ 100545748Smckusick for (vaddr = dst_entry->start, dst_offset = 0; 100645748Smckusick vaddr < dst_entry->end; 100745748Smckusick vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) { 100845748Smckusick 100945748Smckusick /* 101045748Smckusick * Allocate a page in the destination object 101145748Smckusick */ 101245748Smckusick vm_object_lock(dst_object); 101345748Smckusick do { 101445748Smckusick dst_m = vm_page_alloc(dst_object, dst_offset); 101545748Smckusick if (dst_m == VM_PAGE_NULL) { 101645748Smckusick vm_object_unlock(dst_object); 101745748Smckusick VM_WAIT; 101845748Smckusick vm_object_lock(dst_object); 101945748Smckusick } 102045748Smckusick } while (dst_m == VM_PAGE_NULL); 102145748Smckusick 102245748Smckusick /* 102345748Smckusick * Find the page in the source object, and copy it in. 102445748Smckusick * (Because the source is wired down, the page will be 102545748Smckusick * in memory.) 102645748Smckusick */ 102745748Smckusick vm_object_lock(src_object); 102845748Smckusick src_m = vm_page_lookup(src_object, dst_offset + src_offset); 102945748Smckusick if (src_m == VM_PAGE_NULL) 103045748Smckusick panic("vm_fault_copy_wired: page missing"); 103145748Smckusick 103245748Smckusick vm_page_copy(src_m, dst_m); 103345748Smckusick 103445748Smckusick /* 103545748Smckusick * Enter it in the pmap... 103645748Smckusick */ 103745748Smckusick vm_object_unlock(src_object); 103845748Smckusick vm_object_unlock(dst_object); 103945748Smckusick 104045748Smckusick pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m), 104145748Smckusick prot, FALSE); 104245748Smckusick 104345748Smckusick /* 104445748Smckusick * Mark it no longer busy, and put it on the active list. 104545748Smckusick */ 104645748Smckusick vm_object_lock(dst_object); 104745748Smckusick vm_page_lock_queues(); 104845748Smckusick vm_page_activate(dst_m); 104945748Smckusick vm_page_unlock_queues(); 105045748Smckusick PAGE_WAKEUP(dst_m); 105145748Smckusick vm_object_unlock(dst_object); 105245748Smckusick } 105345748Smckusick 105445748Smckusick } 1055