diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h index 7fcaab3372..08451dd027 100644 --- a/headers/private/kernel/vm.h +++ b/headers/private/kernel/vm.h @@ -23,6 +23,11 @@ struct vm_address_space; struct vnode; +// area creation flags +#define CREATE_AREA_DONT_WAIT 0x01 +#define CREATE_AREA_UNMAP_ADDRESS_RANGE 0x02 + + #ifdef __cplusplus extern "C" { #endif @@ -48,14 +53,15 @@ void forbid_page_faults(void); // private kernel only extension (should be moved somewhere else): area_id create_area_etc(team_id team, const char *name, void **address, - uint32 addressSpec, uint32 size, uint32 lock, uint32 protection); + uint32 addressSpec, uint32 size, uint32 lock, uint32 protection, + uint32 flags); status_t vm_unreserve_address_range(team_id team, void *address, addr_t size); status_t vm_reserve_address_range(team_id team, void **_address, uint32 addressSpec, addr_t size, uint32 flags); area_id vm_create_anonymous_area(team_id team, const char *name, void **address, uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection, - bool unmapAddressRange, bool kernel); + uint32 flags, bool kernel); area_id vm_map_physical_memory(team_id team, const char *name, void **address, uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr); area_id vm_map_file(team_id aid, const char *name, void **address, diff --git a/src/system/kernel/arch/x86/vm86.cpp b/src/system/kernel/arch/x86/vm86.cpp index 4af80813db..778472e15e 100644 --- a/src/system/kernel/arch/x86/vm86.cpp +++ b/src/system/kernel/arch/x86/vm86.cpp @@ -548,7 +548,7 @@ vm86_prepare(struct vm86_state *state, unsigned int ramSize) void *address = (void *)0; state->ram_area = create_area_etc(team->id, "dos", &address, - B_EXACT_ADDRESS, ramSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + B_EXACT_ADDRESS, ramSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA, 0); if (state->ram_area < B_OK) { ret = state->ram_area; TRACE("Could not create RAM area\n"); diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index b4a46e25ef..4f5e9626e0 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -1470,7 +1470,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, regionAddress += fileUpperBound; id = create_area_etc(team->id, regionName, (void **)®ionAddress, B_EXACT_ADDRESS, bssSize, - B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + B_NO_LOCK, B_READ_AREA | B_WRITE_AREA, 0); if (id < B_OK) { dprintf("error allocating bss area: %s!\n", strerror(id)); status = B_NOT_AN_EXECUTABLE; diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 729f8cf988..f30b079ba0 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -816,7 +816,7 @@ create_team_user_data(struct team* team) void* address = (void*)KERNEL_USER_DATA_BASE; size_t size = 4 * B_PAGE_SIZE; team->user_data_area = create_area_etc(team->id, "user area", &address, - B_BASE_ADDRESS, size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); + B_BASE_ADDRESS, size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA, 0); if (team->user_data_area < 0) return team->user_data_area; @@ -996,7 +996,7 @@ team_create_thread_start(void *args) sprintf(ustack_name, "%s_main_stack", team->name); t->user_stack_area = create_area_etc(team->id, ustack_name, (void **)&t->user_stack_base, B_EXACT_ADDRESS, sizeLeft, B_NO_LOCK, - B_READ_AREA | B_WRITE_AREA | B_STACK_AREA); + B_READ_AREA | B_WRITE_AREA | B_STACK_AREA, 0); if (t->user_stack_area < 0) { dprintf("team_create_thread_start: could not create default user stack region\n"); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 0bd9834f76..0647ca6c09 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -508,7 +508,7 @@ create_thread(thread_creation_attributes& attributes, bool kernel) thread->user_stack_area = create_area_etc(team->id, stack_name, (void **)&thread->user_stack_base, B_BASE_ADDRESS, thread->user_stack_size + TLS_SIZE, B_NO_LOCK, - B_READ_AREA | B_WRITE_AREA | B_STACK_AREA); + B_READ_AREA | B_WRITE_AREA | B_STACK_AREA, 0); if (thread->user_stack_area < B_OK || arch_thread_init_tls(thread) < B_OK) { // great, we have a fully running thread without a (usable) diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 5e78c7a735..209077e3c8 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1628,7 +1628,7 @@ vm_reserve_address_range(team_id team, void **_address, uint32 addressSpec, area_id vm_create_anonymous_area(team_id team, const char *name, void **address, uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection, - bool unmapAddressRange, bool kernel) + uint32 flags, bool kernel) { vm_area *area; vm_cache *cache; @@ -1712,7 +1712,8 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, // won't be able to free anything for us. addr_t reservedMemory = 0; if (doReserveMemory) { - if (vm_try_reserve_memory(size, 1000000) != B_OK) + bigtime_t timeout = (flags & CREATE_AREA_DONT_WAIT) != 0 ? 0 : 1000000; + if (vm_try_reserve_memory(size, timeout) != B_OK) return B_NO_MEMORY; reservedMemory = size; // TODO: We don't reserve the memory for the pages for the page @@ -1722,18 +1723,28 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, // can get the VM into trouble in low memory situations. } + AddressSpaceWriteLocker locker; + vm_address_space *addressSpace; + status_t status; + // For full lock areas reserve the pages before locking the address // space. E.g. block caches can't release their memory while we hold the // address space lock. page_num_t reservedPages = reservedMapPages; if (wiring == B_FULL_LOCK) reservedPages += size / B_PAGE_SIZE; - if (reservedPages > 0) - vm_page_reserve_pages(reservedPages); + if (reservedPages > 0) { + if ((flags & CREATE_AREA_DONT_WAIT) != 0) { + if (!vm_page_try_reserve_pages(reservedPages)) { + reservedPages = 0; + status = B_WOULD_BLOCK; + goto err0; + } + } else + vm_page_reserve_pages(reservedPages); + } - AddressSpaceWriteLocker locker; - vm_address_space *addressSpace; - status_t status = locker.SetTo(team); + status = locker.SetTo(team); if (status != B_OK) goto err0; @@ -1782,7 +1793,7 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, status = map_backing_store(addressSpace, cache, address, 0, size, addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name, - unmapAddressRange, kernel); + (flags & CREATE_AREA_UNMAP_ADDRESS_RANGE) != 0, kernel); if (status < B_OK) { cache->ReleaseRefAndUnlock(); @@ -2099,8 +2110,10 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec protection |= B_SHARED_AREA; if (fd < 0) { + uint32 flags = addressSpec == B_EXACT_ADDRESS + ? CREATE_AREA_UNMAP_ADDRESS_RANGE : 0; return vm_create_anonymous_area(team, name, _address, addressSpec, size, - B_NO_LOCK, protection, addressSpec == B_EXACT_ADDRESS, kernel); + B_NO_LOCK, protection, flags, kernel); } // get the open flags of the FD @@ -5564,12 +5577,13 @@ clone_area(const char *name, void **_address, uint32 addressSpec, area_id create_area_etc(team_id team, const char *name, void **address, - uint32 addressSpec, uint32 size, uint32 lock, uint32 protection) + uint32 addressSpec, uint32 size, uint32 lock, uint32 protection, + uint32 flags) { fix_protection(&protection); return vm_create_anonymous_area(team, (char *)name, address, addressSpec, - size, lock, protection, false, true); + size, lock, protection, flags, true); } @@ -5580,7 +5594,7 @@ create_area(const char *name, void **_address, uint32 addressSpec, size_t size, fix_protection(&protection); return vm_create_anonymous_area(vm_kernel_address_space_id(), (char *)name, _address, - addressSpec, size, lock, protection, false, true); + addressSpec, size, lock, protection, 0, true); } @@ -5806,8 +5820,7 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec, fix_protection(&protection); area_id area = vm_create_anonymous_area(vm_current_user_address_space_id(), - (char *)name, &address, addressSpec, size, lock, protection, false, - false); + (char *)name, &address, addressSpec, size, lock, protection, 0, false); if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { delete_area(area);