From c6a7ff7a9fd2ed08390fe64b8e37a7e67a0fb24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 23 Mar 2007 11:48:37 +0000 Subject: [PATCH] * The new vm_page_mappings weren't updated correctly in many cases. * Added a comment to vm_remove_all_page_mappings() that shows that we need to change the mapping spinlock into a mutex. * Pointed out some potential problems in the code. * Added vm_page_at_index(), vm_clear_map_activation(), and vm_test_map_activation() in preparation of the page scanner rewrite. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20407 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/vm.h | 2 + headers/private/kernel/vm_page.h | 3 +- src/system/kernel/vm/vm.cpp | 97 +++++++++++++++++++++++++++----- src/system/kernel/vm/vm_page.c | 17 ++++-- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h index 71f0a45cc1..04bdcb6c2e 100644 --- a/headers/private/kernel/vm.h +++ b/headers/private/kernel/vm.h @@ -62,6 +62,8 @@ status_t vm_create_vnode_cache(void *vnode, vm_cache_ref **_cacheRef); vm_area *vm_area_lookup(vm_address_space *addressSpace, addr_t address); status_t vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type); status_t vm_get_page_mapping(team_id team, addr_t vaddr, addr_t *paddr); +int32 vm_test_map_activation(vm_page *page); +void vm_clear_map_activation(vm_page *page); void vm_remove_all_page_mappings(vm_page *page); status_t vm_unmap_pages(vm_area *area, addr_t base, size_t length); status_t vm_map_page(vm_area *area, vm_page *page, addr_t address, diff --git a/headers/private/kernel/vm_page.h b/headers/private/kernel/vm_page.h index 92da31751a..274c0051eb 100644 --- a/headers/private/kernel/vm_page.h +++ b/headers/private/kernel/vm_page.h @@ -38,7 +38,8 @@ vm_page *vm_page_allocate_page(int state); status_t vm_page_allocate_pages(int pageState, vm_page **pages, uint32 numPages); vm_page *vm_page_allocate_page_run(int state, addr_t length); vm_page *vm_page_allocate_specific_page(addr_t page_num, int state); -vm_page *vm_lookup_page(addr_t page_num); +vm_page *vm_page_at_index(int32 index); +vm_page *vm_lookup_page(addr_t pageNumber); #ifdef __cplusplus } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 5e058ca52d..492fe95d7f 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1616,6 +1616,9 @@ vm_copy_on_write_area(vm_area *area) map->ops->unmap(map, area->base, area->base - 1 + area->size); map->ops->flush(map); + // TODO: does anything guarantee that we remap the same pages here? + // Shouldn't we better introduce a "change mapping"? + for (page = lowerCache->page_list; page; page = page->cache_next) { map->ops->map(map, area->base + (page->cache_offset << PAGE_SHIFT) - area->cache_offset, page->physical_page_number << PAGE_SHIFT, @@ -1836,9 +1839,67 @@ vm_get_page_mapping(team_id aid, addr_t vaddr, addr_t *paddr) } +int32 +vm_test_map_activation(vm_page *page) +{ + int32 activation = 0; + + // TODO: this can't work... (we need to lock the map, so this has to be a mutex) + cpu_status state = disable_interrupts(); + acquire_spinlock(&sMappingLock); + + vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); + vm_page_mapping *mapping; + while ((mapping = iterator.Next()) != NULL) { + vm_area *area = mapping->area; + vm_translation_map *map = &area->address_space->translation_map; + + addr_t physicalAddress; + uint32 flags; +// map->ops->lock(map); + addr_t address = area->base + (page->cache_offset << PAGE_SHIFT); + map->ops->query_interrupt(map, address, &physicalAddress, &flags); +// map->ops->unlock(map); + + if (flags & PAGE_ACCESSED) + activation++; + } + + release_spinlock(&sMappingLock); + restore_interrupts(state); + + return activation; +} + + +void +vm_clear_map_activation(vm_page *page) +{ + // TODO: this can't work... (we need to lock the map, so this has to be a mutex) + cpu_status state = disable_interrupts(); + acquire_spinlock(&sMappingLock); + + vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); + vm_page_mapping *mapping; + while ((mapping = iterator.Next()) != NULL) { + vm_area *area = mapping->area; + vm_translation_map *map = &area->address_space->translation_map; + +// map->ops->lock(map); + addr_t address = area->base + (page->cache_offset << PAGE_SHIFT); + map->ops->clear_flags(map, address, PAGE_ACCESSED); +// map->ops->unlock(map); + } + + release_spinlock(&sMappingLock); + restore_interrupts(state); +} + + void vm_remove_all_page_mappings(vm_page *page) { + // TODO: this can't work... (we need to lock the map, so this has to be a mutex) cpu_status state = disable_interrupts(); acquire_spinlock(&sMappingLock); @@ -1851,10 +1912,10 @@ vm_remove_all_page_mappings(vm_page *page) vm_area *area = mapping->area; vm_translation_map *map = &area->address_space->translation_map; - map->ops->lock(map); +// map->ops->lock(map); addr_t base = area->base + (page->cache_offset << PAGE_SHIFT); map->ops->unmap(map, base, base + (B_PAGE_SIZE - 1)); - map->ops->unlock(map); +// map->ops->unlock(map); area->mappings.Remove(mapping); } @@ -2485,6 +2546,9 @@ vm_area_for(team_id team, addr_t address) } +/*! + Frees physical pages that were used during the boot process. +*/ static void unmap_and_free_physical_pages(vm_translation_map *map, addr_t start, addr_t end) { @@ -3470,6 +3534,13 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) if (status == B_OK) { // All went fine, all there is left to do is to map the page into the address space + // In case this is a copy-on-write page, we need to unmap it from the area now + if (isWrite && page->cache == topCacheRef->cache) + vm_unmap_pages(area, address - area->base, B_PAGE_SIZE); + + // TODO: there is currently no mechanism to prevent a page being mapped + // more than once in case of a second page fault! + // If the page doesn't reside in the area's cache, we need to make sure it's // mapped in read-only, so that we cannot overwrite someone else's data (copy-on-write) uint32 newProtection = area->protection; @@ -4127,13 +4198,8 @@ resize_area(area_id areaID, size_t newSize) current->size = newSize; // we also need to unmap all pages beyond the new size, if the area has shrinked - if (newSize < oldSize) { - vm_translation_map *map = ¤t->address_space->translation_map; - - map->ops->lock(map); - map->ops->unmap(map, current->base + newSize, current->base + oldSize - 1); - map->ops->unlock(map); - } + if (newSize < oldSize) + vm_unmap_pages(current, current->base + newSize, oldSize - newSize); } if (status == B_OK) @@ -4193,6 +4259,11 @@ transfer_area(area_id id, void **_address, uint32 addressSpec, team_id target) acquire_sem_etc(sourceAddressSpace->sem, WRITE_COUNT, 0, 0); + // unmap the area in the source address space + vm_unmap_pages(area, area->base, area->size); + + // TODO: there might be additional page faults at this point! + reservedAddress = (void *)area->base; remove_area_from_address_space(sourceAddressSpace, area, true); status = insert_area(sourceAddressSpace, &reservedAddress, B_EXACT_ADDRESS, @@ -4204,12 +4275,6 @@ transfer_area(area_id id, void **_address, uint32 addressSpec, team_id target) if (status != B_OK) goto err3; - // unmap the area in the source address space - map = &sourceAddressSpace->translation_map; - map->ops->lock(map); - map->ops->unmap(map, area->base, area->base + (area->size - 1)); - map->ops->unlock(map); - // insert the area into the target address space acquire_sem_etc(targetAddressSpace->sem, WRITE_COUNT, 0, 0); @@ -4228,6 +4293,8 @@ transfer_area(area_id id, void **_address, uint32 addressSpec, team_id target) // The area was successfully transferred to the new team when we got here area->address_space = targetAddressSpace; + // TODO: take area lock/wiring into account! + release_sem_etc(targetAddressSpace->sem, WRITE_COUNT, 0); vm_unreserve_address_range(sourceAddressSpace->id, reservedAddress, area->size); diff --git a/src/system/kernel/vm/vm_page.c b/src/system/kernel/vm/vm_page.c index 189613c462..4623c37893 100644 --- a/src/system/kernel/vm/vm_page.c +++ b/src/system/kernel/vm/vm_page.c @@ -1030,16 +1030,23 @@ vm_page_allocate_page_run(int page_state, addr_t len) vm_page * -vm_lookup_page(addr_t page_num) +vm_page_at_index(int32 index) { - if (page_num < sPhysicalPageOffset) + return &sPages[index]; +} + + +vm_page * +vm_lookup_page(addr_t pageNumber) +{ + if (pageNumber < sPhysicalPageOffset) return NULL; - page_num -= sPhysicalPageOffset; - if (page_num >= sNumPages) + pageNumber -= sPhysicalPageOffset; + if (pageNumber >= sNumPages) return NULL; - return &sPages[page_num]; + return &sPages[pageNumber]; }