diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index b2e00a2ff2..49a4b4c16b 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -529,7 +529,7 @@ map_backing_store(vm_address_space *addressSpace, vm_store *store, void **_virtu // create an anonymous store object newStore = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0, - USER_STACK_GUARD_PAGES); + 0, USER_STACK_GUARD_PAGES); if (newStore == NULL) { status = B_NO_MEMORY; goto err1; @@ -784,8 +784,9 @@ vm_create_anonymous_area(team_id aid, const char *name, void **address, } // create an anonymous store object - store = vm_store_create_anonymous_noswap(canOvercommit, isStack ? - ((protection & B_USER_PROTECTION) != 0 ? + // if it's a stack, make sure that two pages are available at least + store = vm_store_create_anonymous_noswap(canOvercommit, isStack ? 2 : 0, + isStack ? ((protection & B_USER_PROTECTION) != 0 ? USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0); if (store == NULL) { status = B_NO_MEMORY; @@ -1461,7 +1462,7 @@ vm_copy_on_write_area(vm_area *area) lowerCache = upperCacheRef->cache; // create an anonymous store object - store = vm_store_create_anonymous_noswap(false, 0); + store = vm_store_create_anonymous_noswap(false, 0, 0); if (store == NULL) return B_NO_MEMORY; @@ -2456,8 +2457,8 @@ vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user, err = vm_soft_fault(address, is_write, is_user); if (err < 0) { - dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n", - err, address, fault_address, is_write, is_user, thread_get_current_thread_id()); + dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n", + strerror(err), address, fault_address, is_write, is_user, thread_get_current_thread_id()); if (!is_user) { struct thread *t = thread_get_current_thread(); if (t && t->fault_handler != 0) { @@ -2542,8 +2543,8 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) vm_page dummyPage; vm_page *page = NULL; addr_t address; - int change_count; - int err; + int32 changeCount; + status_t status; FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n", thread_get_current_thread_id(), originalAddress, isWrite, isUser)); @@ -2604,7 +2605,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) topCacheRef = area->cache_ref; cacheOffset = address - area->base + area->cache_offset; vm_cache_acquire_ref(topCacheRef); - change_count = addressSpace->change_count; + changeCount = addressSpace->change_count; release_sem_etc(addressSpace->sem, READ_COUNT, 0); // See if this cache has a fault handler - this will do all the work for us @@ -2687,8 +2688,10 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) addressSpace->translation_map.ops->get_physical_page(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&vec.iov_base, PHYSICAL_PAGE_CAN_WAIT); // ToDo: handle errors here - err = cacheRef->cache->store->ops->read(cacheRef->cache->store, + status = cacheRef->cache->store->ops->read(cacheRef->cache->store, cacheOffset, &vec, 1, &bytesRead, false); + if (status < B_OK) + panic("hello, dudes!"); addressSpace->translation_map.ops->put_physical_page((addr_t)vec.iov_base); mutex_lock(&cacheRef->lock); @@ -2783,8 +2786,8 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) // try to get a mapping for the src and dest page so we can copy it for (;;) { (*addressSpace->translation_map.ops->get_physical_page)(src_page->physical_page_number * B_PAGE_SIZE, (addr_t *)&src, PHYSICAL_PAGE_CAN_WAIT); - err = (*addressSpace->translation_map.ops->get_physical_page)(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT); - if (err == B_NO_ERROR) + status = (*addressSpace->translation_map.ops->get_physical_page)(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT); + if (status == B_NO_ERROR) break; // it couldn't map the second one, so sleep and retry @@ -2822,20 +2825,20 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) } } - err = B_OK; + status = B_OK; acquire_sem_etc(addressSpace->sem, READ_COUNT, 0, 0); - if (change_count != addressSpace->change_count) { + if (changeCount != addressSpace->change_count) { // something may have changed, see if the address is still valid area = vm_area_lookup(addressSpace, address); if (area == NULL || area->cache_ref != topCacheRef || (address - area->base + area->cache_offset) != cacheOffset) { dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n"); - err = B_BAD_ADDRESS; + status = B_BAD_ADDRESS; } } - if (err == B_OK) { + if (status == B_OK) { // All went fine, all there is left to do is to map the page into the address space // If the page doesn't reside in the area's cache, we need to make sure it's @@ -2868,7 +2871,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) vm_cache_release_ref(topCacheRef); vm_put_address_space(addressSpace); - return err; + return status; } diff --git a/src/system/kernel/vm/vm_store_anonymous_noswap.c b/src/system/kernel/vm/vm_store_anonymous_noswap.c index 66cd029e6b..3a7213ed6f 100644 --- a/src/system/kernel/vm/vm_store_anonymous_noswap.c +++ b/src/system/kernel/vm/vm_store_anonymous_noswap.c @@ -31,6 +31,8 @@ typedef struct anonymous_store { vm_store vm; bool can_overcommit; + bool has_precommitted; + uint8 precommitted_pages; int32 guarded_size; } anonymous_store; @@ -49,8 +51,15 @@ anonymous_commit(struct vm_store *_store, off_t size) anonymous_store *store = (anonymous_store *)_store; // if we can overcommit, we don't commit here, but in anonymous_fault() - if (store->can_overcommit) - return B_OK; + if (store->can_overcommit) { + if (store->has_precommitted) + return B_OK; + + // pre-commit some pages to make a later failure less probable + store->has_precommitted = true; + if (size > store->vm.cache->virtual_base + store->precommitted_pages) + size = store->vm.cache->virtual_base + store->precommitted_pages; + } size -= store->vm.cache->virtual_base; // anonymous stores don't need to span over their whole source @@ -61,7 +70,7 @@ anonymous_commit(struct vm_store *_store, off_t size) // try to commit if (vm_try_reserve_memory(size - store->vm.committed_size) != B_OK) return B_NO_MEMORY; - + store->vm.committed_size = size; } else { // we can release some @@ -121,9 +130,12 @@ anonymous_fault(struct vm_store *_store, struct vm_address_space *aspace, off_t } } - // try to commit additional memory - if (vm_try_reserve_memory(B_PAGE_SIZE) != B_OK) - return B_NO_MEMORY; + if (store->precommitted_pages == 0) { + // try to commit additional memory + if (vm_try_reserve_memory(B_PAGE_SIZE) != B_OK) + return B_NO_MEMORY; + } else + store->precommitted_pages--; store->vm.committed_size += B_PAGE_SIZE; } @@ -150,7 +162,7 @@ static vm_store_ops anonymous_ops = { */ vm_store * -vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages) +vm_store_create_anonymous_noswap(bool canOvercommit, int32 numPrecommittedPages, int32 numGuardPages) { anonymous_store *store = malloc(sizeof(anonymous_store)); if (store == NULL) @@ -163,6 +175,8 @@ vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages) store->vm.cache = NULL; store->vm.committed_size = 0; store->can_overcommit = canOvercommit; + store->has_precommitted = numPrecommittedPages != 0; + store->precommitted_pages = min(numPrecommittedPages, 255); store->guarded_size = numGuardPages * B_PAGE_SIZE; return &store->vm; diff --git a/src/system/kernel/vm/vm_store_anonymous_noswap.h b/src/system/kernel/vm/vm_store_anonymous_noswap.h index 58f30a4e35..f8bde0e20e 100644 --- a/src/system/kernel/vm/vm_store_anonymous_noswap.h +++ b/src/system/kernel/vm/vm_store_anonymous_noswap.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -13,8 +13,14 @@ #ifdef __cplusplus -extern "C" +extern "C" { +#endif + +vm_store *vm_store_create_anonymous_noswap(bool canOvercommit, + int32 numPrecommittedPages, int32 numGuardPages); + +#ifdef __cplusplus +} #endif -vm_store *vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages); #endif /* _KERNEL_VM_STORE_ANONYMOUS_H */